Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/295.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/meteor/3.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 允许deafult构造函数接受一个实例并返回它而不受约束_Python_Python 3.x_Default Constructor - Fatal编程技术网

Python 允许deafult构造函数接受一个实例并返回它而不受约束

Python 允许deafult构造函数接受一个实例并返回它而不受约束,python,python-3.x,default-constructor,Python,Python 3.x,Default Constructor,我想让我的类构造函数接受这个类的一个实例,在这种情况下,返回这个相同的实例,而不是创建一个新的对象。就像tuple所做的那样: >>> t = (1, 2, 3) >>> tuple(t) is t True 我想我需要为此重写\uuuu new\uuu方法,并在\uuuu init\uuu方法中处理这个特殊情况。这有什么食谱吗 当给构造函数一个类实例,它将返回不变时,我宁愿完全跳过\uuuuu init\uuuu,但我看不到任何方法。我还对cls在supe

我想让我的类构造函数接受这个类的一个实例,在这种情况下,返回这个相同的实例,而不是创建一个新的对象。就像
tuple
所做的那样:

>>> t = (1, 2, 3)
>>> tuple(t) is t
True
我想我需要为此重写
\uuuu new\uuu
方法,并在
\uuuu init\uuu
方法中处理这个特殊情况。这有什么食谱吗

当给构造函数一个类实例,它将返回不变时,我宁愿完全跳过
\uuuuu init\uuuu
,但我看不到任何方法。我还对
cls
super
中的三重用法表示怀疑:

class C:
    @staticmethod
    def __new__(cls, x=None):
        if isinstance(x, cls):
            return x
        else:
            return super(cls, cls).__new__(cls)

    def __init__(self, x=None):
        if x is self: return  # Can I just skip __init__ instead?
        self.x = x
(我知道没有参数的
super()
,但我不喜欢。)

在学习了更多关于
super
和Python中的MRO的知识之后,我发现这段代码并不好。例如,子类化
C
会导致

>>> class D(C): pass
>>> d = D(1)
......
RecursionError: maximum recursion depth exceeded while calling a Python object
我非常害怕
super()
没有从(词汇或动态?)上下文中神奇地提取参数的参数,因此我决定添加一个“回调”来完成类定义,而不是使用它:

class C2:
    @classmethod
    def finalise(this_cls_yes_this_one):
        @staticmethod
        def __new__(cls, x=None):
            if isinstance(x, cls):
                return x
            else:
                return super(this_cls_yes_this_one, cls).__new__(cls)

        this_cls_yes_this_one.__new__ = __new__

        del this_cls_yes_this_one.finalise

    def __init__(self, x=None):
        if x is self: return
        self.x = x

C2.finalise()

您可以使用元类。每当调用实例时,Metacals的
\uuuuuuuuu init\uuuuuuuuuuuuuuuuuuuuu
方法中都会调用
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。您可以通过重写元类调用函数来处理这两个问题

class MyMetaClass(type):

    def __call__(cls, obj, *args, **kwargs):
        if (isinstance(obj, cls)):
            return obj
        else:
            self = cls.__new__(cls, obj, *args, **kwargs)
            cls.__init__(self, obj, *args, **kwargs)
            return self
            # Note: In order to be sure that you don't miss anything
            # It's better to do super().__call__(obj, *args, **kwargs) here

class A(metaclass=MyMetaClass):
    def __init__(self, obj, *args, **kwargs):
        self.val = obj
演示:


MyMetaClass的
else
子句是否可以是:
else:returnsuper()
?是否可以链接到Python的文档,以确认类的
\uuuu-cal\uuuuu
中没有其他需要处理的内容?@Alexey我不确定,但为了让Rob放心,你应该使用
super()
@Kasramvd-抱歉,我没有仔细阅读这个问题。没关系。考虑到,对于可变值,这可能会产生令人惊讶的结果:<代码> A1. Val= 1;a2=A(a1);a2.val=2;打印(a1.val)类的用户可能期望构造函数为可变对象生成一个副本。这实际上是期望的结果。正如我所说,我希望构造函数返回相同的对象。此外,我的类实例并不是用于变异的。
a = A(10)
b = A(a)
c = A(40)
print(b is a)
print(a.val)
print(b.val)
print(c is a)
print(c.val)

# out:
True
10
10
False
40