【问题标题】:Python garbage collection and singletons classesPython 垃圾收集和单例类
【发布时间】:2020-11-29 21:47:13
【问题描述】:

我有一个单例类,但我不明白 Python 垃圾收集器如何不删除实例。

我正在使用 - from singleton_decorator import singleton

我班的例子:

from singleton_decorator import singleton

@singleton
class FilesRetriever:

    def __init__(self, testing_mode: bool = False):
        self.testing_mode = testing_mode

测试示例:

def test_singletone(self):
    FilesRetriever(testing_mode=True)
    mode = FilesRetriever().testing_mode
    print("mode 1:" + str(mode))
    mode = FilesRetriever().testing_mode
    print("mode 2:" + str(mode))
    count_before = gc.get_count()
    gc.collect()
    count_after = gc.get_count()
    mode = FilesRetriever().testing_mode
    print("mode 3:" + str(mode))
    print("count_before:" + str(count_before))
    print("count_after:" + str(count_after))   

测试输出:

mode 1:True
mode 2:True
mode 3:True
count_before:(306, 10, 5)
count_after:(0, 0, 0)

我希望在垃圾收集器自动运行或在我的测试中运行它之后,_SingletonWrapper 的实例(装饰器实现中的类)将被删除,因为没有任何东西指向它。然后 "print("mode 3:" + str(mode))" 的值将为 False,因为这是默认值(并且重新创建了实例)

【问题讨论】:

标签: python memory garbage-collection


【解决方案1】:

所以代码和垃圾收集按预期工作。查看您所指的单例装饰器的代码。 decorator

仅仅因为您调用 gc.collect() 而您的代码没有在某处保存引用并不意味着其他代码没有。

它在装饰器中创建一个实例,然后将该实例存储在装饰器中的一个变量中。因此,即使您收集的代码相对于您的代码。他们的代码仍然持有对该实例的引用,因此不会被收集。

这是单例的预期行为,因为这是它的全部目的。是将实例存储在可以检索和使用的某个地方,而不是每次都创建一个新实例。因此,除非您需要替换该实例,否则您不希望该实例被丢弃。

回答您的评论

  1. 不,您没有将实例发送到_SingletonWrapper。当您编写FileRetriever() 时,您实际上正在调用_SingletonWrapper 实例的__call__ 方法。当您使用 @singleton() 返回一个实例而不是类对象时。

  2. 同样,在您的代码中,您没有将其存储在任何地方并不意味着它没有存储在其他地方。当您定义一个类时,您在某种意义上所做的是在模块的全局范围内,它正在创建一个包含该类定义的变量。所以在你在全局范围内的代码中,它有这样的东西,

FileRetriever = (class:
    def __init__(self):
        blahblahblah

所以现在你的类定义存储在一个变量调用FileRetriever中。

所以现在你正在使用一个装饰器,所以现在它看起来像这样基于单个装饰器中的代码。

FileRetriever = _SingletonWrapper(class: blahblah)

现在你的类被包装并存储在变量FileRetriever 中。 现在您在运行FileRetriever() 时调用_SingletonWrapper.__call__()。 因为__call__ 是一个实例方法。它可以包含对您的原始类和您声明的类的实例的引用,因此即使您删除了对该类的所有引用,此代码仍会保留该引用。

如果您真的想删除所有对您的单身人士的引用,我不确定您为什么要这样做。您需要删除对包装器的所有引用以及您的班级。所以像FileRetriever = None 这样的东西可能会导致 gc 收集它。但是你会在这个过程中失去你原来的类定义。

【讨论】:

  • 谢谢,装饰器返回类 _SingletonWrapper,我同意在该类中保存我的类的实例,但在我的测试代码中,我得到了 _SingletonWrapper 实例,我没有将它存储在任何变量,所以 gc.collect() 是否应该删除它,然后还有我保存在 self._instance 中的我的 lass 的实例?
  • 我编辑了我的答案,因为有很多解释。请查看我的编辑。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-21
相关资源
最近更新 更多