Python - write () so với writelines () và các chuỗi được nối


124

Vì vậy, tôi đang học Python. Tôi đang xem qua các bài học và gặp phải một vấn đề trong đó tôi phải kết tụ rất nhiều target.write()thành một duy nhất write(), trong khi có một "\n"giữa mỗi biến đầu vào của người dùng (đối tượng của write()).

Tôi đến với:

nl = "\n"
lines = line1, nl, line2, nl, line3, nl
textdoc.writelines(lines)

Nếu tôi cố gắng làm:

textdoc.write(lines)

Tôi nhận được một lỗi. Nhưng nếu tôi nhập:

textdoc.write(line1 + "\n" + line2 + ....)

Sau đó, nó hoạt động tốt. Tại sao tôi không thể sử dụng một chuỗi cho một dòng mới trong write()nhưng tôi có thể sử dụng nó trong writelines()?

Python 2.7 Khi tôi tìm kiếm trên google, hầu hết các tài nguyên tôi tìm thấy đều nằm trong đầu tôi, tôi vẫn là một cư dân.


lineskhông phải là một chuỗi trong ví dụ của bạn. Nó là một tuple bao gồm sáu dây.
Bachsau

Câu trả lời:


147
  • writelines mong đợi một chuỗi có thể lặp lại
  • write mong đợi một chuỗi duy nhất.

line1 + "\n" + line2hợp nhất các chuỗi đó với nhau thành một chuỗi trước khi chuyển nó tới write.

Lưu ý rằng nếu bạn có nhiều dòng, bạn có thể muốn sử dụng "\n".join(list_of_lines).


50
Cụ thể hơn, writelinesmong đợi có thể lặp lại. Bạn có thể sử dụng một danh sách, một bộ hoặc một trình tạo.
Mark Ransom

Cảm ơn bạn đã trả lời thưa ông. Tôi giả sử bằng tên (list_of_lines) rằng tôi nên tạo một danh sách các chuỗi và sau đó chuyển vào .join (list)?
AbeLinkon

9
Tại sao bạn nên sử dụng writethay vì writelinesnếu bạn có nhiều dòng? Writelines có thể hoạt động tốt hơn vì nó không phải tạo một chuỗi được nối tạm thời mà chỉ cần lặp qua các dòng.
Bouke

@ hBy2Py: hoàn toàn ngược lại: stackoverflow.com/a/6165711/281545
Mr_and_Mrs_D

1
Một chuỗi đơn cũng là một iterable bằng Python
natbusa

123

Tại sao tôi không thể sử dụng một chuỗi cho một dòng mới trong write () nhưng tôi có thể sử dụng nó trong writelines ()?

Ý tưởng là như sau: nếu bạn muốn viết một chuỗi đơn, bạn có thể làm điều này với write(). Nếu bạn có một chuỗi các chuỗi, bạn có thể viết tất cả chúng bằng cách sử dụngwritelines() .

write(arg)mong đợi một chuỗi làm đối số và ghi nó vào tệp. Nếu bạn cung cấp danh sách các chuỗi, nó sẽ tạo ra một ngoại lệ (nhân tiện, hiển thị lỗi cho chúng tôi!).

writelines(arg)mong đợi một đối số có thể lặp lại (một đối tượng có thể lặp có thể là một bộ, một danh sách, một chuỗi hoặc một trình lặp theo nghĩa chung nhất). Mỗi mục chứa trong trình vòng lặp được mong đợi là một chuỗi. Một bộ dây là những gì bạn đã cung cấp, vì vậy mọi thứ đã hoạt động.

Bản chất của (các) chuỗi không quan trọng đối với cả hai hàm, tức là chúng chỉ ghi vào tệp bất cứ thứ gì bạn cung cấp cho chúng. Phần thú vị là nó writelines()không tự thêm các ký tự dòng mới, vì vậy tên phương thức thực sự có thể khá khó hiểu. Nó thực sự hoạt động giống như một phương thức tưởng tượng được gọi write_all_of_these_strings(sequence).

Sau đây là một cách thành ngữ trong Python để ghi danh sách các chuỗi vào một tệp trong khi giữ mỗi chuỗi ở dòng riêng của nó:

lines = ['line1', 'line2']
with open('filename.txt', 'w') as f:
    f.write('\n'.join(lines))

Thao tác này sẽ giúp bạn đóng tệp. Cấu trúc '\n'.join(lines)nối (kết nối) các chuỗi trong danh sách linesvà sử dụng ký tự '\ n' làm keo dán. Nó hiệu quả hơn việc sử dụng+ toán tử.

Bắt đầu từ cùng một linestrình tự, kết thúc với cùng một đầu ra, nhưng sử dụng writelines():

lines = ['line1', 'line2']
with open('filename.txt', 'w') as f:
    f.writelines("%s\n" % l for l in lines)

Điều này sử dụng một biểu thức trình tạo và tự động tạo các chuỗi kết thúc bằng dòng mới. writelines()lặp lại chuỗi chuỗi này và ghi mọi mục.

Chỉnh sửa: Một điểm khác mà bạn cần lưu ý:

write()readlines()tồn tại trước khi writelines()được giới thiệu. writelines()được giới thiệu sau đó như một bản sao của readlines(), để người ta có thể dễ dàng ghi nội dung tệp vừa được đọc qua readlines():

outfile.writelines(infile.readlines())

Thực sự, đây là lý do chính tại sao writelinescó một cái tên khó hiểu như vậy. Ngoài ra, ngày nay, chúng tôi không thực sự muốn sử dụng phương pháp này nữa. readlines()đọc toàn bộ tệp vào bộ nhớ của máy trước khi writelines()bắt đầu ghi dữ liệu. Trước hết, điều này có thể lãng phí thời gian. Tại sao không bắt đầu viết các phần của dữ liệu trong khi đọc các phần khác? Nhưng, quan trọng nhất, cách tiếp cận này có thể rất tốn bộ nhớ. Trong một trường hợp cực đoan, khi tệp đầu vào lớn hơn bộ nhớ của máy bạn, phương pháp này thậm chí sẽ không hoạt động. Giải pháp cho vấn đề này là chỉ sử dụng các trình vòng lặp. Một ví dụ hoạt động:

with open('inputfile') as infile:
    with open('outputfile') as outfile:
        for line in infile:
            outfile.write(line)

Điều này đọc từng dòng tệp đầu vào. Ngay sau khi một dòng được đọc, dòng này được ghi vào tệp đầu ra. Nói một cách giản lược, luôn chỉ có một dòng duy nhất trong bộ nhớ (so với toàn bộ nội dung tệp nằm trong bộ nhớ trong trường hợp của phương pháp readlines / writelines).


5
@AbeLinkon: Tôi không ủng hộ kết luận này. write()writelines()về cơ bản là tương đương và việc sử dụng chúng cũng là một câu hỏi về sở thích cá nhân. Tuy nhiên, điều quan trọng cần lưu ý là đối với một danh sách cực kỳ dài các chuỗi (được gọi lines) thì việc viết sẽ kém hiệu quả f.write('\n'.join(lines))hơn for l in line: f.write('%s\n' % l). Trong trường hợp đầu tiên, một chuỗi hoàn toàn mới và rất dài được tạo trong bộ nhớ trước khi viết nó. Trong trường hợp thứ hai, dữ liệu được viết theo từng đoạn.
Tiến sĩ Jan-Philip Gehrcke

3
f.write ('\ n'.join (lines)) đã không thêm nl cuối cùng khi tôi chạy nó.
Jiminion,

5
Tất nhiên bạn sẽ không làm outf.writelines(inf.readlines())nhưng đúng hơn outf.writelines(inf). Chức năng chúng tôi không muốn sử dụng nữa thì readlines()không writelines().
moooeeeep

2
@moooeeeep: mặc dù không có gì sai với chức năng / việc triển khai writelines(), nhưng ngữ nghĩa của nó, như đã giải thích, ít lý tưởng hơn. Đây là lý do tại sao tôi chưa bao giờ sử dụng nó. Và tôi chưa bao giờ bỏ lỡ nó.
Tiến sĩ Jan-Philip Gehrcke

2
@AbeLinkon - có lẽ bạn nên cân nhắc để chấp nhận câu trả lời này, nó rõ ràng là tốt hơn câu trả lời mà bạn đã chấp nhận ban đầu
Peter M. - là viết tắt của Monica

-4

nếu bạn chỉ muốn lưu và tải một danh sách, hãy thử Pickle

Tiết kiệm dưa chua:

with open("yourFile","wb")as file:
 pickle.dump(YourList,file)

và tải:

with open("yourFile","rb")as file:
 YourList=pickle.load(file)

-5

Trên thực tế, tôi nghĩ rằng vấn đề là "dòng" biến của bạn là xấu. Bạn đã xác định các dòng là một bộ tuple, nhưng tôi tin rằng write () yêu cầu một chuỗi. Tất cả những gì bạn phải thay đổi là dấu phẩy thành dấu cộng (+).

nl = "\n"
lines = line1+nl+line2+nl+line3+nl
textdoc.writelines(lines)

nên làm việc.


-5

Bài tập 16 từ cuốn sách của Zed Shaw? Bạn có thể sử dụng các ký tự thoát như sau:

paragraph1 = "%s \n %s \n %s \n" % (line1, line2, line3)
target.write(paragraph1)
target.close()

Giải pháp rất yếu. Nếu bạn muốn nối nhiều dòng theo cách này, bạn nên làm điều đó như thế này: " \n ".join((line1, line2, line3)).
Bachsau
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.