[英]Visibility of global variables in imported modules
我在 Python 腳本中遇到了一些導入模塊的問題。 我會盡力描述錯誤,為什么會遇到它,以及為什么我要使用這種特殊的方法來解決我的問題(我將在稍后描述):
假設我有一個模塊,我在其中定義了一些實用函數/類,它們引用了將要導入該輔助模塊的命名空間中定義的實體(讓“a”成為這樣的實體):
模塊1:
def f():
print a
然后我有主程序,其中定義了“a”,我想將這些實用程序導入其中:
import module1
a=3
module1.f()
執行程序會觸發如下錯誤:
Traceback (most recent call last):
File "Z:\Python\main.py", line 10, in <module>
module1.f()
File "Z:\Python\module1.py", line 3, in f
print a
NameError: global name 'a' is not defined
過去(兩天前,d'uh) 也提出了類似的問題,並提出了幾種解決方案,但我認為這些並不符合我的要求。 這是我的特定背景:
我正在嘗試制作一個 Python 程序,它連接到 MySQL 數據庫服務器並使用 GUI 顯示/修改數據。 為了簡潔起見,我在一個單獨的文件中定義了一堆與 MySQL 相關的輔助/實用程序函數。 但是它們都有一個公共變量,我最初在實用程序模塊中定義,它是 MySQLdb 模塊中的游標對象。 后來我意識到應該在主模塊中定義游標對象(用於與數據庫服務器通信),以便主模塊和導入到其中的任何內容都可以訪問該對象。
最終結果將是這樣的:
實用程序_module.py:
def utility_1(args):
code which references a variable named "cur"
def utility_n(args):
etcetera
我的主要模塊:
程序.py:
import MySQLdb, Tkinter
db=MySQLdb.connect(#blahblah) ; cur=db.cursor() #cur is defined!
from utilities_module import *
然后,一旦我嘗試調用任何實用程序函數,它就會觸發上述“未定義全局名稱”錯誤。
一個特別的建議是在實用程序文件中有一個“from program import cur”語句,例如:
實用程序_module.py:
from program import cur
#rest of function definitions
程序.py:
import Tkinter, MySQLdb
db=MySQLdb.connect(#blahblah) ; cur=db.cursor() #cur is defined!
from utilities_module import *
但這是循環導入或類似的東西,最重要的是,它也會崩潰。 所以我的問題是:
我怎么能讓主模塊中定義的“cur”對象對導入到其中的輔助函數可見?
感謝您的寶貴時間,如果解決方案已在其他地方發布,我深表歉意。 我自己找不到答案,而且我的書中沒有更多的技巧。
Python 中的全局變量對於一個模塊來說是全局的,而不是在所有模塊中。 (很多人對此感到困惑,因為在 C 語言中,全局在所有實現文件中都是相同的,除非您明確將其static
。)
有不同的方法可以解決這個問題,具體取決於您的實際用例。
在走這條路之前,問問自己這是否真的需要全球化。 也許你真的想要一個以f
作為實例方法的類,而不僅僅是一個自由函數? 然后你可以做這樣的事情:
import module1
thingy1 = module1.Thingy(a=3)
thingy1.f()
如果您確實想要一個全局變量,但它只是供module1
使用,請將其設置在該模塊中。
import module1
module1.a=3
module1.f()
另一方面,如果a
被很多模塊共享,請將其放在其他地方,並讓每個人都導入它:
import shared_stuff
import module1
shared_stuff.a = 3
module1.f()
…並且,在module1.py中:
import shared_stuff
def f():
print shared_stuff.a
不要使用from
導入,除非該變量是常量。 from shared_stuff import a
將創建一個新a
變量,該變量初始化為導入時引用的任何shared_stuff.a
,並且這個新a
變量不會受到對shared_stuff.a
的分配的影響。
或者,在極少數情況下,您確實需要它在任何地方都是真正的全局,例如內置,將其添加到內置模塊中。 Python 2.x 和 3.x 之間的確切細節有所不同。 在 3.x 中,它的工作方式如下:
import builtins
import module1
builtins.a = 3
module1.f()
作為一種解決方法,您可以考慮在外層設置環境變量,如下所示。
主要.py:
import os
os.environ['MYVAL'] = str(myintvariable)
我的模塊.py:
import os
myval = None
if 'MYVAL' in os.environ:
myval = os.environ['MYVAL']
作為額外的預防措施,處理模塊內部未定義 MYVAL 的情況。
函數使用定義它的模塊的全局變量。例如,您應該設置module1.a = 3
而不是設置a = 3
= 3 。 因此,如果您希望cur
在utilities_module
模塊中作為全局變量使用,請設置utilities_module.cur
模塊.cur。
更好的解決方案:不要使用全局變量。 將你需要的變量傳遞給需要它的函數,或者創建一個類將所有數據捆綁在一起,並在初始化實例時傳遞。
這篇文章只是對我遇到的 Python 行為的觀察。 如果您做了與我在下面所做的相同的事情,那么您在上面閱讀的建議可能對您不起作用。
也就是說,我有一個包含全局/共享變量的模塊(如上所述):
#sharedstuff.py
globaltimes_randomnode=[]
globalist_randomnode=[]
然后我有一個導入共享內容的主模塊:
import sharedstuff as shared
以及其他一些實際填充這些數組的模塊。 這些由主模塊調用。 退出這些其他模塊時,我可以清楚地看到數組已填充。 但是當在主模塊中讀回它們時,它們是空的。 這對我來說很奇怪(好吧,我是 Python 新手)。 但是,當我將在主模塊中導入 sharedstuff.py 的方式更改為:
from globals import *
它起作用了(填充了數組)。
只是在說'
解決這個特定問題的最簡單方法是在模塊中添加另一個函數,該函數將光標存儲在模塊的全局變量中。 然后所有其他功能也可以使用它。
模塊1:
cursor = None
def setCursor(cur):
global cursor
cursor = cur
def method(some, args):
global cursor
do_stuff(cursor, some, args)
主程序:
import module1
cursor = get_a_cursor()
module1.setCursor(cursor)
module1.method()
由於全局變量是特定於模塊的,因此您可以將以下函數添加到所有導入的模塊中,然后將其用於:
addglobals = lambda x: globals().update(x)
然后,您需要傳遞當前全局變量的是:
導入模塊
module.addglobals(globals())
由於我在上面的答案中沒有看到它,我想我會添加一個簡單的解決方法,即在需要調用模塊全局變量的函數中添加一個global_dict
參數,然后在調用時將 dict 傳遞給函數; 例如:
# external_module
def imported_function(global_dict=None):
print(global_dict["a"])
# calling_module
a = 12
from external_module import imported_function
imported_function(global_dict=globals())
>>> 12
執行此操作的 OOP 方法是使您的模塊成為一個類,而不是一組未綁定的方法。 然后你可以使用__init__
或 setter 方法來設置來自調用者的變量,以便在模塊方法中使用。
為了測試這個理論,我創建了一個模塊並將其放在 pypi 上。 這一切都很完美。
pip install superglobals
這在 Python 2 或 3 中運行良好:
import inspect
def superglobals():
_globals = dict(inspect.getmembers(
inspect.stack()[len(inspect.stack()) - 1][0]))["f_globals"]
return _globals
保存為superglobals.py
並因此在另一個模塊中使用:
from superglobals import *
superglobals()['var'] = value
您可以添加一些額外的功能,使事情更有吸引力。
def superglobals():
_globals = dict(inspect.getmembers(
inspect.stack()[len(inspect.stack()) - 1][0]))["f_globals"]
return _globals
def getglobal(key, default=None):
"""
getglobal(key[, default]) -> value
Return the value for key if key is in the global dictionary, else default.
"""
_globals = dict(inspect.getmembers(
inspect.stack()[len(inspect.stack()) - 1][0]))["f_globals"]
return _globals.get(key, default)
def setglobal(key, value):
_globals = superglobals()
_globals[key] = value
def defaultglobal(key, value):
"""
defaultglobal(key, value)
Set the value of global variable `key` if it is not otherwise st
"""
_globals = superglobals()
if key not in _globals:
_globals[key] = value
然后這樣使用:
from superglobals import *
setglobal('test', 123)
defaultglobal('test', 456)
assert(getglobal('test') == 123)
亂扔這個問題的“python 純度聯盟”答案是完全正確的,但是在某些基本上是單線程的環境(例如 IDAPython)中,它基本上是具有大型全局實例化 API 的單線程,它並不重要。
這仍然是一種不好的形式,也是一種不好的鼓勵做法,但有時它更容易。 尤其是當您編寫的代碼不會有很長的壽命時。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.