在python中使用继承(如swift或objective-c)实现委派安全吗?
来自Objective-C和Swift,我在Python中实现了以下模式,以便在Python中使用基于协议的委托,就像我在Swift或Obj-C中所做的那样:在python中使用继承(如swift或objective-c)实现委派安全吗?,python,delegates,Python,Delegates,来自Objective-C和Swift,我在Python中实现了以下模式,以便在Python中使用基于协议的委托,就像我在Swift或Obj-C中所做的那样: class DataReceiverDelegate: def data_receiver_did_receive_data(self, data): pass def data_receiver_did_update_settings(self): pass class DataRe
class DataReceiverDelegate:
def data_receiver_did_receive_data(self, data):
pass
def data_receiver_did_update_settings(self):
pass
class DataReceiver
def __init__(self, delegate = None):
self.delegate = delegate
def received_data(self, data):
self.delegate.data_receiver_did_receive_data(data)
我就是这样使用它的:
应该作为委托的类只是从DataReceiverDelegate
类继承
class DataParser(object, DataReceiverDelegate):
def __init__(self):
self.data_receiver = DataReceiver(self)
# or -> self.data_receiver.delegate = self
def data_receiver_did_receive_data(self, data):
print data
这是没有问题的,非常类似于Swift,协议也是类(或结构,不太确定)
我担心在Python中实现这样的委托会导致奇怪的问题,或者是绝对不可能的。那么这样处理委托关系安全吗
由于我目前对Python中的内存处理没有任何线索,我不确定这是否会因为“强引用循环”而导致死锁。那么,有没有一种方法来定义“弱”类型
唯一的问题是,委托给(DataReceiver
在本例中)的类不知道什么类型的self.delegate
,因此编辑器中的代码完成不起作用
编辑:
这是一个简单的例子,只是为了展示我所追求的。在现实世界中,可以添加检查以确保委托不是
None
。与Swift中的“安全展开选项”非常相似。您所做的看起来很好。您甚至可以省略DataReceiverDelegate
类,因为只有在运行时才能找到方法,或者您可以将其作为抽象基类进行一些额外的安全性和静态分析
Python2.7可以在其垃圾收集中处理引用周期,尽管周期越少越好。如果你担心的话,你也可以查看弱引用
PyCharm中的类型提示可以指示
self.delegate
的类型。您所做的看起来很好。您甚至可以省略DataReceiverDelegate
类,因为只有在运行时才能找到方法,或者您可以将其作为抽象基类进行一些额外的安全性和静态分析
Python2.7可以在其垃圾收集中处理引用周期,尽管周期越少越好。如果你担心的话,你也可以查看弱引用
PyCharm中的类型提示可以指示
self.delegate
的类型。我正在做完全相同的事情,因为我在swift库中看到了这些示例,我认为该模式可以真正帮助我。
目前,我还担心强引用中的内存泄漏。但是我看到python中的这些链接类型被称为循环引用:
。。。它创建一个类B的实例,该实例将自身传递给类A,然后类A设置对类B的引用并生成循环引用
我们这里的循环引用几乎相同
我并没有找到一个关于我们是否必须手动处理循环引用的明确解释,所以我决定提供一个实验
下面是我试图适合您的示例的实验(刚刚更改了类名:)
输出:
Line # Mem usage Increment Line Contents
================================================
74 64.0 MiB 64.0 MiB @profile
75 def monitor():
76 3557.1 MiB 0.0 MiB for _ in range(60):
77 3557.1 MiB 128.0 MiB parser = DataParser()
78
79 3515.4 MiB 0.0 MiB print("monitoring at the last point")
Line # Mem usage Increment Line Contents
================================================
73 64.1 MiB 64.1 MiB @profile
74 def monitor():
75 192.1 MiB 0.0 MiB for _ in range(60):
76 192.1 MiB 128.0 MiB parser = DataParser()
77
78 192.1 MiB 0.0 MiB print("monitoring at the last point")
似乎经过60次迭代后,它消耗了大约3.5 GB的内存,无法摆脱这些强引用
之后,我们做了完全相同的事情,但使用weakref模块实现弱引用:
import weakref
...
class DataReceiver:
def __init__(self, delegate):
self.workload = " " * 128 * 1024 * 1024
self.delegate = weakref.ref(delegate) # only here is difference: delegate is weak reference
...
输出:
Line # Mem usage Increment Line Contents
================================================
74 64.0 MiB 64.0 MiB @profile
75 def monitor():
76 3557.1 MiB 0.0 MiB for _ in range(60):
77 3557.1 MiB 128.0 MiB parser = DataParser()
78
79 3515.4 MiB 0.0 MiB print("monitoring at the last point")
Line # Mem usage Increment Line Contents
================================================
73 64.1 MiB 64.1 MiB @profile
74 def monitor():
75 192.1 MiB 0.0 MiB for _ in range(60):
76 192.1 MiB 128.0 MiB parser = DataParser()
77
78 192.1 MiB 0.0 MiB print("monitoring at the last point")
现在看来,在每次迭代之后,垃圾收集器都能够在每次迭代之后删除本地实例,因为不再有强引用
同样重要的是:
您不再能够以这种方式调用方法:
receiver.delegate.method_name_bluh_bluh()
因为weakref.ref是一个可调用的类型,要获取引用的对象,需要调用ref属性:
receiver.delegate().method_name_bluh_bluh()
你可以这样做:
class DataReceiver:
def __init__(self, delegate):
self.workload = " " * 128 * 1024 * 1024
self._delegate = weakref.ref(delegate)
@property
def delegate(self):
return self._delegate()
现在你可以做:
receiver.delegate.method_name_bluh_bluh()
我正在做完全相同的事情,因为我在swift库中看到了这些示例,我认为该模式可以真正帮助我。 目前,我还担心强引用中的内存泄漏。但是我看到python中的这些链接类型被称为循环引用: 。。。它创建一个类B的实例,该实例将自身传递给类A,然后类A设置对类B的引用并生成循环引用 我们这里的循环引用几乎相同 我并没有找到一个关于我们是否必须手动处理循环引用的明确解释,所以我决定提供一个实验 下面是我试图适合您的示例的实验(刚刚更改了类名:) 输出:
Line # Mem usage Increment Line Contents
================================================
74 64.0 MiB 64.0 MiB @profile
75 def monitor():
76 3557.1 MiB 0.0 MiB for _ in range(60):
77 3557.1 MiB 128.0 MiB parser = DataParser()
78
79 3515.4 MiB 0.0 MiB print("monitoring at the last point")
Line # Mem usage Increment Line Contents
================================================
73 64.1 MiB 64.1 MiB @profile
74 def monitor():
75 192.1 MiB 0.0 MiB for _ in range(60):
76 192.1 MiB 128.0 MiB parser = DataParser()
77
78 192.1 MiB 0.0 MiB print("monitoring at the last point")
似乎经过60次迭代后,它消耗了大约3.5 GB的内存,无法摆脱这些强引用
之后,我们做了完全相同的事情,但使用weakref模块实现弱引用:
import weakref
...
class DataReceiver:
def __init__(self, delegate):
self.workload = " " * 128 * 1024 * 1024
self.delegate = weakref.ref(delegate) # only here is difference: delegate is weak reference
...
输出:
Line # Mem usage Increment Line Contents
================================================
74 64.0 MiB 64.0 MiB @profile
75 def monitor():
76 3557.1 MiB 0.0 MiB for _ in range(60):
77 3557.1 MiB 128.0 MiB parser = DataParser()
78
79 3515.4 MiB 0.0 MiB print("monitoring at the last point")
Line # Mem usage Increment Line Contents
================================================
73 64.1 MiB 64.1 MiB @profile
74 def monitor():
75 192.1 MiB 0.0 MiB for _ in range(60):
76 192.1 MiB 128.0 MiB parser = DataParser()
77
78 192.1 MiB 0.0 MiB print("monitoring at the last point")
现在看来,在每次迭代之后,垃圾收集器都能够在每次迭代之后删除本地实例,因为不再有强引用
同样重要的是:
您不再能够以这种方式调用方法:
receiver.delegate.method_name_bluh_bluh()
因为weakref.ref是一个可调用的类型,要获取引用的对象,需要调用ref属性:
receiver.delegate().method_name_bluh_bluh()
你可以这样做:
class DataReceiver:
def __init__(self, delegate):
self.workload = " " * 128 * 1024 * 1024
self._delegate = weakref.ref(delegate)
@property
def delegate(self):
return self._delegate()
现在你可以做:
receiver.delegate.method_name_bluh_bluh()
如果您不希望
委托
为无
,请不要将其设为默认值。这当然有道理!谢谢您使用的是哪一版本的python?上面的示例是在2.7中完成的,没有在较新版本中进行检查。在python 2中,您应该使用类DataReceiverDelegate(对象):
,而不是类DataReceiverDelegate:
,这将为您提供一个“旧式”类。然后您就可以使用类DataParser(DataReceiverDelegate):
。如果您不希望委托
为无
,请不要将其设为默认值。当然,这是有意义的!谢谢您使用的是什么版本的python?上面的示例是d