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__
。
我正在 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
.
如果调用构造函数,它将创建一个新对象。最简单的事情就是按照 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__
。