27 votes

Pourquoi __new__ dans les classes de style ancien en Python n'est-il pas une méthode de classe?

Le journal des modifications de Python 2.2 (où les nouvelles classes ont été introduites) dit ce qui suit à propos de la fonction __new__:

__new__ est une méthode statique, pas une méthode de classe. J'ai initialement pensé qu'elle devait être une méthode de classe, et c'est pourquoi j'ai ajouté le primitive classmethod. Malheureusement, avec les méthodes de classe, les upcalls ne fonctionnent pas correctement dans ce cas, donc j'ai dû en faire une méthode statique avec une classe explicite comme premier argument.

Cependant, je ne peux pas comprendre pourquoi les méthodes de classe ne fonctionneraient pas à cette fin, et cela aurait certainement meilleure allure. Pourquoi __new__ n'a-t-elle finalement pas été une méthode de classe? À quoi Guido fait-il référence lorsqu'il dit que "les upcalls ne fonctionnent pas correctement dans ce cas"?

16voto

J.F. Sebastian Points 102961

__new__ étant une méthode statique permet un cas d'utilisation lorsque vous créez une instance d'une sous-classe en son sein :

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

Si new est une méthode de classe, alors ce qui précède s'écrit comme suit :

return super(, cls).new(*args, **kwargs)

et il n'y a pas d'endroit pour mettre subcls.

Je ne vois pas vraiment quand cela serait un usage approprié de __new__, cependant. Peut-être que je ne le vois pas, mais cela me semble tout simplement être un usage complètement pathologique de celui-ci (et il convient de dire que si vous le voulez vraiment toujours, alors vous pourriez y accéder avec object.__new__.__func__). En tout cas, je trouve très difficile d'imaginer que cela aurait été la raison pour laquelle Guido a changé __new__ d'une méthode de classe en une méthode statique.

Un cas plus courant serait d'appeler le __new__ parent sans utiliser super(). Dans ce cas, vous avez besoin d'un endroit pour passer cls explicitement :

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() # passe cls comme premier argument

class NoSuper(Base):
    @classmethod
    def new(cls):
        print("NoSuper.new(%r)" % (cls,))
        return Base.new()  # passe Base comme premier argument

class UseFunc(Base):
    @classmethod
    def new(cls):
        print("UseFunc.new(%r)" % (cls,))
        return Base.new.im_func(cls)  # ou `.__func__(cls)`. # passe cls comme premier argument

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X