簡體   English   中英

告訴編譯器它不知道的本地?

[英]Tell compiler about a local it doesn't know about?

我有一個名為let的函數,它修改調用命名空間以插入一個新變量。

def let(**nameValuePair):
    from inspect import stack

    name, value = nameValuePair.items()[0]
    stack()[1][0].f_locals[name] = value
    return value

這個想法是它允許你在任何你想要的地方插入賦值語句,即使Python中通常不允許賦值語句(盡管let()需要5個額外的字符。

從全局命名空間調用時,這非常有效。

>>> let(outside = 'World')
>>> print(outside)
World

這失敗並出現錯誤NameError: global name 'hello' is not defined

>>> def breaker():
...     let(hello = 'World')
...     print(hello)
...
>>> breaker()

你可能會得出結論,問題在於我的let函數。 它不是 - 我的功能表現完美。 告訴你:

>>> def fine():
...     let(another = 'World')
...     print(locals()['another'])
...
>>> fine()
World

問題實際上來自於Python解釋器編譯breaker 為了演示,我將創建另一個函數,它與breaker做同樣的事情,但使用普通賦值而不是let ,然后我將用dis反編譯。

>>> def normal():
...     hello = 'World'
...     print(hello)
...
>>> normal()
World

>>> from dis import dis
>>> print(dis(normal))
 0 LOAD_CONST               1 ('World')
 3 STORE_FAST               0 (hello)
 6 LOAD_FAST                0 (hello)
 9 PRINT_ITEM
10 PRINT_NEWLINE
11 LOAD_CONST               0 (None)
14 RETURN_VALUE

>>> print(dis(breaker))
 0 LOAD_GLOBAL              0 (let)
 3 LOAD_CONST               1 ('hello')
 6 LOAD_CONST               2 ('World')
 9 CALL_FUNCTION          256
12 POP_TOP
13 LOAD_GLOBAL              2 (hello)  # <= This is the real problem.
16 PRINT_ITEM
17 PRINT_NEWLINE
18 LOAD_CONST               0 (None)
19 RETURN_VALUE

問題是,編譯器正在查看breaker ,沒有看到hello被分配到本地范圍內的任何位置,因此假設它必須是全局變量。

我該怎么辦? 當我的函數被調用時,我可以換掉我指出的有問題的行並將其替換為:

LOAD_GLOBAL 1 (locals)
CALL_FUNCTION 0
LOAD_CONST 1 ('hello')  # Or whatever the name of the variable is
BINARY_SUBSCR

我知道我可以通過簡單地將變量存儲在全局范圍內來快速解決當前問題,但這可能會導致許多微妙的錯誤。 僅舉幾例:

  1. 全局變量被覆蓋。
  2. 對象可能會在內存中持續存在的時間遠遠超過預期。
  3. 否則將是一個錯字的東西是有效的。 (誠​​然,這個似乎不太可能)。

...實際上,如果我可以更改已編譯的代碼,我甚至可以在RETURN_VALUE之后添加STORE_GLOBALDELETE_GLOBAL 將前全局變量緩存到別處或其他什么?

locals()的文檔說明如下:

注意不應修改此詞典的內容; 更改可能不會影響解釋器使用的本地和自由變量的值。

我檢查過,並沒有在inspect文檔中看到關於f_locals的明確說明,但我不明白為什么會有任何不同。

簡短的版本是,你做不到。 你不能在3.x中做到這一點,你不能在2.x的最新版本中做到這一點,如果你能夠可靠地做到這一點我會感到驚訝。 您將來也無法做到這一點,因為局部變量太容易成為優化的目標。 一個編譯器無法實現這一點,更不用說所有的python編譯器了。

另一方面,也許還有另一種方法可以做你想做的事情。 那是什么?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM