Dans Python 3, lors de la définition d'une sous-classe, pourquoi avez-vous besoin d'utiliser Un exemple: Quand j'ai comparé ces fonctions, je suis devenu plus confus: p > Alors, quelles sont les différences entre cls
comme premier argument de __new__
, mais pas d'utiliser self code> comme premier argument de
__init__
? >>> cls = object
>>> self = cls()
>>> cls.__new__ is self.__new__
True
>>> cls.__init__ is self.__init__
False
>>> self.__init__()
>>> cls.__init__()
Traceback (most recent call last): ...
class MyClass(object):
def __new__(cls, *args, **kwargs):
return super(MyClass, cls).__new__(cls, *args, **kwargs) # with `cls`
def __init__(self, *args, **kwargs):
return super(MyClass, self).__init__(*args, **kwargs) # without `self`
__new__
et __init__
derrière ces résultats? Quelles méthodes sont liées et lesquelles sont gratuites? Pourquoi pouvez-vous appeler self .__ init __ ()
mais pas cls .__ init __ ()
? cls .__ init__
est-il une méthode définie dans cls
lui-même ou dans sa métaclasse?
3 Réponses :
cls
représente la classe elle-même, tandis que self
représente l'objet lui-même. Ce ne sont que des conventions.
La méthode __new__
est appelée avant la création de l'objet, en fait, __new__
doit créer l'objet et le renvoyer. Par conséquent, il a besoin d'une classe pour créer un objet. Après cela, le __init__
est appelé pour initialiser l'objet, il a donc besoin de l'objet comme premier argument.
Par exemple:
cls.__init__(self)
__new__
est une méthode statique, donc la classe et l'instance partagent la même méthode __new__
. __init__
est la méthode d'instance. Si vous voulez l'appeler via la classe, vous devez passer l'instance comme premier argument explicitement.
class MyClass: def __new__(cls, *args, **kwargs): # cls == MyClass return super().__new__(cls, *args, **kwargs) # cls here is because __new__ is staticmethods so you have to pass the cls explicitly # You can't use cls() here because it will call this methods again and again # causing recusion error def __init__(self, *args, **kwargs): # Here self is the instance(or object) of MyClass # So you can initialize it by self.xxx self.xxx = 'xxx'
Tout en Python est objet, y compris la classe elle-même. Donc, pour la classe, il a ses propres __new__
et __init__
qui sont utilisés par la métaclasse
pour créer la classe et initialiser la classe .
Ce sont des métaprogrammations de Python, je suggère de lire le neuvième chapitre de Python Cookbook.
La plus grande partie de l'image qui vous manque probablement est que __new__
est une méthode statique, special-cased pour en être un même si vous n'utilisez pas le décorateur @staticmethod
.
Lors de l'appel d'une méthode via super ()
, super ()
effectue le même type de liaison d'argument qui serait effectuée normalement pour ce type de méthode (en utilisant le a href = "https://docs.python.org/3/reference/datamodel.html#implementing-descriptors" rel = "nofollow noreferrer"> protocole de descripteur ). Pour une méthode statique comme __new__
, cela signifie qu'aucun argument n'est automatiquement lié, donc cls
doit être passé explicitement. Pour une méthode d'instance comme __init__
, cela signifie que self
est lié automatiquement, c'est pourquoi vous n'avez pas à passer self
à super () .__ init__
.
Je me demandais pourquoi __new__
est devenu une méthode statique mais pas une méthode de classe, alors que vous devez encore passer un argument de classe.
@Cyker: Avec une méthode statique, vous pouvez faire des choses comme object .__ new __ (peu importe)
. Il serait beaucoup plus difficile de reproduire cette fonctionnalité avec une méthode de classe.
Mais pourquoi object .__ nouveau __ (peu importe)
alors que vous pouvez n'importe quoi .__ nouveau __ ()
?
@Cyker: Parce que vous voulez utiliser la méthode __new__
de object
au lieu de celle de Whatever
.
Alors pourquoi ne voulez-vous pas utiliser la méthode __init__
de object
au lieu de celle de Whatever
?
@Cyker: object .__ new __ (peu importe)
n'appelle aucune méthode __init__
du tout. Si vous voulez appeler object .__ init__
, vous pouvez l'appeler manuellement sur l'objet résultant, mais object .__ init__
n'effectue aucune initialisation. Dans tous les cas, la raison habituelle d'appeler une superclasse __new__
manuellement en dehors d'une sous-classe __new__
est que la sous-classe __new__
refuserait de créer l'objet .
L'objectif principal de __new__
consiste à allouer une nouvelle instance de la classe, tandis que __ init__
est de configurer une instance existante.
D'après la documentation:
__new __ ()
est une méthode statique (avec une casse spéciale, vous n'avez donc pas besoin de la déclarer comme telle)
__init__
d'autre part, est une méthode d'instance appropriée. Il peut être appelé plusieurs fois sur la même instance, au fait.
Cela devrait suffire à expliquer votre session de terminal:
>>> cls.__init__(self)
Vous venez d'appeler object .__ call__
, ce qui fait essentiellement
>>> cls.__init__()
Notez que la valeur de retour de __new__
n'est pas obligatoirement une instance de la classe à laquelle il appartient, mais __init__
n'est appelé que si c'est le cas. Dans votre cas, c'est le cas.
>>> self.__init__()
__new__
est une méthode statique, donc tenter de la lier à l'instance ne fait rien: cela reste une classe méthode. C'est la même raison pour laquelle vous devez passer cls
explicitement lors de l'appel de super () .__ new__
: c'est la même fonction gratuite, indépendante de la classe ou de l'instance. P >
>>> cls.__init__ is self.__init__ False
Non seulement ce ne sont pas la même chose, mais leurs types sont différents. cls .__ init__
est une fonction régulière. self .__ init__
est une méthode liée qui n'a pas le premier paramètre de cls.__init__
.
>>> cls.__new__ is self.__new__ True
Cela a déjà été appelé, mais pour objet
, c'est un no-op que vous pouvez appeler autant de fois que vous le souhaitez. Notez que le premier paramètre n'est pas passé, car il s'agit d'une méthode liée.
self = cls.__new__() if isinstance(self, cls): cls.__init__(self) return self
Ceci appelle la fonction brute __init__
, qui nécessite que le paramètre self
soit passé. Comme vous ne le faites pas, il déclenche. Essayez plutôt ceci:
>>> cls = object >>> self = cls()
Si self .__ init __ ()
invoque la méthode __init__
définie dans type (self)
, pourquoi cls .__ init __ () < / code> invoquer la méthode
__init__
définie dans type (cls)
? Un objet de classe n'est-il pas aussi un objet?
@Cyker. Point intéressant. Étant donné qu'une méthode est un descripteur sans données, tout attribut de l'instance portant le même nom le remplacera. Si vous faites self .__ init__ = some_other_function
, vous verrez que l'autre fonction est appelée lorsque vous faites self .__ init__
. Si vous n'aviez pas défini __init__
dans la classe, il utiliserait celui de la métaclasse. Il est intéressant de noter que vous ne pouvez pas remplacer les méthodes dunder comme celle-ci au niveau de l'instance car les méthodes dunder sont toujours appelées comme type (self) .__ dunder __ (self, ...)
lorsqu'elles sont utilisées comme opérateurs.
Je pense que si je ne définis pas __init__
dans la classe, il utiliserait celui de sa superclasse. Seulement si la superclasse n'a pas cette méthode, elle utiliserait celle de sa métaclasse. Mais object .__ init__
existe toujours donc celui de sa métaclasse ne sera pas utilisé.
@Cyker correct. Object n'a pas de superclasse, ce qui simplifie ce cas.
Copie possible de Que peut `__init__` faire que` __new__` ne peut pas? A >
@TheExorcist: Pas un doublon. Cette question est complètement différente.
Je vois aussi que vous utilisez new et init de la même manière, alors comment pouvez-vous voir la différence,. Ne l'utilisez pas pour initialiser plutôt changer la manière d'initaliser.
Étant donné que ce n'est pas un sujet trivial et que vous avez fait des efforts pour jouer avec et comprendre ce qui se passe, +1