簡體   English   中英

如何解決模塊中的全局變量?

[英]How to resolve a global variable in a module?

我有一個腳本如下

from mapper import Mapper

class A(object):
    def foo(self):
        print "world"

a = A()
a.foo()
Mapper['test']()

使用mapper.py文件中定義的Mapper

Mapper = {'test': a.foo}

我想在哪里定義一個函數調用,引用一個未在mapper.py定義的對象,但在原始代碼中。 但是上面的代碼給出了錯誤

NameError: name 'a' is not defined

這使得那種感覺,作為a沒有定義mapper.py本身。 但是,是否可以更改代碼以使代碼在主代碼本身中執行名稱解析,或者使用globals或其他東西?

為了解決這個問題,我可以將mapper.py的實現指定為文本,並在主代碼中使用eval ,但我想避免使用eval

附加信息:

  • 函數的完整定義必須在mapper.py
  • 這是事先不知道的情況是什么a是,或什么CLAS它被實例化。

除非像eval這樣的安全漏洞,否則無法在mapper.py使用名稱a ,除非該名稱在mapper.py某處定義或從其他模塊導入。 沒有辦法讓mapper.py自動並靜默地訪問來自不同模塊的值a

另外,如果你只是在你的例子中的dict中使用它, a.foo將在創建dict時立即進行評估。 它不會等到你實際調用該函數; 只要它計算a.foo創建字典,它會失敗,因為它不知道是什么a是。

您可以通過將元素包裝在函數中來解決第二個問題(為簡潔起見使用lambda):

Mapper = {'test': lambda: a.foo}

但這仍然不會幫助,除非你能以某種方式得到a可用的內部mapper.py

一種可能性是通過“神秘”對象對Mapper進行參數化,然后從外部傳遞該對象:

# mapper.py
Mapper = {'test': lambda a: a.foo}

# other module
from mapper import Mapper
Mapper['test'](a)()

或者,類似於mgilson建議的,你可以用Mapper以某種方式“注冊”對象a 這使您可以傳遞對象a唯一的一次注冊,然后你不必把它傳遞每一個呼叫:

# mapper.py
Mapper = {'test': lambda a: Mapper['a'].foo}

# other module
from mapper import Mapper
Mapper['a'] = a
Mapper['test']()()

注意那里的兩組括號:一組用於評估lambda並提取你想要調用的函數,另一組用於實際調用該函數。 您可以使用模塊級變量執行類似的處理,而不是使用Mapper['a']作為引用:

# mapper.py
Mapper = {'test': lambda: a.foo}

# other module
import mapper
Mapper = mapper.Mapper

mapper.a = a
Mapper['test']()()

請注意,這需要您執行import mapper以便在該其他模塊中設置模塊變量。

您可以通過使用Mapper的自定義類而不是常規字典來簡化這一點,並讓該類在其__getitem__執行一些工作以查看“已知位置”(例如,讀取某個模塊變量)以用作基礎評估a 不過,這將是一個更重的解決方案。

底線是你根本不能(再次,沒有使用eval或其他這樣的漏洞)在mapper.py中編寫使用未定義變量a ,然后在另一個模塊中定義變量a並讓mapper.py自動知道關於那個。 必須有一些代碼行,某處“講述” mapper.py什么價值a你想使用它。

我不知道我完全跟隨,而是a可以“注冊”這是法Mapper由具有參考映射器的任何地方:

#mapping.py
Mapper = {}

接着:

#main.py
from mapping import Mapper

#snip
a = A()
Mapper['test'] = a.foo #put your instance method into the Mapper dict.
#snip

Mapper['test']()

暫無
暫無

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

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