如果這是您代碼,不是解決方案不是依賴於模塊級變量,而是以某種其他方式來保持對象的狀態。 Python中的模塊是「單身」 - 這意味着一旦任何模塊導入,只有一個版本,然後解釋器寬 - 例如,你想要的行爲正是你得到的,如果你使用類繼承 - 子類可以自定義一些,但不需要重寫所有的父類。
所以,如果你就像封裝你「foo」的代碼的類裏面 - 你甚至可以不寫,需要實例類,你得到的功能,你想不已:
#foo module:
class Foo(object):
sanitize = "value 1"
@classmethod
def parse(cls):
print cls.sanitize
#foo2
from foo import Foo
class Foo2(Foo):
sanitize = "value 2"
# code:
from foo import Foo
from foo2 import Foo2
Foo.parse()
Foo2.parse()
中當然,隨着Python允許的內省和元編程的歡呼聲,它可能會像你想要的那樣做一些事情 - 但這會讓問題複雜化,因爲沒有好處。模塊變量與C代碼中的全局變量具有大部分相同的缺點。
這樣做的一種方法是在通過foo2訪問時使「foo」變爲動態變化,在「foo」中調用函數並在退出時恢復先前的值。 對於在模塊「foo2」上的「foo」屬性訪問上觸發的任意代碼,「foo」必須引用具有「屬性」屬性的對象 - 因此,您編寫的exa示例會運行,在併發性,不安全的方式,順便說一句,非常不安全的方式,如果foo2的寫入或多或少這樣:
import foo as _foo
SANITIZE = "value2"
class _FooWrapper(object):
def __getattribute__(self, attr):
self.change_vars()
original_function = getattr(_foo, attr)
if callable(original):
def wrapper(func):
def new_func(*args, **kw):
res = func(*args, **kw)
self.restore_vars()
return res
return new_func
return wrapper(original)
return original
def change_vars(self):
self.original_sanitize = _foo.SANITIZE
_foo.SANITIZE = SANITIZE
def restore_vars(self):
__foo.SANITIZE = self.original_sanitize
foo = _FooWrapper()
這將在模塊foo2的一個訪問,當「foo」的對象,獲取任何請求的屬性從原來的「富」模塊。因此,「foo2.foo.parse」將獲得「foo」解析函數 - 但是,在這種方法中,感知「hackiness」的數量 - 爲了能夠恢復生活在「foo」模塊中的原始值Python解釋器,在從foo2獲取函數之後,該函數也會返回,自己恢復這些值。唯一的方法是修改該函數,以便它在返回時運行附加代碼 - 因此它由上面的代碼實時裝飾。
我認爲這個例子清楚地表明,在這種情況下使用模塊級配置並不是可行的方法。
編輯 的O.P.評論:
感謝jsbueno,遺憾的是這不是我的代碼,我必須依靠 模塊級變量。包裝類方法是有趣 但正如你所說,非常哈克和令人難以置信的非線程安全的,這我恐怕 不會爲我的情況
在回答該做的事:
模塊是「單身人士」 - 因此,更改模塊上的變量,在 任何一點都會使其線程不安全。另一種方式,我可以考慮 這是創建一個「複印機」模塊,實際上重新創建 類別,屬性和實例的另一個現有的模塊,當 導入 - 重新綁定所有函數的全局變量(方法將 仍然被處理爲在這個級別的功能)
閱讀本說明書聽起來作爲「unfeasable」 - 但它不是容易完成的描述 - 這裏緊跟我的「foo2的」模塊,做以上:
from types import ModuleType, FunctionType
import foo as _foo
SANITIZE = "value 2"
def rebuild_function(func, glob):
"""Rebinds the globals in the given functions to globals in
this module by default"""
new_func = FunctionType(func.func_code,
glob,
func.func_name,
func.func_defaults,
func.func_closure)
return new_func
def rebuild_class(cls, glob):
metatype = type(cls)
dct = cls.__dict__.copy()
for key, value in dct.items():
if isinstance(value, FunctionType):
dct[key] = rebuild_function(value, glob)
return metatype(cls.__name__, cls.__bases__, dct)
def rebuild_module(mod,glob):
new_module = ModuleType(mod.__name__)
for key, value in mod.__dict__.items():
if isinstance(value, FunctionType):
value = rebuild_function(value, glob)
elif isinstance(value, type):
value = rebuild_class(value, glob)
setattr(new_module, key, value)
return new_module
foo = rebuild_module(_foo, globals())
__all__ = ["foo", "SANITIZE"]
這段代碼確實如此我所描述的 - 它重新創建原始模塊中的所有函數對象,重新指定每個函數的全局變量字典。它是併發安全的。如果待克隆模塊確實指向本地代碼類或函數(它們不是「FunctionType」),則存在一些轉角情況。如果它大量使用多個類繼承,metaclasses, - 它有用或不可用。
我用一個簡單的類測試,它工作得很好:
#module "foo"
SANITIZE='foo'
def parse():
print SANITIZE
class Parser(object):
def __init__(self):
print SANITIZE * 2
而且
#test script
import foo
import foo2
foo2.foo.parse() #i want this to print 'foo2'
foo2.foo.Parser()
foo.parse() #i want this to print 'foo'
foo.Parser()
輸出:
[[email protected] tmp16]$ python test_foo.py
foofoo
value 2
value 2value 2
foo
foofoo
[[email protected] tmp16]$
這個代碼是沒有意義的,foo.parse ()在任何情況下都會打印'foo',這是一個不以任何方式依賴於SANITIZE的常量。 – yurib
對於那個yurib抱歉,我解決了它。 – djs22
你總是可以刪除並重新加載foo.py –