Reputation: 665
I am making a constructor in Python. When called with an existing object as its input, it should set the "new" object to that same object. Here is a 10 line demonstration:
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
I want the object A(a)
constructed from the existing object a
to be a
. Why is it not? To be clear, I want A(a)
to reference the same object as a
, NOT a copy.
Upvotes: 4
Views: 7580
Reputation: 881675
self
, like any other argument, is among the local variables of a function or method. Assignment to the bare name of a local variable never affects anything outside of that function or method, it just locally rebinds that name.
As a comment rightly suggests, it's unclear why you wouldn't just do
b = a
Assuming you have a sound reason, what you need to override is not __init__
, but rather __new__
(then take some precaution in __init__
to avoid double initialization). It's not an obvious course so I'll wait for you to explain what exactly you're trying to accomplish.
Added: having clarified the need I agree with the OP that a factory function (ideally, I suggest, as a class method) is better -- and clearer than __new__
, which would work (it is a class method after all) but in a less-sharply-clear way.
So, I would code as follows:
class A(object):
@classmethod
def make(cls, value):
if isinstance(value, cls): return value
return cls(value)
def __init__(self, value):
self.attribute = value
Now,
a = A.make(1)
b = A.make(a)
accomplishes the OP's desires, polymorphically over the type of argument passed to A.make
.
Upvotes: 9
Reputation: 122032
The only way to make it work exactly as you have it is to implement __new__
, the constructor, rather than __init__
, the initialiser (the behaviour can get rather complex if both are implemented). It would also be wise to implement __eq__
for equality comparison, although this will fall back to identity comparison. For example:
>>> 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
You should have a look at the data model documentation, which explains the various "magic methods" available and what they do. See e.g. __new__
.
Upvotes: 3
Reputation: 641
If you call a constructor, it's going to create a new object. The simplest thing is to do what hacatu suggested and simply assign b to a's value. If not, perhaps you could have an if statement checking if the value passed in is equal to the object you want referenced and if it is, simply return that item before ever calling the constructor. I haven't tested so I'm not sure if it'd work.
Upvotes: 0
Reputation: 56654
__init__
is an initializer, not a constructor. You would have to mess around with __new__
to do what you want, and it's probably not a good idea to go there.
Try
a = b = A(1)
instead.
Upvotes: 2