web-dev-qa-db-fra.com

Variables d’instance et variables de classe dans Python

J'ai Python, dont je n'ai besoin que d'une instance à l'exécution, il serait donc suffisant d'avoir les attributs une seule fois par classe et non par instance. S'il y avait plus d'une instance (ce qui ne se produira pas), toutes les instances devraient avoir la même configuration. Je me demande laquelle des options suivantes serait meilleure ou plus "idiomatique" Python.

Variables de classe:

class MyController(Controller):

  path = "something/"
  children = [AController, BController]

  def action(self, request):
    pass

Variables d'instance:

class MyController(Controller):

  def __init__(self):
    self.path = "something/"
    self.children = [AController, BController]

  def action(self, request):
    pass
113
deamon

De toute façon, si vous n’avez qu’une seule instance, il est préférable de créer toutes les variables par instance, tout simplement parce qu’elles seront consultées (un peu) plus rapidement (un niveau de "recherche" de moins en raison de "l’héritage" de la classe à l’instance), et il n'y a aucun inconvénient à peser contre ce petit avantage.

150
Alex Martelli

faisant écho aux conseils de Mike et d'Alex et en ajoutant ma propre couleur ...

utilisant des attributs d'instance sont les Python typiques, plus idiomatiques. Les attributs de classe ne sont pas souvent utilisés - du moins pas dans le code de production de mes 13 dernières années consécutives de Python. il en va de même pour les méthodes statiques et les méthodes de classe ... mais cela n’est pas très courant sauf s’il existe un cas d’utilisation spécifique ou un programmeur aberrant qui veut montrer qu’il connaît un coin obscur de la programmation Python.

alex mentionne dans sa réponse que l'accès sera (un peu) plus rapide en raison d'un niveau de recherche inférieur ... permettez-moi de préciser pour ceux qui ne savent pas encore comment cela fonctionne, il est très similaire à l'accès variable - - la recherche s'effectue dans cet ordre:

  1. des locaux
  2. non locaux
  3. globals
  4. éléments intégrés

pour l'accès aux attributs, la commande est la suivante:

  1. exemple
  2. classe
  3. classes de base déterminées par le MRO (ordre de résolution de la méthode)

dans l'exemple ci-dessus, supposons que vous cherchiez l'attribut path. quand il rencontre une référence comme "self.path ", Python examinera d'abord les attributs de l'instance pour rechercher une correspondance; s'il échoue, il vérifie la classe à partir de laquelle l'objet a été instancié. Enfin, il effectuera une recherche dans les classes de base. comme alex l'a indiqué, si votre attribut est trouvé dans l'instance, il ne sera pas renvoyé à la classe, d'où votre petit gain de temps.

cependant, si vous insistez sur les attributs de classe, vous devrez abandonner cette petite performance, o, votre autre alternative consiste à faire référence à l'objet via la classe au lieu de l'instance, par exemple, MyController.path au lieu de self.path. c'est une recherche directe qui contournera la recherche différée, mais comme le mentionne alex ci-dessous, il s'agit d'une variable globale. Vous perdez donc ce bit que vous pensiez sauver (à moins de créer une référence locale au nom de la classe [global] ).

42
wescpy

En cas de doute, vous voulez probablement un attribut d'instance.

Les attributs de classe sont mieux réservés aux cas spéciaux où ils ont un sens. Le seul cas d'utilisation très courant concerne les méthodes. Il n'est pas inhabituel d'utiliser les attributs de classe pour les constantes en lecture seule que les instances doivent connaître (bien que le seul avantage de cela est que vous souhaitez également un accès à partir de extérieur de la classe ), mais vous devriez certainement faire attention à ne pas y stocker d’état, ce qui est rarement ce que vous voulez. Même si vous n'avez qu'une seule instance, vous devez écrire la classe comme n'importe quelle autre, ce qui signifie généralement que vous utilisez des attributs d'instance.

24
Mike Graham

Même question à Performance d'accès aux variables de classe en Python - le code ici adapté de @Edward Loper

Les variables locales sont les plus rapides d'accès. Elles sont liées aux variables de module, suivies des variables de classe, suivies des variables d'instance.

Vous pouvez accéder aux variables depuis 4 portées:

  1. Variables d'instance (self.varname)
  2. Variables de classe (Classname.varname)
  3. Variables de module (VARNAME)
  4. Variables locales (varname)

Le test:

import timeit

setup='''
XGLOBAL= 5
class A:
    xclass = 5
    def __init__(self):
        self.xinstance = 5
    def f1(self):
        xlocal = 5
        x = self.xinstance
    def f2(self):
        xlocal = 5
        x = A.xclass
    def f3(self):
        xlocal = 5
        x = XGLOBAL
    def f4(self):
        xlocal = 5
        x = xlocal
a = A()
'''
print('access via instance variable: %.3f' % timeit.timeit('a.f1()', setup=setup, number=300000000) )
print('access via class variable: %.3f' % timeit.timeit('a.f2()', setup=setup, number=300000000) )
print('access via module variable: %.3f' % timeit.timeit('a.f3()', setup=setup, number=300000000) )
print('access via local variable: %.3f' % timeit.timeit('a.f4()', setup=setup, number=300000000) )

Le résultat:

access via instance variable: 93.456
access via class variable: 82.169
access via module variable: 72.634
access via local variable: 72.199
3
robertcollier4