PEP 8 không quá rõ ràng về điều đó. Nó chỉ đề cập đến tuyên bố with
một lần cho một trường hợp ngoại lệ khi tiếp tục dấu gạch chéo ngược là không sao:
Dấu gạch chéo ngược đôi khi vẫn có thể thích hợp.Ví dụ, rất lâu, nhiều với -statements không thể sử dụng tiếp tục tiềm ẩn, vì vậy backslashes được chấp nhận:
with open('/path/to/some/file/you/want/to/read') as file_1, \
open('/path/to/some/file/being/written', 'w') as file_2:
file_2.write(file_1.read())
Một cách để khắc phục những vấn đề này sẽ được thực sự đầu tiên thực hiện cuộc gọi hàm trả về người quản lý bối cảnh và sau đó chỉ cần sử dụng trực tiếp, như bạn đã gợi ý trong câu hỏi của bạn:
file_1 = open('/path/to/some/file/you/want/to/read')
file_2 = open('/path/to/some/file/being/written', 'w')
with file_1, file_2:
file_2.write(file_1.read())
này hoạt động hoàn hảo (vì tuyên bố with
chỉ sẽ gọi các phương thức quản lý bối cảnh của, bất kể nó đến từ đâu), và cũng có thể đóng xử lý một cách chính xác .
Tuy nhiên, điều này là không được phép explicitely trong PEP 8:
nhà quản lý Bối cảnh nên được gọi thông qua chức năng hoặc các phương pháp riêng biệt mỗi khi họ làm điều gì đó khác hơn là tiếp thu và giải phóng tài nguyên. Ví dụ:
Có:
with conn.begin_transaction():
do_stuff_in_transaction(conn)
Số:
with conn:
do_stuff_in_transaction(conn)
Ví dụ thứ hai không cung cấp bất kỳ thông tin để chỉ ra rằng các __enter__
và __exit__
phương pháp đang làm một cái gì đó khác hơn là đóng kết nối sau một giao dịch. Rõ ràng là quan trọng trong trường hợp này.
Vì vậy, cuối cùng, có vẻ là không có giải pháp thực sự mà được phép bởi PEP 8. Và vào thời điểm đó, tôi sẽ tranh luận, rằng nó hoàn toàn tốt đẹp để “vi phạm nó” và đi ngược lại nó: Nó chỉ một phong cách hướng dẫn.
Trong khi nó gợi ý nhiều quy tắc tốt, cũng có nhiều tình huống, trong đó đơn giản là không có ý nghĩa gì khi theo dõi chúng một cách nghiêm túc. Tôi cho rằng ví dụ bằng cách sử dụng dấu gạch chéo là khó có thể đọc được, và có lẽ bạn có thể đọc được nó tốt hơn rất nhiều nếu bạn cho phép dòng lâu hơn và chỉ phá vỡ đường dây một lần mỗi quản lý bối cảnh:
with tempfile.NamedTemporaryFile(prefix='malt_input.conll.', dir=self.working_dir, mode='w', delete=False) as input_file, \
tempfile.NamedTemporaryFile(prefix='malt_output.conll.', dir=self.working_dir, mode='w', delete=False) as output_file:
pass
Có, bạn có thể cần phải di chuyển cho điều này, nhưng ít nhất bạn có thể thấy rất rõ những gì đang xảy ra.
Một lựa chọn khác sẽ được thực sự khởi tạo các đối tượng trực tiếp trước khi with
:
malt_input = tempfile.NamedTemporaryFile(prefix='malt_input.conll.', dir=self.working_dir, mode='w', delete=False)
malt_output = tempfile.NamedTemporaryFile(prefix='malt_output.conll.', dir=self.working_dir, mode='w', delete=False)
with malt_input as input_file, malt_output as output_file:
pass
Kể từ khi bạn làm điều đó trực tiếp trước khi with
, nó phải là một ngoại lệ có thể chấp nhận từ PEP 8 quy tắc ở đây. Sau khi tất cả, nó cải thiện khả năng đọc, và đó là những gì đếm.
Btw. lưu ý rằng người quản lý ngữ cảnh không thể trả lại self
trên __enter__
, vì vậy bạn vẫn nên sử dụng cú pháp as
để chỉ định giá trị trả lại của trình quản lý ngữ cảnh cho một biến.
Cuối cùng, một lựa chọn khác, mà sẽ làm việc cho tình hình cụ thể của bạn, sẽ được quấn cuộc gọi của bạn thành một chức năng riêng biệt:
def namedTemp(prefix):
return tempfile.NamedTemporaryFile(prefix=prefix,
dir=self.working_dir, mode='w', delete=False)
with namedTemp('malt_input.conll.') as input_file, \
namedTemp('malt_output.conll.') as output_file:
pass
Vì vậy, về cơ bản, trừu tượng tất cả mọi thứ đi, do đó tuyên bố with
có thể đọc lại được.
Có một phần trong [PEP8] (https://www.python.org/dev/peps/pep-0008/#maximum-line-length) về độ dài dòng tối đa – GP89
[Ngoài PEP8] (https: // www.youtube.com/watch?v=wf-BqAjZb8M)! – mkrieger1
có thể trùng lặp của [Làm thế nào để phá vỡ một tuyên bố dài trong python] (http://stackoverflow.com/questions/16080049/how-to-break-a-long-with-statement-in-python) – mkrieger1