J'ai lu @ free_jinji2020 "J'ai réfléchi à la raison pour laquelle Python self est nécessaire en tant que débutant". J'ai adopté une approche différente, imaginé la structure interne et le fonctionnement interne de l'interpréteur Python, et vérifié le fonctionnement avec l'interpréteur Python, ce qui a approfondi ma compréhension, donc je vais écrire la méthode.
De plus, la vérification des opérations est effectuée avec la série Python3. Veuillez noter que le résultat d'affichage sera différent dans la série Python2.
Lorsque l'interpréteur Python lit le script Python et trouve la définition " def
", il crée une" instance de la classe function
", en fait un "objet fonction" qui peut appeler le processus et l'affecte à la variable du nom de la fonction.
Le traitement dans la fonction est compilé dans Bytecode et affecté à l'objet fonction. Vous pouvez également [assembler en sens inverse] le code d'octet (https://docs.python.org/ja/3.5/library/dis.html).
>>> def hello():
... print("Hello, world!")
...
>>> hello
<function hello at 0x6fffffd0dae8>
>>> type(hello)
<class'function'>
>>> hello()
Hello, world!
>>> hello.__code__.co_code.hex()
'740064018301010064005300'
>>> import dis
>>> dis.dis(hello)
2 0 LOAD_GLOBAL 0 (print)
2 LOAD_CONST 1 ('Hello, world!')
4 CALL_FUNCTION 1
6 POP_TOP
8 LOAD_CONST 0 (None)
10 RETURN_VALUE
Lorsque l'interpréteur Python trouve la "définition de classe", il crée une instance de la classe "type", en fait un "objet de classe" et l'affecte à la variable du nom de classe.
Un objet de classe peut créer un ** espace de noms ** (** espace variable **), définir des ** variables ** librement dans l'objet de classe et affecter des ** valeurs ** et ** fonctions **. Je vais.
Les variables de l'objet peuvent être vues avec la fonction vars
. Vous pouvez également voir les noms dans la portée locale avec la fonction dir
. J'ai aussi Diverses informations.
>>> class Sample:
... pass
...
>>> Sample.value = 123
>>> Sample.value * 3
369
>>> Sample.data = [1, 2, 3]
>>> vars(Sample)
mappingproxy({'__module__': '__main__', '__dict__': <attribute '__dict__' of 'Sample' objects>, '__weakref__': <attribute '__weakref__' of 'Sample' objects>, '__doc__': None,
'value': 123, 'data': [1, 2, 3]})
>>> dir(Sample)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
>>> Sample.__name__
'Sample'
La fonction n'est exécutée que si elle est appelée, mais l'affectation de variable (affectation à l'objet de classe) et la définition de fonction (affectation à l'objet de fonction) écrites directement sous la définition de classe sont exécutées au moment de la définition de classe.
>>> class Sample:
... value = 123
... print(value * 3)
...
369
>>> Sample.value
123
S'il y a une définition «def» (définition de fonction) dans la définition de «classe», l '«objet de fonction» est affecté dans l'objet de classe.
Il peut être appelé avec nom de classe.nom de fonction ()
.
>>> class Sample:
... def greet():
... print("Hey, guys!")
...
>>> Sample
<class'__main__.Sample'>
>>> type(Sample)
<class'type'>
>>> Sample.greet
<function Sample.greet at 0x6fffffd0dd08>
>>> type(Sample.greet)
<class'function'>
>>> Sample.greet()
Hey, guys!
Vous pouvez voir que l'objet de fonction greet
( function greet
) a été assigné à la variable greet
.
>>> vars(Sample)
mappingproxy({'__module__': '__main__', 'greet': <function Sample.greet at 0x6fffffd0dd08>, '__dict__': <attribute '__dict__' of 'Sample' objects>, '__weakref__': <attribute '__weakref__' of 'Sample' objects>, '__doc__': None})
Lors de la création d'un objet de classe, le processus appelé "constructeur" est automatiquement défini comme méthode __call__
, et" Vous pouvez maintenant appeler le constructeur avec nom de classe ()
".
L'appel du constructeur crée une "zone de données" appelée "instance".
Les instances peuvent également créer un espace de noms (espace variable), définir librement des variables et affecter des valeurs. L'instance initiale est un état vide sans variable.
>>> data = Sample()
>>> vars(data)
{}
>>> data.name = "Taro"
>>> vars(data)
{'name': 'Taro'}
Définissons une "fonction" qui affiche le "nom" attribué à l'instance et affiche le "nom". Vous avez besoin d'un argument qui indique à quelle instance est le nom.
>>> def introduce(data):
... print("My name is", data.name)
...
>>> introduce(data)
My name is Taro
Vous pouvez également appeler la fonction ʻintroduire` définie en dehors de la classe ci-dessus en l'affectant à un objet de classe.
>>> introduce
<function introduce at 0x6fffffd0dc80>
>>> Sample.introduce = introduce
>>> Sample.introduce
<function introduce at 0x6fffffd0dc80>
>>> Sample.introduce(data)
My name is Taro
Le "constructeur" a été automatiquement défini lors de la création de la classe, mais la "méthode" est automatiquement définie lors de la création de l'instance. Une "méthode" est une instance de la classe de méthode. Il existe différents types de méthodes telles que la "méthode d'instance" et la "méthode de classe". Lorsque vous appelez une méthode, la fonction de l'objet de classe est appelée avec l'instance ou l'objet de classe comme premier argument.
>>> Sample.introduce
<function introduce at 0x6fffffd0dc80>
>>> type(Sample.introduce)
<class'function'>
>>> data.introduce
<bound method introduce of <__main__.Sample object at 0x6fffffd16518>>
>>> type(data.introduce)
<class'method'>
>>> data.introduce()
My name is Taro
J'ai assigné la fonction ʻintroduire` définie en dehors de la classe à l'objet de classe, mais il est plus facile de comprendre si la définition de la fonction est écrite à l'intérieur de la classe.
>>> class Person:
... def initialize(data, name):
... data.name = name
... def introduce(data):
... print("My name is", data.name)
...
>>> taro = Person()
>>> vars(taro)
{}
>>> Person.initialize(taro, "Taro")
>>> vars(taro)
{'name': 'Taro'}
>>> Person.introduce(taro)
My name is Taro
Vous pouvez également appeler des fonctions en classe via des méthodes d'instance. Comme je l'ai écrit précédemment, la méthode appelle la fonction dans l'objet de classe avec l'instance elle-même comme premier argument.
>>> hanako = Person()
>>> hanako.inittialize("Hanako")
>>> hanako.introduce()
My name is Hanako
__init__
Après avoir créé l'instance, j'appelle la méthode ʻinitializepour définir le nom, mais ce serait pratique si la valeur initiale pouvait être spécifiée dans l'argument du constructeur. C'est la [méthode
init](https://docs.python.org/ja/3.6/reference/datamodel.html#object.__init__). Une fois le constructeur instancié, il appelle la méthode
init` avec l'instance elle-même comme premier argument. Avec les arguments passés au constructeur.
>>> class Person:
... def __init__(self, name):
... self.name = name
... def introduce(self):
... print("My name is", self.name)
...
>>> ichiro = Person("Ichiro")
>>> ichiro.introduce()
My name is Ichiro
self
Dans «PEP8: Python Code Style Guide», il est dit:
Utilisez toujours
self
comme nom du premier argument de la méthode d'instance. Utilisez toujourscls
comme nom du premier argument de la méthode de classe.
Le nom de l'argument n'a pas d'importance, mais changeons le nom de l'argument data
dans le code ci-dessus en self
selon le guide de style.
C'est la manière générale d'écrire.
@ classmethod
Si vous ajoutez un décorateur @ classmethod
lors de la définition d'une fonction en classe, il sera remplacé par une méthode qui appelle le premier argument en tant qu'objet de classe.
Vous pouvez définir le traitement pour chaque classe qui est indépendant de l'instance.
>>> class Sample:
... @classmethod
... def class_method(cls):
... print("called:", cls)
...
>>> Sample.class_method
<bound method Sample.class_method of <class'__main__.Sample'>>
>>> Sample.class_method()
called: <class'__main__.Sample'>
>>> s = Sample()
>>> s.class_method
<bound method Sample.class_method of <class'__main__.Sample'>>
>>> s.class_method()
called: <class'__main__.Sample'>
@ staticmethod
Si vous ajoutez un décorateur @ staticmethod
lors de la définition d'une fonction en classe, la fonction sera appelée directement sans ajouter le premier argument.
C'est la même chose qu'une définition de fonction normale, mais en la plaçant dans l'espace de noms de classe, vous pouvez définir une fonction avec le même nom dans différentes classes, vous n'avez donc pas à vous soucier des conflits de noms.
>>> class Sample:
... @staticmethod
... def static_method():
... print("Hello, world!")
...
>>> Sample.static_method
<function Sample.static_method at 0x6fffffd1e268>
>>> Sample.static_method()
Hello, world!
>>> s = Sample()
>>> s.static_method
<function Sample.static_method at 0x6fffffd1e268>
>>> s.static_method()
Hello, world!
Les objets de fonction sont responsables de tout le traitement en Python, et un argument est requis pour spécifier quelle donnée = instance = objet à traiter, et la règle d'opération selon laquelle le premier nom d'argument passé par l'instance doit être unifié avec self
. Il s'est avéré être spécifié dans PEP8.
Je n'ai pas suivi en profondeur le code source de l'interpréteur Python, donc je pense qu'il y a quelques inexactitudes. J'apprécierais que vous me donniez des commentaires tels que des suggestions. Il y avait beaucoup de choses que je pouvais comprendre en pensant aux sentiments de l'interpréteur Python. Pourquoi ne pensez-vous pas aux sentiments de l'interpréteur Python?
Recommended Posts