web-dev-qa-db-fra.com

Membres de classe Python

J'apprends juste Python et je viens d'un C, alors merci de me prévenir si j'ai de la confusion ou une confusion entre les deux.

Supposons que j'ai la classe suivante:

class Node(object):
    def __init__(self, element):
        self.element = element
        self.left = self.right = None

    @classmethod
    def tree(cls, element, left, right):
        node = cls(element)
        node.left = left
        node.right = right
        return node

Il s'agit d'une classe nommée Node, qui surcharge le constructeur, pour pouvoir gérer différents arguments si nécessaire.

Quelle est la différence entre définir self.element uniquement dans __init__ (comme indiqué ci-dessus) et ne pas procéder comme suit:

class Node(object):
    element, left, right = None
    def __init__(self, element):
        self.element = element
        self.left = self.right = None

self.element dans __init__ n'est-il pas identique à la variable element de la classe définie? Cela ne remplacerait-il pas simplement element de None par la valeur element passée dans __init__?

40
darksky

L'un est un attribut de classe, tandis que l'autre est un attribut d'instance. Ils sont différents, mais ils sont étroitement liés les uns aux autres de manière à ce qu'ils se ressemblent parfois. 

Cela a à voir avec la façon dont python recherche les attributs. Il y a une hiérarchie. Dans des cas simples, cela pourrait ressembler à ceci:

instance -> Subclass -> Superclass -> object (built-in type)

Lorsque vous recherchez un attribut sur instance comme ceci ...

`instance.val`

... ce qui se passe réellement est que first , Python recherche val dans l'instance elle-même. Ensuite, s'il ne trouve pas val, il cherche dans sa classe, Subclass. Ensuite, s'il ne trouve pas val, il cherche dans le parent de Subclass, Superclass. Cela signifie que lorsque vous faites cela ...

>>> class Foo():
    foovar = 10  
    def __init__(self, val):
        self.selfvar = val

... toutes les instances de Foo share foovar, mais ont leurs propres selfvars. Voici un exemple simple et concret de la façon dont cela fonctionne:

>>> f = Foo(5)
>>> f.foovar
10
>>> Foo.foovar
10

Si nous ne touchons pas foovar, c'est la même chose pour f et Foo. Mais si nous changeons f.foovar...

>>> f.foovar = 5
>>> f.foovar
5
>>> Foo.foovar
10

... nous ajoutons un attribut d'instance qui masque efficacement la valeur de Foo.foovar. Maintenant, si nous changeons directement Foo.foovar, cela n’affectera pas notre instance foo:

>>> Foo.foovar = 7
>>> f.foovar
5

Mais cela affecte une nouvelle instance foo:

>>> Foo(5).foovar
7

Gardez également à l'esprit que les objets mutables ajoutent une autre couche d'indirection (comme me l'a rappelé mgilson). Ici, f.foovar fait référence au même objet que Foo.foovar. Ainsi, lorsque vous modifiez l'objet, les modifications sont propagées dans la hiérarchie:

>>> Foo.foovar = [1]
>>> f = Foo(5)
>>> f.foovar[0] = 99
>>> Foo.foovar
[99]
65
senderle

En python, il est possible d'avoir des variables de classe et des variables d'instance du même nom. Ils sont situés séparément dans la mémoire et sont accessibles très différemment.

Dans votre code:

class Node(object):
    element, left, right = None
    def __init__(self, element):
        self.element = element
        self.left = self.right = None

Le premier ensemble de variables (en dehors de la fonction __init__) est appelé variable de classe. On peut y accéder par la suite à l'aide de Node.element, etc. Ils sont équivalents aux variables membres statiques en C++ et ils sont partagés par toutes les instances de la classe.

Le deuxième ensemble de variables (à l'intérieur de la fonction __init__) est appelé variable d'instance. Celles-ci sont accessibles via l’objet self, par exemple. self.element, ou par le nom de l'instance, par exemple. myNode.element en dehors de la classe.

Il est important de noter que vous devez utiliser le formulaire self.variable ou Node.variable pour accéder à l'un de ces éléments à partir d'une fonction membre. Un simple accès à variable tentera d’accéder à une variable locale appelée variable.

11
Lee Netherton

self.element à l'intérieur du constructeur est une variable d'instance (si un objet de noeud modifie sa valeur, elle ne change que pour cet objet) où celui de la deuxième version est une variable de classe (ainsi, si un objet de noeud modifie sa valeur, il changera pour tout objets nœuds).

L'analogie en C++ serait une variable de membre non statique ou statique dans votre classe.

2
Borgleader

La partie importante est l'argument self à __init__. En fait, dans la méthode any instance, ce sera le premier argument. Ceci est fait par la conception; en Python, la seule fois où vous avez réellement accès à l'instance est lors d'appels de méthode, et cela est montré explicitement avec l'argument self.

Lorsque vous êtes à l'intérieur d'une définition class, vous n'avez pas encore d'instance, alors vous modifiez réellement la classe elle-même. Ainsi, si vous définissez des attributs au niveau de la classe, ils deviennent alors des attributs de classe et non des instances.

En le comparant à un C (++), vous pourriez probablement dire que les "classes" dans ces langages sont essentiellement des modèles pour les objets qu'elles représentent. "Ces objets doivent avoir les attributs foo et bar, ainsi que les méthodes suivantes." Cependant, en Python, les classes sont des objets eux-mêmes et leur principale force est de pouvoir créer des copies (instances) d’elles-mêmes, qui utilisent également les méthodes de la classe. Donc, cela ressemble plus à "Tu auras foo et bar comme attributs de classe, et en plus la méthode suivante que tu utiliseras pour créer des instances."

Ainsi, au lieu d’un plan directeur, il s’agit plutôt d’un guide pas à pas.

0
voithos

self.element dans init est une variable d'instance, vous pouvez l'obtenir/le définir dans n'importe quelle fonction membre en tapant self.element L'élément déclaré dans la classe est la variable de classe, vous pouvez l'obtenir/le définir en tapant Node.element.

0
waitingkuo

lorsque vous essayez d'accéder à la variable avec une classe, il ne regarde que 

cls.__dict__

mais lorsque vous essayez d'accéder à la variable avec instance, il semble d'abord 

self.__dict__ 

si trouver puis revenir ou si ne peut pas trouver alors il regarde aussi dans 

cls.__dict__

ici c'est la classe 

class Test:
    temp_1=10
    temp_2=20

    def __init__(self):
        self.test_1=10
        self.test_2=20

    @classmethod
    def c_test(cls):
        pass

    def t_method(self):
        pass


print Test.__dict__
print Test().__dict__

Sortie:

{'c_test': <classmethod object at 0x7fede8f35a60>, '__module__': '__main__', 't_method': <function t_method at 0x7fede8f336e0>, 'temp_1': 10, '__doc__': None, '__init__': <function __init__ at 0x7fede8f335f0>, 'temp_2': 20}

{'test_2': 20, 'test_1': 10}

Pour détail attribut spécial de classe

0
Kallz