Search code examples
pythonconstructorself

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


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.


Solution

  • 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.