我对python还是很陌生,我正在开发具有单例类的应用程序(我知道人们对单例的看法,但它们适合我的需求),但是我遇到了一个不会引起问题的问题单身人士,但确实阻止了他们正常工作。
考虑以下代码(不涉及单例):
main.py
class Test:
pass
def main():
print("main.py:", Test, id(Test))
import test
if __name__ == '__main__':
main()
test.py
from main import Test
print("test.py:", Test, id(Test))
结果:
main.py: <class '__main__.Test'> 1382824602424
test.py: <class 'main.Test'> 1382824594872
看来 main.py 中的Test
类与 test.py 中的{strong>不它们具有不同的名称和ID),因此Test
类在 test.py ?
注意:我尝试使用import main
和main.Test
来代替-结果相同。
python的这种奇怪行为实际上阻止了我的单例实现正常工作。
这是单例元类的实现:
from collections import defaultdict
# A `defaultdict` subclass which passes the missing key
# as an argument to `default_factory`
class KeyDefaultDict(defaultdict):
def __missing__(self, key):
if self.default_factory is None:
raise KeyError(key)
res = self[key] = self.default_factory(key)
return res
class Singleton(type):
# a dictionary that maps between the singleton class
# and the singleton object of that class. When attempting
# to access the singleton object for the first time (via
# the `instance` property), the object will be created and
# added to the dictionary (lazy initialization).
__instances = KeyDefaultDict(type.__call__)
def __new__(mcs, name, bases, dct):
# prevent inheritance from a singleton class
for base in bases:
if isinstance(base, mcs):
raise TypeError("Singletons can't be inherited from")
return super().__new__(mcs, name, bases, dct)
def __call__(cls, *args, **kwargs):
raise TypeError("Singletons can't be instantiated")
@property
def instance(cls):
try:
return cls.__instances[cls]
except TypeError as e:
# happens when the singleton class `__init__` method
# has more parameters than just self
raise TypeError("Singletons can't be instantiated "
"with parameters") from e
和一个简单的用法示例,证明该单例有效:
class MySingleton(metaclass=Singleton):
def __init__(self):
print("Initialized") # will be printed once
self.x = 5
s1 = MySingleton.instance # "Initialized" printed
s2 = MySingleton.instance
assert s1 is s2, "Singleton failed"
assert s1 is MySingleton.instance, "Singleton failed"
print(s1.x, s2.x, MySingleton.instance.x) # output: 5 5 5
MySingleton.instance.x = 10
print(s1.x, s2.x, MySingleton.instance.x) # output: 10 10 10
使用此实现,至关重要的一点是,类不要更改,因此其键在__instances
词典中保持不变。但是,在上面的示例中,如果我使Test
类成为单例,则Test.instance
将导致 main.py 和不同对象> test.py ,因为它们是“不同”的类(不同的ID)。换句话说,我在__instances
中得到了两个 different 键:一个用于 main.py ,另一个用于 test.py ,其中相同的类Test
导致单例类的两个不同对象。
在互联网上搜索后,我发现这是python中单例模式的最佳实现(我认为),因此我宁愿不要更改它,而要更改或解决python的奇怪行为代替。
能否请您向我解释为什么python在不同文件中像这样处理Test
类,更重要的是,如何更改该行为或解决该问题,所以Test
类将在主脚本和任何外部python脚本中都一样吗?
注意:我正在Windows 10上使用python 3.6.5。