Quand j'ai commencé à apprendre à écrire des classes en Python, j'ai trouvé cela très gênant. Pourquoi est-ce nécessaire lors de la définition mais pas lors de l'appel ? Pourquoi ne peut-il pas être simplifié en interne pour réduire le nombre de frappes que nous devons effectuer ? ? Vous comprendrez tous vos doutes après avoir lu cet article.
self représente une instance d'une classe, pas une classe.
Exemple pour illustrer :
class Test: def prt(self): print(self) print(self.__class__) t = Test() t.prt()
Les résultats d'exécution sont les suivants
<__main__.Test object at 0x000000000284E080> <class '__main__.Test'>
D'après l'exemple ci-dessus, il est évident que self représente une instance d'une classe. Et self.class pointe vers la classe.
self n'a pas besoin d'être écrit comme self
De nombreux enfants apprennent d'abord d'autres langues, puis apprennent Python, donc ils ont toujours l'impression que self est bizarre si. tu veux l'écrire comme ça, tu peux ?
Bien sûr, réécrivons le code ci-dessus. Une fois
class Test: def prt(this): print(this) print(this.__class__) t = Test() t.prt()
remplacé par ceci, les résultats d'exécution sont exactement les mêmes.
Bien sûr, il est préférable de respecter les habitudes établies et de se servir de soi.
Puis-je ne pas m'écrire ?
Dans l'interpréteur Python, lorsque nous appelons t.prt(), Python l'interprète en fait comme Test.prt(t ), c'est-à-dire remplacer self par une instance de la classe.
Les enfants intéressés peuvent réécrire la ligne t.prt() ci-dessus, et les résultats réels après l'exécution seront exactement les mêmes.
En fait, il a été partiellement expliqué que le soi ne peut pas être omis lors de la définition. Si vous devez l'essayer, veuillez voir ci-dessous :
class Test: def prt(): print(self) t = Test() t.prt()
L'erreur de rappel d'exécution est la suivante : prt n'a pas de paramètres lorsqu'il est défini, mais nous transmettons de force un paramètre lors de son exécution.
Puisque t.prt() est équivalent à Test.prt(t) comme expliqué ci-dessus, le programme nous rappelle que nous avons passé un paramètre t supplémentaire.
Traceback (most recent call last): File "h.py", line 6, in <module> t.prt() TypeError: prt() takes 0 positional arguments but 1 was given
Bien sûr, ce n'est pas grave si nous ne transmettons pas une instance de classe lorsque nous la définissons et l'appelons, c'est une méthode de classe.
class Test: def prt(): print(__class__) Test.prt()
Les résultats en cours d'exécution sont les suivants
<class '__main__.Test'>
En cas d'héritage , pass L'instance saisie est l'instance transmise, et non l'instance de la classe dans laquelle self est défini.
Regardez d'abord le code
class Parent: def pprt(self): print(self) class Child(Parent): def cprt(self): print(self) c = Child() c.cprt() c.pprt() p = Parent() p.pprt()
Les résultats d'exécution sont les suivants
<__main__.Child object at 0x0000000002A47080> <__main__.Child object at 0x0000000002A47080> <__main__.Parent object at 0x0000000002A47240>
Explication :
Il ne devrait y avoir aucun problème de compréhension lors de l'exécution de c.cprt(), qui fait référence à une instance de la classe Child.
Mais lors de l'exécution de c.pprt(), c'est équivalent à Child.pprt(c), donc self fait toujours référence à une instance de la classe Child Puisque la méthode pprt() n'est pas définie dans self, l'héritage est hérité En parcourant l'arborescence, nous constatons que la méthode pprt() est définie dans la classe parent Parent, elle sera donc appelée avec succès.
Dans la classe descripteur, self fait référence à l'instance de la classe descripteur
n'est pas facile à comprendre. Regardons d'abord l'exemple :
<. 🎜>class Desc: def __get__(self, ins, cls): print('self in Desc: %s ' % self ) print(self, ins, cls) class Test: x = Desc() def prt(self): print('self in Test: %s' % self) t = Test() t.prt() t.x
self in Test: <__main__.Test object at 0x0000000002A570B8> self in Desc: <__main__.Desc object at 0x000000000283E208> <__main__.Desc object at 0x000000000283E208> <__main__.Test object at 0x0000000002A570B8> <class '__main__.Test'>
self in Test: <__main__.Test object at 0x00000000022570B8> self in Desc: <__main__.Desc object at 0x000000000223E208> <__main__.Desc object at 0x000000000223E208> None <class '__main__.Test'>
Comprendre soi-même en python à partir de l'essence de OO
Par exemple, supposons que je veuille opérer sur les données de l'utilisateur, qui contiennent le nom et l'âge. Si une approche orientée processus est utilisée, l'implémentation ressemblera à ceci.
def user_init(user,name,age): user['name'] = name user['age'] = age def set_user_name(user, x): user['name'] = x def set_user_age(user, x): user['age'] = x def get_user_name(user): return user['name'] def get_user_age(user): return user['age'] myself = {} user_init(myself,'kzc',17) print get_user_age(myself) set_user_age(myself,20) print get_user_age(myself)
Si vous utilisez l'orientation objet, vous n'avez pas besoin de transmettre le paramètre utilisateur à chaque fois. Les données et les opérations pertinentes sont liées au même endroit. Les données peuvent être facilement obtenues à partir de différents endroits de cette classe.
La raison pour laquelle les données sont accessibles à partir de différents endroits de la classe est qu'elles sont liées à self. Bien sûr, le premier paramètre de sa méthode n'a pas besoin d'être appelé self, mais peut être appelé un autre nom. juste une convention.
Ce qui suit est l'implémentation orientée objet. Comme vous pouvez le voir, elle est beaucoup plus structurée, claire et lisible.
class User(object): def __init__(self,name,age): self.name = name self.age = age def SetName(self,name): self.name = name def SetAge(self,age): self.age = age def GetName(self): return self.name def GetAge(self): return self.age u = User('kzc',17) print u.GetName() print u.GetAge()
Résumé
selon l'accord
self fait toujours référence à l'instance de la classe lorsqu'elle est appelée.
Pour plus d'articles sur la compréhension de l'utilisation de self en Python, veuillez faire attention au site Web PHP chinois !