J'ai réfléchi à la raison pour laquelle Python self est nécessaire avec le sentiment d'un interpréteur Python

introduction

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.

Définition de fonction: création d'objet de fonction

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

Définition de classe: création d'objet de classe

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

Définition de fonction en classe: affectation d'objet de fonction

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})

Constructeur: génération d'instance

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".

Instance: données

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

Attribuer une fonction à un objet de classe

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

Méthode: objet de méthode

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

Méthode d'instance

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

Méthode d'initialisation: méthode __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éthodeinit](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

Instance elle-même: 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 toujours cls 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.

Méthode de classe: @ 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'>

Méthode statique: @ 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!

à la fin

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

J'ai réfléchi à la raison pour laquelle Python self est nécessaire avec le sentiment d'un interpréteur Python
Pourquoi le premier argument de la classe [Python] est-il self?
J'ai examiné de plus près pourquoi l'auto Python est nécessaire
[python] [meta] Le type de python est-il un type?
Un mémo que j'ai touché au magasin de données avec python
Un mémorandum sur la mise en œuvre des recommandations en Python
[Python & SQLite] J'ai analysé la valeur attendue d'une course avec des chevaux dans la fourchette 1x win ②
À propos des fonctionnalités de Python
J'ai remplacé le livre de recettes Windows PowerShell par un script python.
J'ai essayé la "correction gamma" de l'image avec Python + OpenCV
J'ai pensé à un cours pour débutants sur Python basé sur des jeux blockchain
Pourquoi puis-je utiliser le module en important avec python?
J'ai écrit la grammaire de base de Python dans Jupyter Lab
J'ai évalué la stratégie de négociation du système boursier avec Python.
J'ai essayé de simuler la probabilité d'un jeu de bingo avec Python
J'ai réfléchi un peu car Trace Plot du paramètre de stan est difficile à voir
J'ai écrit un doctest dans "J'ai essayé de simuler la probabilité d'un jeu de bingo avec Python"
J'ai comparé la vitesse de Hash avec Topaz, Ruby et Python
[Python] Qu'est-ce qu'une instruction with?
J'ai essayé de gratter le classement du calendrier de l'avent Qiita avec Python
Le 14 mars est le jour du rapport de circonférence. L'histoire du calcul du ratio de circonférence avec python
[python, ruby] sélénium-Obtenez le contenu d'une page Web avec le pilote Web
[Python] Qu'est-ce que @? (À propos des décorateurs)
[Introduction à StyleGAN] J'ai joué avec "The Life of a Man" ♬
Je veux sortir le début du mois prochain avec Python
J'ai fait une loterie avec Python.
J'ai créé beaucoup de fichiers pour la connexion RDP avec Python
L'histoire de la création d'un pilote standard pour db avec python.
Une liste de fonctions que j'ai rencontrées avec 100 coups Numpy et j'ai pensé "C'est pratique!"
J'ai aimé le tweet avec python. ..
Je voulais résoudre le problème ABC164 A ~ D avec Python
L'idée d'alimenter le fichier de configuration avec un fichier python au lieu de yaml
Le dernier NGINX est un serveur d'applications! ?? J'ai mesuré le benchmark de NGINX Unit avec PHP, Python, Go! !!
Après avoir fait des recherches sur la bibliothèque Python, j'ai un peu compris egg.info.
J'ai essayé d'améliorer l'efficacité du travail quotidien avec Python
Je veux clarifier la question de la méthode "__init__" et de l'argument "self" de la classe Python.
J'ai créé un démon avec Python
À propos de la liste de base des bases de Python
L'histoire de la création d'un module qui ignore le courrier avec python
J'ai fait beaucoup de recherches sur la façon dont Python est exécuté
Une raison simple pour laquelle la valeur de retour de round (2.675,2) est de 2,67 en python (elle devrait être de 2,68 en réalité ...)
Créez un programme de jugement de compatibilité avec le module aléatoire de python.
J'étais fatigué de Python, alors j'ai analysé les données avec nehan (lié à Corona, est-ce que ce mot est maintenant?)
[Explication AtCoder] Contrôlez les problèmes A, B, C d'ABC182 avec Python!
Quel est le fichier XX à la racine d'un projet Python populaire?
Calculer l'itinéraire le plus court d'un graphe avec la méthode Dyxtra et Python
[Introduction à Python] Comment trier efficacement le contenu d'une liste avec le tri par liste
J'ai essayé d'obtenir le code d'authentification de l'API Qiita avec Python.
Calculez la probabilité d'être une pièce de calmar avec le théorème de Bayes [python]
Hit une méthode d'une instance de classe avec l'API Web Python Bottle
Recevez une liste des résultats du traitement parallèle en Python avec starmap
J'ai fait GAN avec Keras, donc j'ai fait une vidéo du processus d'apprentissage.