从主脚本导入类会创建该类的副本吗?

时间:2018-06-23 16:23:21

标签: python class singleton python-import

我对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 mainmain.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。

0 个答案:

没有答案