Python代理模式 - 如何避免循环引用? [英] Python Delegate Pattern - How to avoid circular reference?

查看:202
本文介绍了Python代理模式 - 如何避免循环引用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我会问,如果在Python中使用Delegate Pattern会导致循环引用,如果是这样,执行它的最好方法是确保对象及其代理将被垃圾回收?



在Objective C中,通过使用对代理的弱引用来避免上述问题。在C ++中,我们不会在委托上调用delete。我在这里找到了一个指向Python弱参考模块的链接: http://docs.python.org/ library / weakref.html 。似乎一个合理的做法可能是创建一个弱引用来引用使用这个模块的实例变量,但我不确定。



我已经google了问题,并没有找到答案,我想知道这是否是Python中的一个问题,或者是否有一个常见的解决方案(不需要weakref模块),我不知道?此外,我在询问之前搜索stackoverflow,但是我发现问题是处理循环导入或代理模式,而不是Python特有的和循环引用的问题。



感谢提前收到任何回复。



下面列出了玩具示例的一些代码,以帮助说明我的问题。我以这种方式实现了代码,它的工作原理,但我不知道内存是否在最后垃圾回收。

  A类(对象):
def __init __(self):
self.delegate =无

#跟踪执行某些任务的状态的其他一些实例变量。

def doSomething(self):
如果self.delegate不是None:
self.delegate.doSomething()
else:
print('无法执行任务,因为委托未设置。')

#其他方法未显示。

class B(object):
def __init __(self):
self.a = A()#需要保持对象a不被收集,以保留其状态信息。
self.a.delegate = self#这是一个循环引用吗?如何修复,以便A和B最终会被垃圾收集?

def doSomething(self):
print('B doing something')

#其他方法未显示。

编辑



在阅读了一些答复后,我决定澄清我的问题。我明白Python有垃圾回收。我不知道是否在循环引用对象上执行垃圾收集。我的后顾之忧源于Python的文档:


CPython实现细节:CPython目前使用
引用计数方案(可选)延迟检测
循环链接的垃圾,一旦
变得不可达即可收集大多数对象,但是不能保证收集垃圾
包含循环引用
。有关控制循环垃圾收集的信息,请参阅gc模块
的文档。其他
实现方式不同,CPython可能会改变。不要依赖
立即敲定对象,因为它们变得无法访问(例如:
总是关闭文件)。


原始形式的段落可以在这里找到: http://docs.python.org/reference /datamodel.html 粗体设置是我的。



以下文章对循环引用对象的问题提供了更清楚的解释,以及为什么会阻止垃圾回收在这些对象上(至少在典型的设置中): http://www.electricmonk.nl/log/2008/07/07/python-destructor-and-garbage-collection-notes/


$ b $此外,我刚刚遇到了Alex Martellli对Python用户是否应该担心循环引用的回复:我应该担心Python中的循环引用吗?从他的答案中,我收集到即使循环引用的对象最终将被垃圾回收,但是会有开销。是否重要取决于程序。



此外,他提到使用Python的weakref模块,但没有明确说明如何。



因此,我想添加以下问题来澄清一些未解决的问题:


  1. 文档说,对于循环
    引用的对象,不能保证加载集合。但是从答复看来,这不是
    的情况。所以我误解了段落,还是有进一步的
    的细节,我错过了?

  2. 我想使用弱参考,如亚历克斯的回复和我的
    问题,会完全避免这个问题的开销吗?

再次感谢您的回复。

解决方案

Python已经做垃圾回收了。如果您在C中编写自己的容器类型作为扩展名,那么只需要做一些特别的事情。



演示:运行此程序并观察内存使用攀登

  class C(object):
pass

def circular():
for x in range(10 ** 4):
for y in range(10 ** 4):
a = C()
b = C()
ax = b
bx = a

循环()

脚注:以下功能无效,删除。

 code> def setDelegate(self,delegate):
self.delegate = delegate

而不是调用 x.setDelegate(y),您可以使用 x.delegate = y 。您可以在Python中重载成员访问,因此编写方法没有任何好处。


I would to ask if using the Delegate Pattern in Python would lead to circular references and if so, what would be the best way to implement it to ensure the object and its delegate will be garbage collected?

In Objective C, the above problem is avoided by using a weak reference to the delegate. In C++, we don't call delete on the delegate. I've found a link to Python's weak reference module here: http://docs.python.org/library/weakref.html. It seems like a plausible approach might be to create a weak reference to refer to the instance variable using this module but I'm not sure.

As I've googled this question and was not able to find answers to it, I'm wondering whether this is even a problem in Python or if there is a common solution (without the need for the weakref module) that I'm unaware of? Also, I did search stackoverflow before asking but the questions I found either deal with circular imports or delegate pattern in general and not specific to Python and the problem of circular references.

Thanks in advance for any replies.

Listed below is some code for a toy example to help illustrate my question. I've implemented code in this way and it works but I'm not sure whether memory is garbage collected at the end.

class A(object):
    def __init__(self):
        self.delegate = None

        # Some other instance variables that keep track of state for performing some tasks.

    def doSomething(self):
        if self.delegate is not None:
            self.delegate.doSomething()
        else:
            print('Cannot perform task because delegate is not set.')

    # Other methods not shown.

class B(object):
    def __init__(self):
        self.a = A() # Need to keep object 'a' from garbage collected so as to preserve its state information.
        self.a.delegate = self  # Is this a circular reference? How to 'fix' it so that A and B will eventually be garbage collected?

    def doSomething(self):
        print('B doing something')

    # Other methods not shown.

EDIT:

After reading some of the replies, I decided to clarify my question. I understand that Python has garbage collection. What I wasn't sure was whether it will perform garbage collection on circular referenced objects. My worries stems from the following passage from Python's doc:

CPython implementation detail: CPython currently uses a reference-counting scheme with (optional) delayed detection of cyclically linked garbage, which collects most objects as soon as they become unreachable, but is not guaranteed to collect garbage containing circular references. See the documentation of the gc module for information on controlling the collection of cyclic garbage. Other implementations act differently and CPython may change. Do not depend on immediate finalization of objects when they become unreachable (ex: always close files).

The passage in its original form can be found here: http://docs.python.org/reference/datamodel.html The bold setting is mine.

The following post provides a clearer explanation on the problem of circular referenced objects and why it would prevent garbage collection on those objects (at least in a typical setting): http://www.electricmonk.nl/log/2008/07/07/python-destructor-and-garbage-collection-notes/.

Further, I just came across Alex Martellli's reply to the following question on whether Python users should worry about circular reference: Should I worry about circular references in Python? From his answer, I gather that even though circular referenced objects will eventually be garbage collected BUT there would be overheads. Whether it is significant depends on the program.

Further, he mentioned to use Python's weakref module but did not explicitly say how.

Hence, I would like to add the following questions to clarify some unresolved issues:

  1. The docs say garbaged collection is not guaranteed for circular referenced objects. But from the replies it appears that is not the case. So have I misunderstood the passage or are there further details that I've missed?
  2. I suppose using a weak reference, as stated in Alex's reply and my question, would avoid the overhead the problem entirely?

Again thanks for the replies.

解决方案

Python already does garbage collection. You only need to do something special if you write your own container types in C, as extensions.

Demo: Run this program and watch the memory usage not climb.

class C(object):
    pass

def circular():
    for x in range(10**4):
        for y in range(10**4):
            a = C()
            b = C()
            a.x = b
            b.x = a

circular()

Footnote: The following function doesn't do anything, delete it.

def setDelegate(self, delegate):
    self.delegate = delegate

Instead of calling x.setDelegate(y), you can use x.delegate = y. You can overload member access in Python, so there's no benefit to writing a method.

这篇关于Python代理模式 - 如何避免循环引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆