![](/img/trans.png)
[英]Tell Flask-Migrate / Alembic to NOT drop any tables it doesn't know about
[英]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
我知道我可以通過簡單地將變量存儲在全局范圍內來快速解決當前問題,但這可能會導致許多微妙的錯誤。 僅舉幾例:
...實際上,如果我可以更改已編譯的代碼,我甚至可以在RETURN_VALUE
之后添加STORE_GLOBAL
或DELETE_GLOBAL
? 將前全局變量緩存到別處或其他什么?
locals()
的文檔說明如下:
注意不應修改此詞典的內容; 更改可能不會影響解釋器使用的本地和自由變量的值。
我檢查過,並沒有在inspect
文檔中看到關於f_locals
的明確說明,但我不明白為什么會有任何不同。
簡短的版本是,你做不到。 你不能在3.x中做到這一點,你不能在2.x的最新版本中做到這一點,如果你能夠可靠地做到這一點我會感到驚訝。 您將來也無法做到這一點,因為局部變量太容易成為優化的目標。 一個編譯器無法實現這一點,更不用說所有的python編譯器了。
另一方面,也許還有另一種方法可以做你想做的事情。 那是什么?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.