2011-06-21 23 views
53

Hãy xem xét ví dụ sau:Biến được xác định với câu lệnh có sẵn bên ngoài với khối?

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

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

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

+4

Câu hỏi có hay không f sẽ có sẵn trong phạm vi kèm theo đã được trả lời. Đối với tôi, toàn bộ khái niệm về các 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ề ngữ cảnh * khác với khái niệm * phạm vi *. Đây là một liên kết đến trang web của tôi hy vọng sẽ giúp một chút: http://www.markus-gattol.name/ws/python.html#context_manager – Tom

+0

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

Trả lời

96

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

+2

Đây là giải thích rõ ràng nhất trong quan điểm của tôi để trao giải câu trả lời được chấp nhận; sẽ cung cấp điểm cho Alex và TokenMacGuy để có thêm thông tin hữu ích. –

11

Trong trường hợp f là một tệp, tệp sẽ xuất hiện bên ngoài câu hỏi with.

Ví dụ, đâ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 các chi tiết trong PEP-0343 dưới Đặc điểm kỹ thuật phần : Các 'với' Tuyên bố. Python scope rules (có thể là irritating) cũng áp dụng cho f.

+0

Tôi biết điều này, tôi đã đề cập đến nó trong câu hỏi. Cho CPython 2.6.5 ít nhất. Nhưng bạn có thể đảm bảo rằng điều này giữ cho Jython, IronPython và PyPy? –

+0

Quy tắc phạm vi của Python không phải lúc nào cũng rõ ràng. Hãy xem xét điều này trong CPython 2.6.5: '[x cho x trong [1]]'. 'x' có sẵn bên ngoài đó. Làm cho nó thành một máy phát điện: '(x cho x trong [1])'. Bây giờ 'x' khô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 danh sách hiểu 'x' sẽ 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ờ. –

+0

Tôi đã tìm kiếm, nhưng không tìm thấy bất kỳ điều gì đáng kể cho bây giờ. Câu hỏi thú vị, mặc dù. – miku

17

các with cú pháp:

with foo as bar: 
    baz() 

xấp xỉ đường cho:

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

này thường rất hữu ích: ví dụ

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

with myLock: 
    frob_some_more() 

người quản lý bối cảnh có thể được sử dụng nhiều hơn Một lần.

+0

Bạn có chắc chắn điều này sẽ làm việc trong Jython, IronPython và PyPy? –

+0

Vâng, khóa tái sử dụng có thể hoặc có thể không (không có ý tưởng, nhưng nó sẽ là một lỗi nếu họ đã khác nhau) - nhưng các quy tắc scoping Python chắc chắn sẽ giống nhau ở đây trên thực hiện. – fuzzyman

+1

điều nà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 thực hiện foo .__ exit__ đặt luồng vào trạng thái dừng, sau đó trừ khi khóa có __enter__ để gắn lại nó, câu lệnh thứ hai không giống như nó sẽ làm bất cứ điều gì hữu ích cho các khóa chuỗi. –

8

Để trả lời câu hỏi của Heikki trong nhận xét: có, hành vi 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 mọi Pythons tương thích (bao gồm PyPy, Jython và IronPython).

Các vấn đề liên quan