Skip to main content
 首页 » 编程设计

Python Singletons之你如何在你的测试平台中摆脱(__del__)它们

2025年05月04日16powertoolsteam

非常感谢您迄今为止给我的建议。使用测试台是这个论坛真正向我展示的东西,对此我很感激。我的问题是我正在玩单例,通常我不会删除它,但在测试台上我需要这样做。那么谁能告诉我如何删除这件事?我从 basic example 开始并将其构建到测试台中,这样我就可以看到发生了什么。现在我不知道如何摆脱它!

非常感谢!!

import sys 
import logging 
import unittest 
 
LOGLEVEL = logging.DEBUG 
 
class Singleton: 
    """ A python singleton """ 
 
    class __impl: 
        """ Implementation of the singleton interface """ 
        def __init__(self): 
            self.log = logging.getLogger() 
            self.log.debug("Init %s" % self.__class__.__name__) 
 
        def id(self): 
            """ Test method, return singleton id """ 
            return id(self) 
 
 
    # storage for the instance reference 
    __instance = None 
 
    def __init__(self): 
        """ Create singleton instance """ 
        # Check whether we already have an instance 
        if Singleton.__instance is None: 
            # Create and remember instance 
            Singleton.__instance = Singleton.__impl() 
 
        # Store instance reference as the only member in the handle 
        self.__dict__['_Singleton__instance'] = Singleton.__instance 
 
    def __getattr__(self, attr): 
        """ Delegate access to implementation """ 
        return getattr(self.__instance, attr) 
 
    def __setattr__(self, attr, value): 
        """ Delegate access to implementation """ 
        return setattr(self.__instance, attr, value) 
 
class A: 
    def __init__(self): 
        self.log = logging.getLogger() 
        self.log.debug("Init %s" % self.__class__.__name__) 
        self.lowclass = Singleton() 
        self.id = self.lowclass.id() 
        self.log.debug("ID: %s" % self.id) 
 
class B: 
    def __init__(self): 
        self.log = logging.getLogger() 
        self.log.debug("Init %s" % self.__class__.__name__) 
        self.lowclass = Singleton() 
        self.id = self.lowclass.id() 
        self.log.debug("ID: %s" % self.id) 
 
 
class ATests(unittest.TestCase): 
 
    def testOne(self): 
        a = A() 
        aid = a.id 
        b = B() 
        bid = b.id 
        self.assertEqual(a.id, b.id) 
 
        # 
        # How do I destroy this thing?? 
        # 
 
        del a 
        del b 
 
        a1 = A() 
        a1id = a1.id 
        self.assertNotEqual(a1id, aid) 
 
if __name__ == '__main__': 
    # Set's up a basic logger 
    logging.basicConfig( format="%(asctime)s %(levelname)-8s %(module)s %(funcName)s %(message)s",  
                         datefmt="%H:%M:%S", stream=sys.stderr ) 
    log = logging.getLogger("") 
    log.setLevel(LOGLEVEL) 
    #  
    suite = unittest.TestLoader().loadTestsFromTestCase(ATests) 
    sys.exit(unittest.TextTestRunner(verbosity=LOGLEVEL).run(suite)) 

请您参考如下方法:

作为 Borg 的作者,我显然支持@mjv 的评论,但是,对于 Borg(又名“monostate”)或 Highlander(又名“singleton”),您需要添加一个“删除一切”方法来支持 tearDown 在你的测试套件中。用一个前导下划线命名这样的方法会告诉 sw 的其他部分不要管它,但测试是非典型的野兽,通常需要处理这些其他内部属性。

因此,对于您的具体情况,

class Singleton: 
   ... 
   def _drop(self): 
   "Drop the instance (for testing purposes)." 
   Singleton.__instance = None 
   del self._Singleton__instance 

类似地,对于 Borg,_drop 方法将释放并清除共享字典并将其替换为全新的字典。