2010-05-01 36 views
17

Trong Python 2.6,Tại sao đóng cửa bị phá vỡ trong exec?

>>> exec "print (lambda: a)()" in dict(a=2), {} 
2 
>>> exec "print (lambda: a)()" in globals(), {'a': 2} 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<string>", line 1, in <module> 
    File "<string>", line 1, in <lambda> 
NameError: global name 'a' is not defined 
>>> exec "print (lambda: a).__closure__" in globals(), {'a': 2} 
None 

tôi mong đợi nó để in 2 hai lần, và sau đó in một tuple với một đơn cell. Tình hình tương tự trong 3.1. Chuyện gì vậy?

Trả lời

24

Khi bạn chuyển một chuỗi đến exec hoặc eval, nó biên dịch chuỗi đó thành đối tượng mã trước khi xem xét hình ảnh tổng thể hoặc người dân địa phương. Vì vậy, khi bạn nói:

eval('lambda: a', ...) 

nó có nghĩa là:

eval(compile('lambda: a', '<stdin>', 'eval'), ...) 

Không có cách nào cho compile để biết rằng a là một freevar, vì vậy nó biên dịch nó vào một tài liệu tham khảo toàn cầu:

>>> c= compile('lambda: a', '<stdin>', 'eval') 
>>> c.co_consts[0] 
<code object <lambda> at 0x7f36577330a8, file "<stdin>", line 1> 
>>> dis.dis(c.co_consts[0]) 
    1   0 LOAD_GLOBAL    0 (a) 
       3 RETURN_VALUE   

Vì vậy, để làm cho nó hoạt động, bạn phải đặt a trong các hình cầu chứ không phải người dân địa phương.

Vâng, có một chút tinh ranh. Nhưng sau đó đó là execeval cho bạn, tôi cho rằng ... chúng không phải là tốt đẹp.

+0

+1. Tôi đã làm mới chủ đề này một lần mỗi phút kể từ khi nó được đăng để tìm ra câu trả lời cho câu hỏi này. Nhờ bạn, tôi bây giờ được tự do để lại cho tôi một thời gian và đi ra ngoài và tận hưởng ánh nắng mặt trời. Cảm ơn bạn! ;) –

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