correctly override __new__ in python3

喜欢而已 提交于 2019-12-23 03:01:46

问题


So I am trying override __new__ and let it exist as a factory to create derived instances. After reading a bit on SO, I am under the impression that I should be calling __new__ on the derived instance as well.

BaseThing

class BaseThing:
    def __init(self, name, **kwargs):
        self.name = name

    # methods to be derived

ThingFactory

class Thing(BaseThing):
    def __new__(cls, name, **kwargs):
        if name == 'A':
           return A.__new__(name, **kwargs)
        if name == 'B':
           return B.__new__(name, **kwargs)        

    def __init__(self, *args, **kwargs):
        super().__init__(name, **kwargs)

   # methods to be implemented by concrete class (same as those in base)

A

class A(BaseThing):
    def __init__(self, name, **kwargs):
       super().__init__(name, **kwargs)

B

class B(BaseThing):
    def __init__(self, name, **kwargs):
       super().__init__(name, **kwargs)

what I am expecting was that it'd just work.

>>> a = Thing('A')

gives me TypeError: object.__new__(X): X is not a type object (str)

I am bit confused by this; when I just return a concrete instance of derived classes, it just worked. i.e.

def __new__(cls, name, **kwargs):
        if name == 'A':
           return A(name)
        if name == 'B':
           return B(name)

I however don't think this it the correct way of returning in __new__; it may duplicate the calls to __init__.

when I am checking signatures of __new__ in object it seems be this one:

@staticmethod # known case of __new__
def __new__(cls, *more): # known special case of object.__new__
    """ Create and return a new object.  See help(type) for accurate signature. """
    pass

I didn't expect this was the one; I'd expect it came with args and kwargs as well. I must have done something wrong here.

it seems to me that I need to inherit object directly in my base but could anyone explain the correct way of doing it?


回答1:


You're calling __new__ wrong. If you want your __new__ to create an instance of a subclass, you don't call the subclass's __new__; you call the superclass's __new__ as usual, but pass it the subclass as the first argument:

instance = super().__new__(A)

I can't guarantee that this will be enough to fix your problems, since the code you've posted wouldn't reproduce the error you claim; it has other problems that would have caused a different error first (infinite recursion). Particularly, if A and B don't really descend from Thing, that needs different handling.



来源:https://stackoverflow.com/questions/47602278/correctly-override-new-in-python3

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!