Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在python中使用继承(如swift或objective-c)实现委派安全吗?_Python_Delegates - Fatal编程技术网

在python中使用继承(如swift或objective-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

来自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 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