Python 在构造函数中对自身的赋值不会使对象相同

Python assignment to self in constructor does not make object the same

我正在 Python 中创建构造函数。当使用现有对象作为其输入进行调用时,它应该将 "new" 对象设置为同一对象。这是一个 10 行的演示:

class A:
    def __init__(self, value):
        if isinstance(value, A):
            self = value
        else:
            self.attribute = value
a = A(1)
b = A(a)#a and b should be references to the same object
print("b is a", b is a)#this should be true: the identities should be the same
print("b == a", b == a)#this should be true: the values should be the same

我希望从现有对象 a 构造的对象 A(a) 成为 a。为什么不是呢?明确地说,我希望 A(a) 引用与 a 相同的对象,而不是副本。

__init__ 是初始化程序,而不是构造函数。你将不得不与 __new__ 混在一起做你想做的事,去那里可能不是一个好主意。

尝试

a = b = A(1)

相反。

self 与任何其他参数一样,属于函数或方法的局部变量。分配给局部变量的裸名永远不会影响该函数或方法之外的任何东西,它只是在本地重新绑定该名称。

正如一条评论所暗示的那样,不清楚你为什么不这样做

b = a

假设您有充分的理由,您需要覆盖的不是 __init__,而是 __new__(然后在 __init__ 中采取一些预防措施以避免双重初始化)。这不是一门显而易见的课程,所以我会等你解释你到底想完成什么。

补充:澄清了我同意 OP 的需要,即工厂函数(理想情况下,我建议,作为 class 方法)比 __new__ 更好——更清晰工作(它 毕竟是一个 class 方法)但是以一种不太清晰的方式。

所以,我将编码如下:

class A(object):

    @classmethod
    def make(cls, value):
        if isinstance(value, cls): return value
        return cls(value)

    def __init__(self, value):
        self.attribute = value

现在,

a = A.make(1)
b = A.make(a)

通过传递给 A.make.

的参数类型多态地实现了 OP 的愿望

如果调用构造函数,它将创建一个新对象。最简单的事情就是按照 hacatu 的建议去做,然后简单地将 b 分配给 a 的值。如果不是,也许您可​​以使用 if 语句检查传入的值是否等于您要引用的对象,如果是,则在调用构造函数之前简单地 return 该项目。我还没有测试过,所以我不确定它是否有效。

使它完全工作的唯一方法是实现__new__构造函数,而不是 __init__,初始化器(如果两者都实现,行为会变得相当复杂)。实现 __eq__ 进行相等比较也是明智的,尽管这将回退到身份比较。例如:

>>> class A(object):
    def __new__(cls, value):
        if isinstance(value, cls):
            return value
        inst = super(A, cls).__new__(cls)
        inst.attribute = value
        return inst
    def __eq__(self, other):
        return self.attribute == other.attribute


>>> a = A(1)
>>> b = A(a)
>>> a is b
True
>>> a == b
True
>>> a == A(1)
True  # also equal to other instance with same attribute value

你应该看看data model documentation, which explains the various "magic methods" available and what they do. See e.g. __new__