2009-08-09 7 views
12

Je suis intéressé par une discussion sur les attributs de classe en Python. Par exemple, qu'est-ce qu'un bon cas d'utilisation pour les attributs de classe? Pour la plupart, je ne peux pas trouver un cas où un attribut de classe est préférable à l'utilisation d'un attribut de niveau module. Si c'est vrai, alors pourquoi les avoir autour? Le problème que j'ai avec eux, c'est qu'il est presque trop facile d'écraser une valeur d'attribut de classe par erreur, et ensuite votre valeur "globale" est devenue un attribut d'instance locale.Classe Python et attributs de module

Ne hésitez pas à commenter sur la façon dont vous gérer les situations suivantes:

  1. valeurs constantes utilisées par une classe et/ou sous-classes. Cela peut inclure des clés de dictionnaire "nombre magique" ou des index de liste qui ne changeront jamais, mais qui peuvent nécessiter une initialisation unique.
  2. Attribut de classe par défaut, qui, dans de rares occasions, a été mis à jour pour une instance spéciale de la classe.
  3. Structure de données globale utilisée pour représenter un état interne d'une classe partagée entre toutes les instances.
  4. Classe qui initialise un certain nombre d'attributs par défaut, sans être influencée par les arguments du constructeur.

Quelques Related Posts:
Difference Between Class and Instance Attributes

+0

devrait être community wiki – SilentGhost

Répondre

7

# 4: Je ne classe utiliser des attributs pour initialiser instance par défaut les attributs (ceux que vous normalement mis dans __init__). Par exemple:

class Obj(object): 
    def __init__(self): 
     self.users = 0 

jamais:

class Obj(object): 
    users = 0 

Pourquoi? Parce qu'il est incohérent: il ne fait pas ce que vous voulez quand vous attribuez quoi que ce soit, mais un objet invariant:

class Obj(object): 
    users = [] 

provoque les utilisateurs liste à partager entre tous les objets, qui dans ce cas n'est pas voulu. Il est difficile de les diviser en attributs et affectations de classe en __init__ en fonction de leur type, donc je les mets toujours tous en __init__, ce que je trouve plus clair quand même. Comme pour le reste, je place généralement des valeurs spécifiques à la classe à l'intérieur de la classe.Ce n'est pas tellement parce que les globales sont "mauvais" - ils ne sont pas si gros que dans certaines langues, car ils sont toujours étendus au module, sauf si le module lui-même est trop grand - mais si le code externe veut y accéder, il est pratique d'avoir toutes les valeurs pertinentes au même endroit. Par exemple, dans module.py:

class Obj(object): 
    class Exception(Exception): pass 
    ... 

puis:

from module import Obj 

try: 
    o = Obj() 
    o.go() 
except o.Exception: 
    print "error" 

En plus de permettre les sous-classes pour changer la valeur (qui ne sont pas toujours voulu de toute façon), cela signifie que je n'ai pas importer laborieusement des noms d'exception et un tas d'autres choses nécessaires pour utiliser Obj. "du module import Obj, ObjException, ..." devient ennuyeux rapidement.

2

Les attributs de classe sont souvent utilisés pour permettre les valeurs par défaut impérieuses sous-classes. Par exemple, BaseHTTPRequestHandler a des constantes de classe sys_version et server_version, la dernière par défaut étant "BaseHTTP/" + __version__. SimpleHTTPRequestHandler remplace la version_serveur par "SimpleHTTP/" + __version__.

+0

Cependant, la méthode d'accès de l'attribut class serait un facteur si cela a fonctionné ou non. Une autre raison pour laquelle les attributs de classe sont dangereux. – cmcginty

+0

Quelle "méthode d'accès"? cls.version, self.version, getattr, donneront toutes la bonne réponse. * Définir en classe pour autoriser les remplacements * fonctionne aussi bien pour les données que pour le code - donc, Casey, pourquoi penses-tu que c'est dangereux pour les données mais bien pour le code ?! –

+0

L'utilisation de Class.value au lieu de self.value dans une méthode pour accéder à l'attribut empêchera le remplacement.Parfois c'est le cas désiré, d'autres fois non. – cmcginty

1

L'encapsulation est un bon principe: lorsqu'un attribut est à l'intérieur de la classe à la place d'être dans la portée globale, cela donne des informations supplémentaires aux personnes lisant le code. Dans vos situations 1-4, j'éviterais autant que possible les globales, et préfèrerais utiliser les attributs de classe, qui permettent de bénéficier de l'encapsulation.

3

ce qui est un bon cas d'utilisation pour les attributs de classe

Case 0. Les méthodes de classe ne sont que des attributs de classe. Il ne s'agit pas seulement d'une similitude technique: vous pouvez accéder aux méthodes de classe et les modifier à l'exécution en leur affectant des appels.

Cas 1. Un module peut facilement définir plusieurs classes. Il est raisonnable de tout encapsuler environ class A en A... et tout sur class B en B.... Par exemple,

# module xxx 
class X: 
    MAX_THREADS = 100 
    ... 

# main program 
from xxx import X 

if nthreads < X.MAX_THREADS: ... 

Cas 2. Cette classe a beaucoup d'attributs par défaut qui peuvent être modifiés dans une instance. Ici, la possibilité de laisser l'attribut "défaut global" est une fonctionnalité, pas un bogue.

class NiceDiff: 
    """Formats time difference given in seconds into a form '15 minutes ago'.""" 

    magic = .249 
    pattern = 'in {0}', 'right now', '{0} ago' 

    divisions = 1 

    # there are more default attributes 

On crée instance de NiceDiff d'utiliser la mise en forme existante ou légèrement modifiée, mais un radiophare dans une autre langue sous-classes de la classe pour mettre en œuvre certaines fonctions dans une redéfinition de façon et fondamentalement différentes constantes:

class Разница(NiceDiff): # NiceDiff localized to Russian 
    '''Из разницы во времени, типа -300, делает конкретно '5 минут назад'.''' 

    pattern = 'через {0}', 'прям щас', '{0} назад' 

Votre cas:

  • constantes - vous s, je les ai mis en classe. C'est étrange de dire self.CONSTANT = ..., donc je ne vois pas un gros risque de les écraser.
  • Attribut par défaut - mélangé, comme ci-dessus peut aller à la classe, mais peut également aller à __init__ en fonction de la sémantique.
  • Structure de données globale --- passe à la classe si utilisé seulement par la classe, mais peut également aller au module, dans les deux cas doit être très bien documenté.
Questions connexes