web-dev-qa-db-fra.com

Expliquer la variable python 'self' à un débutant

Je suis à peu près ignorant OOP jargon et concepts. Je sais conceptuellement ce qu'est un objet, et que les objets ont des méthodes. Je comprends même qu'en python, les classes sont des objets! C'est cool, je je ne sais pas ce que ça veut dire. Ça ne clique pas avec moi.

J'essaie actuellement de comprendre quelques réponses détaillées qui, à mon avis, éclaireront ma compréhension du python:

  1. Que fait le mot-clé "yield" en Python?
  2. Qu'est-ce qu'une métaclasse en Python?

Dans la première réponse, l'auteur utilise le code suivant comme exemple:

>>> class Bank(): # let's create a bank, building ATMs
...    crisis = False
...    def create_atm(self) :
...        while not self.crisis :
...            yield "$100"

Je ne vois pas immédiatement ce que self pointe. C'est certainement un symptôme de ne pas comprendre les cours, sur lequel je travaillerai à un moment donné. Pour clarifier, en

>>> def func():
...   for i in range(3):
...     print i

Je comprends que i pointe vers un élément de la liste range(3) qui, puisqu'il est dans une fonction, n'est pas global. Mais qu'est-ce que self "pointe vers"?

33
jrhorn424

Je vais d'abord essayer de dissiper une certaine confusion sur les classes et les objets. Regardons ce bloc de code:

>>> class Bank(): # let's create a bank, building ATMs
...    crisis = False
...    def create_atm(self) :
...        while not self.crisis :
...            yield "$100"

Le commentaire y est un peu trompeur. Le code ci-dessus ne "crée" pas de banque. Il définit ce qu'est une banque. Une banque est quelque chose qui a une propriété appelée crisis et une fonction create_atm. C'est ce que dit le code ci-dessus.

Créons maintenant une banque:

>>> x = Bank()

Là, x est maintenant une banque. x a une propriété crisis et une fonction create_atm. L'appel de x.create_atm(); dans python est identique à l'appel de Bank.create_atm(x);, donc maintenant self fait référence à x. Si vous ajoutez une autre banque appelée y, appelant y.create_atm() saura regarder la valeur de crise de y, pas de x car dans cette fonction self fait référence à y.

self n'est qu'une convention de dénomination, mais il est très bon de s'y tenir. Il convient tout de même de souligner que le code ci-dessus équivaut à:

>>> class Bank(): # let's create a bank, building ATMs
...    crisis = False
...    def create_atm(thisbank) :
...        while not thisbank.crisis :
...            yield "$100"
92
Paulpro

Cela peut vous aider à considérer la syntaxe d'invocation de obj.method(arg1, arg2) comme un sucre purement syntaxique pour appeler method(obj, arg1, arg2) (sauf que method est recherché via le type de obj , et n'est pas global).

Si vous le voyez de cette façon, obj est le premier argument de la fonction, qui est traditionnellement nommée self dans la liste des paramètres. (Vous pouvez, en fait, le nommer autre chose, et votre code fonctionnera correctement, mais d'autres codeurs Python vous fronceront les sourcils.)

18
Chris Jester-Young

" self " est l'objet d'instance automatiquement passé à la méthode de l'instance de classe lors de son appel, pour identifier l'instance qui l'a appelée. " self " est utilisé pour accéder à d'autres attributs ou méthodes de l'objet depuis l'intérieur de la méthode. (les méthodes sont essentiellement des fonctions qui appartiennent à une classe)

" self " n'a pas besoin d'être utilisé lors de l'appel d'une méthode alors que vous avez déjà une instance disponible.

Accès à l'attribut "some_attribute" depuis l'intérieur d'une méthode:

class MyClass(object):
    some_attribute = "hello"

    def some_method(self, some_string):
        print self.some_attribute + " " + some_string

Accès à l'attribut "some_attribute" à partir d'une instance existante:

>>> # create the instance
>>> inst = MyClass()
>>>
>>> # accessing the attribute
>>> inst.some_attribute
"hello"
>>> 
>>> # calling the instance's method
>>> inst.some_method("world") # In addition to "world", inst is *automatically* passed here as the first argument to "some_method".
hello world
>>> 

Voici un petit code pour démontrer que self est identique à l'instance:

>>> class MyClass(object):
>>>     def whoami(self, inst):
>>>         print self is inst
>>>
>>> local_instance = MyClass()

>>> local_instance.whoami(local_instance)
True

Comme mentionné par d'autres, il est nommé " self " par convention, mais il pourrait être nommé n'importe quoi.

12
monkut

self fait référence à l'instance actuelle de Bank. Lorsque vous créez un nouveau Bank et appelez create_atm dessus, self sera implicitement passé par python, et fera référence à la banque que vous avez créée.

5
recursive

Je ne vois pas immédiatement ce que self pointe. C'est certainement un symptôme de ne pas comprendre les cours, sur lequel je travaillerai à un moment donné.

self est un argument passé à la fonction. En Python, ce premier argument est implicitement l'objet sur lequel la méthode a été invoquée. En d'autres termes:

class Bar(object):
    def someMethod(self):
        return self.field

bar = Bar()

bar.someMethod()
Bar.someMethod(bar)

Ces deux dernières lignes ont un comportement équivalent. (Sauf si bar fait référence à un objet d'une sous-classe de Bar - alors someMethod() peut faire référence à un objet fonction différent.)

Notez que vous pouvez nommer le premier argument "spécial" tout ce que vous voulez - self n'est qu'une convention pour les méthodes.

Je comprends que i pointe vers un élément de la liste range(3) qui, puisqu'il est dans une fonction, n'est pas global. Mais qu'est-ce que self "pointe vers"?

Le nom self n'existe pas dans le contexte de cette fonction. Tenter de l'utiliser déclencherait un NameError.


Exemple de transcription:

>>> class Bar(object):
...     def someMethod(self):
...         return self.field
...
>>> bar = Bar()
>>> bar.field = "foo"
>>> bar.someMethod()
'foo'
>>> Bar.someMethod(bar)
'foo'
>>> def fn(i):
...     return self
...
>>> fn(0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in fn
NameError: global name 'self' is not defined
5
cdhowie

La raison pour laquelle "self" est là (par convention) est que lorsque le runtime Python voit un appel de la forme Object.Method (Param1, Param2), il appelle Method avec des paramètres (Object, Param1 , Param2). Donc, si vous appelez ce premier paramètre "self", tout le monde saura de quoi vous parlez.

La raison pour laquelle vous devez le faire fait l'objet d'une autre question.

En ce qui concerne une métaclasse, c'est quelque chose de rarement utilisé. Vous voudrez peut-être regarder: http://python-history.blogspot.com/2009/04/metaclasses-and-extension-classes-aka.html , l'auteur original et actuel dictateur bienveillant pour Life of Python explique ce que c'est, et comment cela a été. Il a également un article sympa sur certaines utilisations possibles, mais la plupart des gens ne l'utilisent jamais directement du tout.

2
psr

Le point de vue d'un Rubyist (Ruby est mon premier langage de programmation, donc je m'excuse pour les abstractions simplifiées et potentiellement erronées que je suis sur le point d'utiliser)

pour autant que je sache, l'opérateur point, par exemple:

os.path

est tel que os est passé dans path() comme première variable "invisible"

C'est comme si os.path Était VRAIMENT ceci:

path(os)

S'il y avait une guirlande, j'imagine que ceci:

os.path.filename

Serait un peu comme ça en réalité *:

filename(path(os))

Voici la partie offensive Donc, avec l'auto-variable, tout ce que vous faites est d'autoriser la MÉTHODE DE CLASSE (d'un point de vue rubyiste python 'les méthodes d'instance' semblent être des méthodes de classe). ..) pour agir comme une méthode d'instance en lui faisant passer une instance en tant que première variable (via la méthode point "sneaky" ci-dessus) qui est appelée self par convention.

c = ClassName()
c.methodname

mais la classe elle-même:

ClassName.methodname

la classe serait transmise plutôt que l'instance.

OK, il est également important de se rappeler que la méthode __init__ Est appelée "magique" par certains. Ne vous inquiétez donc pas de ce qui est passé pour générer une nouvelle instance. Pour être honnête, c'est probablement nil.

2
boulder_ruby

self fait référence à une instance de la classe.

1
MRAB