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

后端 未结 4 894
日久生厌
日久生厌 2020-12-18 09:58

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 demonstratio

相关标签:
4条回答
  • 2020-12-18 10:17

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

    0 讨论(0)
  • 2020-12-18 10:23

    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.

    0 讨论(0)
  • 2020-12-18 10:31

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

    0 讨论(0)
  • 2020-12-18 10:39

    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.

    0 讨论(0)
提交回复
热议问题