Подтвердить что ты не робот

Почему __new__ в классах нового стиля Python метод класса?

В Changelog для Python 2.2 (где были введены классы нового стиля) говорится о функции __new__:

__new__ - это статический метод, а не метод класса. Первоначально я думал, что это должен быть метод класса, и поэтому я добавил примитив classmethod. К сожалению, с помощью методов класса, upcalls не работают правильно в этом случае, поэтому я должен был сделать его статическим методом с явным классом в качестве его первого аргумента.

Однако я не могу придумать, почему методы класса не будут работать для этой цели, и это, безусловно, будет выглядеть лучше. Почему в конце концов метод __new__ оказался в качестве метода класса? О чем говорит Гвидо, когда он говорит, что "восстания в этом случае не работают"?

4b9b3361

Ответ 1

__new__ статический метод позволяет использовать прецедент при создании в нем экземпляра подкласса:

return super(<currentclass>, cls).__new__(subcls, *args, **kwargs)

Если new - метод класса, то указанное выше записывается как:

return super(<currentclass>, cls).new(*args, **kwargs)

и нет места для размещения subcls.

Я действительно не вижу, когда это было бы правильным использованием __new__. Может быть, я этого не вижу, но мне кажется, что это полностью патологическое его использование (и нужно сказать, что если вы все еще этого хотите, тогда вы можете получить доступ к нему с помощью object.__new__.__func__). По крайней мере, мне очень трудно представить, что это было бы причиной того, что Гвидо изменил бы __new__ как метод класса на статический метод.

Более распространенным случаем является вызов parent __new__ без использования super(). Вам нужно место, чтобы передать cls явно в этом случае:

class Base(object):
    @classmethod
    def new(cls):
        print("Base.new(%r)" % (cls,))
        return cls()

class UseSuper(Base):
    @classmethod
    def new(cls):
        print("UseSuper.new(%r)" % (cls,))
        return super(UseSuper, cls).new() # passes cls as the first arg

class NoSuper(Base):
    @classmethod
    def new(cls):
        print("NoSuper.new(%r)" % (cls,))
        return Base.new()  # passes Base as the first arg

class UseFunc(Base):
    @classmethod
    def new(cls):
        print("UseFunc.new(%r)" % (cls,))
        return Base.new.im_func(cls)  # or `.__func__(cls)`. # passes cls as the first arg

print(UseSuper.new())
print('-'*60)
print(NoSuper.new())
print('-'*60)
print(UseFunc.new())