Biến được xác định với câu lệnh with có sẵn bên ngoài with-block?


88

Hãy xem xét ví dụ sau:

with open('a.txt') as f:
    pass
# Is f supposed to be defined here?

Tôi đã đọc tài liệu ngôn ngữ (2.7) cho with-statement cũng như PEP-343, nhưng theo như tôi có thể nói thì họ không nói gì về vấn đề này.

Trong CPython 2.6.5 fdường như được định nghĩa bên ngoài with-block, nhưng tôi không muốn dựa vào chi tiết triển khai có thể thay đổi.


8
Câu hỏi liệu f có khả dụng trong phạm vi bao quanh hay không đã được trả lời. Đối với tôi, toàn bộ khái niệm về trình quản lý ngữ cảnh được nhấp vào khi tôi nhận ra rằng khái niệm về bối cảnh khác với khái niệm về phạm vi . Dưới đây là một liên kết đến trang web của tôi mà hy vọng sẽ giúp một chút: markus-gattol.name/ws/python.html#context_manager
Tom

1
Chính xác - ngữ cảnh là vấn đề thay đổi trạng thái hiện tại - mở tệp, đóng tệp hoặc khóa / mở khóa luồng. Đã phân bổ / phân bổ thiết bị. Tất cả các biến có tên trong phạm vi vẫn ở đó - nhưng bây giờ chúng sẽ trỏ đến các chốt được phân bổ / đóng / mở khóa được thỏa thuận.
Danny Staple

Câu trả lời:


158

Có, trình quản lý ngữ cảnh sẽ có sẵn bên ngoài câu lệnh with và điều đó không phụ thuộc vào việc triển khai hoặc phiên bản. với các câu lệnh không tạo ra một phạm vi thực thi mới.


3
Đây là lời giải thích rõ ràng nhất theo quan điểm của tôi nên việc trao giải cho câu trả lời được chấp nhận; sẽ cho điểm Alex và TokenMacGuy để biết thêm thông tin hữu ích.
Heikki Toivonen

Một cái gì đó mà người ta có thể dễ dàng quên nếu không làm việc với Python trong một thời gian, chức năng như thụt lề, tên và nội dung cho thấy rằng bạn sẽ không thể truy cập nó nhưng bạn có thể.
Vitaliy Terziev

28

các withcú pháp:

with foo as bar:
    baz()

là khoảng đường cho:

try:
    bar = foo.__enter__()
    baz()
finally:
    if foo.__exit__(*sys.exc_info()) and sys.exc_info():
        raise

Điều này thường hữu ích. Ví dụ

import threading
with threading.Lock() as myLock:
    frob()

with myLock:
    frob_some_more()

trình quản lý ngữ cảnh có thể được sử dụng nhiều lần.


Chà, việc sử dụng lại khóa có thể có hoặc có thể không (không có ý kiến, nhưng sẽ là một lỗi nếu chúng khác nhau) - nhưng các quy tắc xác định phạm vi Python chắc chắn sẽ giống nhau ở đây trên các triển khai.
dimman

1
đây một lần nữa không phải là một vấn đề phạm vi. Phạm vi sẽ giống nhau. Tuy nhiên, nếu việc triển khai foo .__ exit__ đặt luồng vào trạng thái dừng, thì trừ khi lock có một phím nhập để khóa lại nó, câu lệnh thứ hai có vẻ như nó sẽ không hữu ích gì đối với các khóa luồng.
Danny Staple

16

Trong trường hợp flà một tệp, nó sẽ được đóng bên ngoài withcâu lệnh.

Ví dụ, điều này

f = 42
print f
with open('6432134.py') as f:
    print f
print f

sẽ in:

42
<open file '6432134.py', mode 'r' at 0x10050fb70>
<closed file '6432134.py', mode 'r' at 0x10050fb70>

Bạn có thể tìm thấy chi tiết trong PEP-0343 trong phần Đặc điểm kỹ thuật: Tuyên bố 'với' . Các quy tắc phạm vi Python (có thể gây khó chịu ) cũng áp dụng cho f.


Tôi biết điều này, tôi đã đề cập đến nó trong câu hỏi. Đối với CPython 2.6.5 ít nhất. Nhưng bạn có thể đảm bảo rằng điều này cũng đúng với Jython, IronPython và PyPy?
Heikki Toivonen

Các quy tắc phạm vi của Python không phải lúc nào cũng rõ ràng như vậy. Hãy xem xét điều này trong CPython 2.6.5 : [x for x in [1]]. xcó sẵn bên ngoài đó. Làm cho nó thành một máy phát điện: (x for x in [1]). Bây giờ xkhông có sẵn. Tôi dường như nhớ lại điều này đã được thay đổi trong Python 3 để ngay cả với khả năng hiểu danh sách xsẽ không bị rò rỉ, nhưng tôi không thể tìm thấy tài liệu tham khảo bây giờ.
Heikki Toivonen

Tôi đã tìm kiếm, nhưng không tìm thấy bất cứ điều gì quan trọng cho đến bây giờ. Tuy nhiên, câu hỏi thú vị.
miku

Thực ra đây không phải là vấn đề về phạm vi - biến f vẫn có sẵn, nhưng bây giờ nó là một xử lý để tệp ở trạng thái đóng - cùng một tệp đã được mở trước đó. Lệnh thoát khi rời ngữ cảnh sẽ thay đổi trạng thái này.
Danny Staple

11

Để trả lời câu hỏi của Heikki trong phần nhận xét: vâng, hành vi xác định phạm vi này là một phần của đặc tả ngôn ngữ python và sẽ hoạt động trên bất kỳ và tất cả các Pythons tuân thủ (bao gồm PyPy, Jython và IronPython).

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.