2
votes

Comment la mémoire est-elle mise de côté lorsqu'un objet est créé à partir d'une classe?

J'ai lu que __init__ ne crée pas l'objet (met de côté la mémoire).

Je n'ai pas trouvé qui s'occupe de la création d'objets. Comment cette création d'objet se produit-elle en interne?


0 commentaires

3 Réponses :


2
votes

Lorsque vous tapez quelque chose comme MyClass () en Python, le runtime Python appellera __new__ sur MyClass , ce qui devrait construire un objet; ceci sera suivi par l'appel de __init__ sur l'objet nouvellement construit. Ainsi, __new__ est appelé "constructeur", et __init__ un "initialiseur". Cette séquence est codée en dehors de Python (en C, dans le cas de CPython). Consultez la documentation Python pour en savoir plus sur __new__ < / a> et __init__ .


0 commentaires

2
votes

Vous recherchez probablement __new__ .

D'un point de vue Python, ce qui se passe est quelque chose comme ce qui suit, en supposant que vous ayez une classe, A , qui hérite directement de object:

  • Une méthode .__ new__ est appelée
  • object .__ new__ est appelé, avec cls=A
  • Une méthode .__ init__ est appelée, avec des arguments transférés depuis votre A.__new__

Example:

__new__ called with args ('arg',) and kwargs {'kwarg': 1}
__init__ called with args ('arg',) and kwargs {'kwarg': 1}
1

Output:

class A():

    def __new__(cls, *args, **kwargs):
        print(f'__new__ called with args {args} and kwargs {kwargs}')
        return super().__new__(cls)  # object.__new__

    def __init__(self, *args, **kwargs):
        print(f'__init__ called with args {args} and kwargs {kwargs}')
        # args are discarded
        for key, arg in kwargs.items():
            setattr(self, key, arg)

a_instance = A('arg', kwarg=1)
a_instance.kwarg

En général, il n'y a pas besoin de faire n'importe quoi avec __new__ , parce que les objets Python sont généralement mutables , et il n'y a donc aucune distinction entre l'initialisation des attributs d'instance et leur modification.

Le cas d'utilisation principal de surcharger __new__ , d'après mon expérience, c'est quand vous héritez de types immuables, tels que tuple . Dans de tels cas, vous devez initialiser tous les attributs d'instance à la création, et par conséquent __init__ est trop tard.


4 commentaires

La définition et l'appel à __new__ sont-ils implicites?


@ak_app Oui, lorsque vous appelez A (* args, ** kwargs) , vous appelez en fait A .__ new __ (* args, ** kwargs) . Les args et kwargs sont transmis à A .__ init__ .


Vous avez un commentaire # tuple .__ new__ , mais vous n'héritez pas réellement de tuple .


@ user2357112 Corrigé, j'ai envisagé d'utiliser un exemple de sous-classe tuple , puis je l'ai jeté, mais j'ai oublié de changer le commentaire.



3
votes

Réponse courte

En guise de réponse courte, la méthode qui crée l'objet est __new__ et __init__ initialise simplement l'objet créé.

Réponse longue

Cependant, continuez à lire si vous voulez avoir un aperçu plus détaillé de ce qui se passe quand un objet va être créé en python.


En python 2.x il y avait deux types de classes dans les classes python ancien et nouveau style.

A.__new__ called
A.__init__ called

class A(object):  # -> don't forget the object specified as base

def __new__(cls):
    print "A.__new__ called"
    return super(A, cls).__new__(cls)

def __init__(self):
    print "A.__init__ called"

A()

Dans les classes anciennes, il y avait Il n'y avait pas de méthode __new__ donc __init__ était le constructeur. Cependant, en python 3.x, il ne reste qu'une nouvelle classe de style (indépendamment du type de définition que vous choisissez pour votre classe, elle sera héritée de la classe de base "Object"). Dans les classes de style nouveau, les méthodes __new__ et __init__ sont disponibles. __new__ et __init__ sont respectivement le constructeur et l'initialiseur et vous êtes autorisé à les remplacer tous les deux (soyez prudent, vous n'avez généralement pas besoin de remplacer __new__ attendez dans certains cas comme la définition de méta-classes, etc., alors ne la manipulez pas si ce n'est pas nécessaire.) Enfin, lorsqu'un objet va être créé, le constructeur sera appelé avant l'initialiseur.

class C(object): # A old-style class sample 
     pass

La sortie sera:

class C: # A old-style class sample 
     pass

0 commentaires