mở đọc và đóng tệp trong 1 dòng mã


127

Bây giờ tôi sử dụng:

pageHeadSectionFile = open('pagehead.section.htm','r')
output = pageHeadSectionFile.read()
pageHeadSectionFile.close()

Nhưng để làm cho mã trông đẹp hơn, tôi có thể làm:

output = open('pagehead.section.htm','r').read()

Khi sử dụng cú pháp trên, làm cách nào để đóng tệp để giải phóng tài nguyên hệ thống?


19
Không có gì hấp dẫn hơn về một lớp lót. Mã được đọc thường xuyên hơn nhiều so với nó được viết, và nên được viết để hiểu, không phải cho "mát mẻ". Ngoại lệ duy nhất là khi có một thành ngữ nổi tiếng trong một ngôn ngữ, nhưng tôi không biết về một trong trường hợp này.
drdwilcox

17
@drdwilcox: Một lớp lót mật mã là xấu, một lớp lót khai báo là tốt. Không có lý do (ít nhất là tôi không thể nhìn thấy một), tại sao không có trình bao bọc hàm trong lõi để đọc một tệp (nhu cầu chung như vậy) trong một lệnh gọi hàm duy nhất. Một cái gì đó như contents = os.readfile(path). Nếu tôi muốn làm một cái gì đó lạ hơn, thì ok, tôi vui vẻ sử dụng with open(path) as fd: contents = fd.read(). Tất nhiên người ta có thể viết trình bao bọc của riêng mình, nhưng đó là cốt lõi để làm gì, để cung cấp sự hữu ích cho sự trừu tượng cho các lập trình viên.
tokland

5
Đúng là mã được đọc nhiều hơn nhiều so với mã được viết, nhưng hàm ý rằng mã dài hơn cũng tốt như mã ngắn không thể sai hơn. Nếu bạn đầu tư thời gian để làm cho mã của mình càng ngắn càng tốt (mà không cần dùng đến các thủ thuật thông minh khó hiểu), khoản đầu tư đó sẽ trả hết lần này đến lần khác khi đọc mã. Mỗi dòng bạn viết là một dịch vụ cho bất cứ ai đọc mã của bạn, vì vậy bạn nên cố gắng viết càng ít càng tốt. Hãy nhớ câu nói nổi tiếng từ Pascal: "Tôi đã viết bức thư này lâu hơn chỉ vì tôi không có thời gian rảnh để làm cho nó ngắn hơn."
John Williams

Câu trả lời:


194

Bạn không thực sự phải đóng nó - Python sẽ tự động thực hiện trong quá trình thu gom rác hoặc khi thoát khỏi chương trình. Nhưng như @delnan lưu ý, tốt hơn hết là nên đóng nó vì nhiều lý do.

Vì vậy, những gì bạn có thể làm để giữ cho nó ngắn gọn, đơn giản và rõ ràng:

with open('pagehead.section.htm','r') as f:
    output = f.read()

Bây giờ nó chỉ là hai dòng và khá dễ đọc, tôi nghĩ vậy.


2
@ 1qazxsw2 Nếu bạn sử dụng withcâu lệnh , tài nguyên tệp sẽ được đóng đúng cho bạn.
David Alber

13
Câu đầu tiên: Python sẽ đóng nó cuối cùng . Nhưng điều đó không có nghĩa là bạn nên quên đi việc đóng cửa. Ngay cả khi đếm tiền, tệp có thể vẫn mở lâu hơn bạn nghĩ và muốn (ví dụ: nếu nó xảy ra được gọi theo chu kỳ). Điều này sẽ giúp ba lần triển khai Python có một GC tốt, trong đó bạn không có gì đảm bảo rằng mọi thứ đều là GC tại bất kỳ thời điểm cụ thể nào. Ngay cả tài liệu CPython cũng nói rằng bạn không nên dựa vào GC để dọn dẹp như thế này. Phần sau của câu trả lời nên được in đậm.

6
Nếu bạn thực sự cần một lớp lót , có thể đặt output = f.read()phần trên cùng một dòng sau :.
Karl Knechtel

1
"mở đọc và đóng tệp trong 1 dòng mã" đây là hai dòng và không trả lời câu hỏi.
dùng5359531

1
Đó là phụ thuộc thực hiện - xem câu trả lời của Sven.
Tim Pietzcker

71

Mô-đun Pathlib của Thư viện Tiêu chuẩn Python thực hiện những gì bạn đang tìm kiếm:

Path('pagehead.section.htm').read_text()

Đừng quên nhập Đường dẫn:

jsk@dev1:~$ python3
Python 3.5.2 (default, Sep 10 2016, 08:21:44)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from pathlib import Path
>>> (Path("/etc") / "hostname").read_text()
'dev1.example\n'

Trên Python 27 cài đặt backported pathlibhoặcpathlib2


8
Các câu trả lời khác đề xuất withlà tốt, nhưng withlà một tuyên bố, không phải là một biểu thức. Đây pathlibcâu trả lời là chỉ trả lời cho câu hỏi ban đầu có thể được nhúng trong một biểu thức Python. Một cái gì đó nhưSECRET_KEY = os.environ.get('SECRET_KEY') or pathlib.Path('SECRET_KEY').read_bytes()
LeoRochael

24

Sử dụng CPython, tệp của bạn sẽ bị đóng ngay lập tức sau khi dòng được thực thi, vì đối tượng tệp ngay lập tức được thu gom rác. Có hai nhược điểm:

  1. Trong các triển khai Python khác với CPython, tệp thường không được đóng ngay lập tức mà sau đó, vượt quá tầm kiểm soát của bạn.

  2. Trong Python 3.2 trở lên, điều này sẽ ném ResourceWarning, nếu được bật.

Tốt hơn để đầu tư thêm một dòng:

with open('pagehead.section.htm','r') as f:
    output = f.read()

Điều này sẽ đảm bảo rằng tệp được đóng chính xác trong mọi trường hợp.


17

Không cần phải nhập bất kỳ thư viện đặc biệt để làm điều này.

Sử dụng cú pháp bình thường và nó sẽ mở tệp để đọc sau đó đóng nó.

with open("/etc/hostname","r") as f: print f.read() 

hoặc là

with open("/etc/hosts","r") as f: x = f.read().splitlines()

cung cấp cho bạn một mảng x chứa các dòng và có thể được in như vậy:

for line in x: print line

Những lớp lót này rất hữu ích cho việc bảo trì - về cơ bản là tự ghi chép.


8

Những gì bạn có thể làm là sử dụng withcâu lệnh và viết hai bước trên một dòng:

>>> with open('pagehead.section.htm', 'r') as fin: output = fin.read();
>>> print(output)
some content

Câu withlệnh sẽ chú ý gọi __exit__hàm của đối tượng đã cho ngay cả khi có điều gì đó xấu xảy ra trong mã của bạn; Nó gần với try... finallycú pháp. Đối với đối tượng được trả về bởi open, __exit__tương ứng với việc đóng tệp.

Tuyên bố này đã được giới thiệu với Python 2.6.


Làm rõ nhỏ: theo tài liệu with được giới thiệu trong Python 2.5, nhưng phải được nhập rõ ràng từ __future__. Nó trở nên có sẵn từ tất cả các bối cảnh trong Python 2.6.
David Alber

5

sử dụng ilio : (nội tuyến io):

chỉ cần một lệnh gọi thay vì tệp open (), read (), close ().

from ilio import read

content = read('filename')

2
with open('pagehead.section.htm')as f:contents=f.read()

4
Làm thế nào là khác nhau từ 3 câu trả lời hàng đầu?
Tất cả công nhân đều cần thiết

4
Sự khác biệt lớn nhất là nó chỉ là một dòng như câu hỏi được chỉ định. Cá nhân tôi không thể tìm thấy bất kỳ điều gì ngoài điều đó nhưng cảm thấy tự do phê bình công việc của tôi hơn là thực sự đóng góp cho câu hỏi.

3
Cách ngắn nhất, tích hợp sẵn để đạt được việc mở, đọc và đóng tệp trong Python là sử dụng 2 dòng logic cho dù nó có tụ xuống 1 dòng hay không. Vì vậy, tôi không thấy câu trả lời này có hiệu quả khác với 3 câu trả lời ban đầu.
Tất cả công nhân là điều cần thiết

1
Nó không quan trọng nếu nó "hiệu quả" khác nhau. Tôi đã vào trang này để tìm kiếm cú pháp một dòng có thể được sử dụng python -ctrên dòng lệnh, vì vậy việc đăng câu trả lời 2 dòng không giúp ích gì.
dùng5359531

1
@ user5359531 Tôi không thấy quan điểm của bạn: bạn có biết rằng bạn có thể trích dẫn các biểu thức python với ", sử dụng ;để nối hai hướng dẫn và xóa dòng mới sau :không? Biểu hiện sau chỉ hoạt động tốt với tôi:$> python -c "with open('some file', 'r') as f: print(next(f))"
Joël

2

Tôi nghĩ rằng cách tự nhiên nhất để đạt được điều này là xác định một chức năng.

def read(filename):
    f = open(filename, 'r')
    output = f.read()
    f.close()
    return output

Sau đó, bạn có thể làm như sau:

output = read('pagehead.section.htm')

0

Tôi thường xuyên làm một cái gì đó như thế này khi tôi cần nhận được một vài dòng xung quanh thứ gì đó mà tôi đã ghi trong tệp nhật ký:

$ grep -n "xlrd" requirements.txt | awk -F ":" '{print $1}'
54

$ python -c "with open('requirements.txt') as file: print ''.join(file.readlines()[52:55])"
wsgiref==0.1.2
xlrd==0.9.2
xlwt==0.7.5

1
Hoàn toàn không liên quan đến chủ đề ban đầu, nhưng bạn nên nhìn vào grep -A <n>, grep -B <n>grep -C <n>, nếu nó là hữu ích. Thông tin thêm: stackoverflow.com/a/9083/1830159
Liam Stanley

0

Sử dụng more_itertools.with_iter, có thể mở, đọc, đóng và gán một tương đương outputtrong một dòng (không bao gồm câu lệnh nhập):

import more_itertools as mit


output = "".join(line for line in mit.with_iter(open("pagehead.section.htm", "r")))

Mặc dù có thể, tôi sẽ tìm một cách tiếp cận khác ngoài việc gán nội dung của tệp cho một biến, tức là lặp lại lười biếng - điều này có thể được thực hiện bằng cách sử dụng một withkhối truyền thống hoặc trong ví dụ trên bằng cách loại bỏ join()và lặp lại output.


Bạn có thể nhập bên trong oneliner là tốt. "".join(line for line in __import__('more_itertools').with_iter(open("pagehead.section.htm", "r")))Điều này chỉ hoạt động tốt, và loại bỏ sự cần thiết cho một dòng nhập khẩu.
melwil

1
Tôi hoàn toàn đồng ý với bạn. Tuy nhiên, trong khi thảo luận về việc giải quyết các nhiệm vụ với oneliners, tôi thường thấy mình trong các cuộc tranh luận trong đó kết quả đã được thống nhất sẽ là một dòng mã được dán vào vỏ trăn tươi. Những thách thức như vậy hiếm khi phù hợp với pep8. Đó không phải là một cách thực hành tốt để viết mã, nó chỉ có ý nghĩa như một mẹo để loại bỏ nhu cầu nhập khẩu.
melwil

0

Nếu bạn muốn cảm giác ấm áp và mờ nhạt đó chỉ cần đi với .

Đối với python 3.6, tôi đã chạy hai chương trình này dưới một khởi đầu mới của IDLE, đưa ra các thời gian:

0.002000093460083008  Test A
0.0020003318786621094 Test B: with guaranteed close

Vì vậy, không có nhiều sự khác biệt.

#--------*---------*---------*---------*---------*---------*---------*---------*
# Desc: Test A for reading a text file line-by-line into a list
#--------*---------*---------*---------*---------*---------*---------*---------*

import sys
import time

#                                  # MAINLINE
if __name__ == '__main__':
    print("OK, starting program...")

    inTextFile = '/Users/Mike/Desktop/garbage.txt'

#                                  # Test: A: no 'with;
    c=[]
    start_time = time.time()
    c = open(inTextFile).read().splitlines()
    print("--- %s seconds ---" % (time.time() - start_time))

    print("OK, program execution has ended.")
    sys.exit()                     # END MAINLINE

ĐẦU RA:

OK, starting program...
--- 0.002000093460083008 seconds ---
OK, program execution has ended.

#--------*---------*---------*---------*---------*---------*---------*---------*
# Desc: Test B for reading a text file line-by-line into a list
#--------*---------*---------*---------*---------*---------*---------*---------*

import sys
import time

#                                  # MAINLINE
if __name__ == '__main__':
    print("OK, starting program...")

    inTextFile = '/Users/Mike/Desktop/garbage.txt'

#                                  # Test: B: using 'with'
    c=[]
    start_time = time.time()
    with open(inTextFile) as D: c = D.read().splitlines()
    print("--- %s seconds ---" % (time.time() - start_time))

    print("OK, program execution has ended.")
    sys.exit()                     # END MAINLINE

ĐẦU RA:

OK, starting program...
--- 0.0020003318786621094 seconds ---
OK, program execution has ended.
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.