228 votes

Comment puis-je accéder aux variables de classe "statiques" dans les méthodes en Python ?

Si j'ai le code suivant :

class Foo(object):
    bar = 1

    def bah(self):
        print(bar)

f = Foo()
f.bah()

Il se plaint

NameError : le nom global 'bar' n'est pas défini

Comment puis-je accéder à une classe/ variable statique bar dans la méthode bah ?

0 votes

Vous trouverez plus d'informations concernant Python et la statique ici : stackoverflow.com/questions/68645/python-static-variable

232voto

Chris Cameron Points 3841

Au lieu de bar utilice self.bar o Foo.bar . Affectation à Foo.bar créera une variable statique, et en l'assignant à self.bar va créer une variable d'instance.

13 votes

Foo.bar fonctionnera, mais self.bar crée une variable d'instance, et non une variable statique.

60 votes

Bedwyr, "print self.bar" ne créera aucune variable d'instance (bien que l'affectation à self.bar le fera).

1 votes

@Constantin -- Je n'avais pas réalisé cela, c'est une distinction intéressante. Merci pour la correction :-)

113voto

vartec Points 53382

Définir une méthode de classe :

class Foo(object):
    bar = 1
    @classmethod
    def bah(cls):    
        print cls.bar

Maintenant si bah() doit être une méthode d'instance (c'est-à-dire avoir accès à self), vous pouvez toujours accéder directement à la variable de classe.

class Foo(object):
    bar = 1
    def bah(self):    
        print self.bar

7 votes

Pourquoi pas simplement Foo.bar, au lieu de self.__class__.bar ?

23 votes

@Mk12 : Lorsque vous avez un héritage de classe, une "variable de classe" peut se trouver dans une classe de base ou une sous-classe. A laquelle voulez-vous faire référence ? Cela dépend de ce que vous essayez de faire. Foo.bar fera toujours référence à un attribut de la classe spécifiée - qui peut être une classe de base ou une sous-classe. self.__class__.bar fera référence à la classe dont l'instance est un type.

9 votes

Nous avons maintenant atteint ce point malheureux où nous devenons si conscients des détails de la langue que nous pouvons faire la distinction entre deux cas d'utilisation finement accordés. Cela dépend en effet de ce que vous voulez faire, mais beaucoup de gens ne s'intéressent pas à ces subtilités.

21voto

David Berger Points 5459

Comme dans tous les bons exemples, vous avez simplifié ce que vous essayez réellement de faire. C'est bien, mais il est bon de noter que python possède une fonction lot de flexibilité lorsqu'il s'agit de variables de classe ou d'instance. On peut dire la même chose des méthodes. Pour une bonne liste de possibilités, je vous recommande de lire Introduction aux classes de style nouveau de Michael Fötsch en particulier les sections 2 à 6.

Une chose dont il faut se souvenir quand on commence, c'est que python n'est pas java. Plus qu'un simple cliché. En Java, une classe entière est compilée, ce qui rend la résolution de l'espace de noms très simple : toutes les variables déclarées en dehors d'une méthode (n'importe où) sont des variables d'instance (ou, si elles sont statiques, de classe) et sont implicitement accessibles dans les méthodes.

Avec python, la règle générale est qu'il y a trois espaces de noms qui sont recherchés, dans l'ordre, pour les variables :

  1. La fonction/méthode
  2. Le module actuel
  3. Builtins

{begin pedagogy}

Il existe des exceptions limitées à cette règle. La principale qui me vient à l'esprit est que, lorsqu'une définition de classe est chargée, elle constitue son propre espace de noms implicite. Mais cela ne dure que tant que le module est chargé, et est entièrement contourné lorsqu'il se trouve dans une méthode. Ainsi :

>>> class A(object):
        foo = 'foo'
        bar = foo

>>> A.foo
'foo'
>>> A.bar
'foo'

mais :

>>> class B(object):
        foo = 'foo'
        def get_foo():
            return foo
        bar = get_foo()

Traceback (most recent call last):
  File "<pyshell#11>", line 1, in <module>
    class B(object):
  File "<pyshell#11>", line 5, in B
    bar = get_foo()
  File "<pyshell#11>", line 4, in get_foo
    return foo
NameError: global name 'foo' is not defined

{end pedagogy}

En fin de compte, la chose à retenir est que vous faire ont accès à toutes les variables auxquelles vous voulez accéder, mais probablement pas de manière implicite. Si vos objectifs sont simples et directs, alors choisir Foo.bar ou self.bar sera probablement suffisant. Si votre exemple devient plus compliqué, ou si vous voulez faire des choses fantaisistes comme l'héritage (vous pouvez hériter des méthodes statiques/de la classe !), ou si l'idée de faire référence au nom de votre classe dans la classe elle-même vous semble fausse, consultez l'introduction que j'ai citée.

0 votes

IIRC, il y a techniquement 3(+) espaces de noms recherchés -- function-local, module/global, et builtins. Les scopes imbriqués signifient que plusieurs scopes locaux peuvent être recherchés, mais c'est l'un des cas exceptionnels. (...)

0 votes

De plus, je serais prudent en disant 'module principal', car c'est le module contenant la fonction qui est recherché, et non le principal module... Et rechercher l'attribut à partir d'une référence d'instance est une chose différente, mais cette réponse l'explique pourquoi vous avez besoin de la référence de l'instance/classe.

14voto

Allan Mwesigwa Points 446
class Foo(object):
     bar = 1
     def bah(self):
         print Foo.bar

f = Foo() 
f.bah()

1voto

Parik Chudasma Points 13

bar est votre variable statique et vous pouvez y accéder en utilisant Foo.bar .

Fondamentalement, vous devez qualifier votre variable statique avec un nom de classe.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X