102 votes

Accéder aux variables membres d'une classe en Python ?

class Example(object):
    def the_example(self):
        itsProblem = "problem"

theExample = Example()
print(theExample.itsProblem)

Comment accéder à la variable d'une classe ? J'ai essayé d'ajouter cette définition :

def return_itsProblem(self):
    return itsProblem

Pourtant, cela échoue également.

1 votes

Titre modifié, la question porte en fait sur les variables "statiques" des classes : stackoverflow.com/questions/707380/

179voto

e-satis Points 146299

La réponse, en quelques mots

Dans votre exemple, itsProblem est une variable locale.

Vous devez utiliser self pour définir et obtenir des variables d'instance. Vous pouvez le définir dans le __init__ méthode. Votre code serait alors le suivant :

class Example(object):
    def __init__(self):
        self.itsProblem = "problem"

theExample = Example()
print(theExample.itsProblem)

Mais si vous voulez une véritable variable de classe, utilisez directement le nom de la classe :

class Example(object):
    itsProblem = "problem"

theExample = Example()
print(theExample.itsProblem)
print (Example.itsProblem)

Mais soyez prudent avec celui-ci, car theExample.itsProblem est automatiquement défini comme étant égal à Example.itsProblem mais ce n'est pas du tout la même variable et elle peut être modifiée indépendamment.

Quelques explications

En Python, les variables peuvent être créées dynamiquement. Par conséquent, vous pouvez faire ce qui suit :

class Example(object):
    pass

Example.itsProblem = "problem"

e = Example()
e.itsSecondProblem = "problem"

print Example.itsProblem == e.itsSecondProblem 

imprime

Véritable

Par conséquent, c'est exactement ce que vous faites avec les exemples précédents.

En effet, en Python, nous utilisons self como this mais c'est un peu plus que ça. self est le premier argument de toute méthode objet car le premier argument est toujours la référence de l'objet. C'est automatique, que vous l'appeliez self ou pas.

Ce qui veut dire que vous pouvez le faire :

class Example(object):
    def __init__(self):
        self.itsProblem = "problem"

theExample = Example()
print(theExample.itsProblem)

ou :

class Example(object):
    def __init__(my_super_self):
        my_super_self.itsProblem = "problem"

theExample = Example()
print(theExample.itsProblem)

C'est exactement la même chose. Le premier argument de la méthode ANY object est l'objet courant, nous l'appelons seulement self comme une convention. Et vous ajoutez juste une variable à cet objet, de la même manière que vous le feriez de l'extérieur.

Maintenant, à propos des variables de classe.

Quand vous le faites :

class Example(object):
    itsProblem = "problem"

theExample = Example()
print(theExample.itsProblem)

Vous remarquerez que nous avons d'abord définir une variable de classe alors nous avons accès à une variable objet (instance) . Nous n'avons jamais défini cette variable objet mais elle fonctionne, comment est-ce possible ?

Eh bien, Python essaie d'abord d'obtenir la variable objet, mais s'il ne la trouve pas, il vous donnera la variable classe. Attention : la variable de classe est partagée entre les instances, et la variable d'objet ne l'est pas.

En conclusion, n'utilisez jamais les variables de classe pour définir les valeurs par défaut des variables d'objet. Utilisez __init__ pour ça.

Finalement, vous apprendrez que les classes Python sont des instances et donc des objets eux-mêmes, ce qui donne un nouvel aperçu de la compréhension de ce qui précède. Revenez lire cet article plus tard, lorsque vous l'aurez compris.

0 votes

Vous dites : "theExample.itsProblem est automatiquement défini comme étant égal à Example.itsProblem, mais n'est pas du tout la même variable et peut être modifié indépendamment" - mais ce n'est pas tout à fait exact, et votre phrase est trompeuse. Je pense que vous savez ce qui se passe ici, donc je vous suggère de reformuler cela : "il es la même variable, mais il peut être rebindé indépendamment pour chaque objet".

0 votes

Oui, mais la liaison est un concept quelqu'un pour un autre langage de programmation comme Java ou C (comme je soupçonne l'OP est) qui est complètement inconnu. Je devrais alors expliquer ce qu'est le binding, puis le late binding, puis le problème des références sur les objets mutables. Ce serait trop long. Je pense que parfois, il faut sacrifier la précision sur l'autel de la compréhension.

0 votes

Il y a aussi (je pense que c'est peut-être 2.7+) le décorateur @classmethod, qui vaut la peine d'être examiné. Une discussion intéressante ici - stackoverflow.com/questions/12179271/

14voto

KennyTM Points 232647

Vous déclarez une variable locale, pas une variable de classe. Pour définir une variable d'instance (attribut), utilisez

class Example(object):
    def the_example(self):
        self.itsProblem = "problem"  # <-- remember the 'self.'

theExample = Example()
theExample.the_example()
print(theExample.itsProblem)

Pour définir un variable de classe (aussi appelé membre statique), utilisez la fonction

class Example(object):
    def the_example(self):
        Example.itsProblem = "problem"
        # or, type(self).itsProblem = "problem"
        # depending what you want to do when the class is derived.

1 votes

Sauf que les variables de classe sont déclarées une fois en au niveau de la classe . Votre façon de faire le réinitialisera à chaque instanciation, ce n'est vraiment pas ce que vous voulez. Voir aussi stackoverflow.com/questions/2709821/python-self-explained pour connaître la raison d'être du self explicite.

10voto

andrew pate Points 54

Si vous avez une fonction d'instance (c'est-à-dire une fonction qui reçoit self), vous pouvez utiliser self pour obtenir une référence à la classe en utilisant self.__class__

Par exemple, dans le code ci-dessous, tornado crée une instance pour gérer les requêtes get, mais nous pouvons nous emparer de la fonction get_handler et l'utiliser pour contenir un client riak afin de ne pas avoir à en créer un pour chaque requête.

import tornado.web
import riak

class get_handler(tornado.web.requestHandler):
    riak_client = None

    def post(self):
        cls = self.__class__
        if cls.riak_client is None:
            cls.riak_client = riak.RiakClient(pb_port=8087, protocol='pbc')
        # Additional code to send response to the request ...

0 votes

C'est un très bon exemple pour démontrer la question du titre original du PO. En fait, l'exemple de l'OP ne correspond pas au titre et les autres réponses font référence à l'exemple. Quoi qu'il en soit, c'est la meilleure façon d'accéder à une variable de niveau classe car elle ne viole pas le principe DRY. Comme certains des autres exemples le font. Il est préférable d'utiliser self.__class__ au lieu de répéter le nom de la classe. Cela permet au code d'être à l'épreuve du futur, de faciliter le refactoring et si vous osez utiliser les sous-classes, cela peut aussi avoir des avantages.

0 votes

Le lecteur doit être averti que l'utilisation d'un gestionnaire comme ci-dessus peut entraîner des problèmes non seulement dans les applications non monofilaires. Plusieurs instances de la classe pourraient en théorie utiliser le même gestionnaire en parallèle, et si le gestionnaire n'est pas conçu pour cela, ce qui dépend de sa structure interne, il pourrait ne pas fonctionner. Dans une application à un seul fil, "en parallèle" signifie que la première instance de la classe n'a pas fini d'utiliser le gestionnaire et qu'une deuxième instance commence à l'utiliser. Dans ce cas, il peut être conseillé d'utiliser une variable d'instance à la place.

0voto

user1587329 Points 91

Si vous avez un @classmethod méthode statique vous avez toujours la classe comme premier paramètre :

class Example(object):
    itsProblem = "problem"

    @classmethod
    def printProblem(cls):
        print(cls.itsProblem)

Example.printProblem()

0voto

mayor Points 11

Implémentez l'instruction de retour comme dans l'exemple ci-dessous ! Vous devriez être bon. J'espère que cela aidera quelqu'un

class Example(object):
    def the_example(self):
        itsProblem = "problem"
        return itsProblem 

theExample = Example()
print theExample.the_example()

1 votes

Vous devriez corriger l'indentation de votre code. Il existe également des réponses supérieures à cette question et votre réponse est une variation basique de ces réponses, pas une solution alternative...

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