2010-06-29 22 views
12

Je viens de passer trop de temps sur un bug comme ce qui suit:Python: Une classe peut-elle interdire aux clients de définir de nouveaux attributs?

>>> class Odp(): 
    def __init__(self): 
     self.foo = "bar" 


>>> o = Odp() 
>>> o.raw_foo = 3 # oops - meant o.foo 

J'ai une classe avec un attribut. J'essayais de le régler et je me demandais pourquoi cela n'avait aucun effet. Ensuite, je suis retourné à la définition de classe d'origine, et j'ai vu que l'attribut était nommé quelque chose de légèrement différent. Ainsi, je créais/établissais un nouvel attribut au lieu de celui destiné à.

Tout d'abord, n'est-ce pas exactement le type d'erreur que les langages statiquement typés sont censés empêcher? Dans ce cas, quel est l'avantage du typage dynamique?

Deuxièmement, y a-t-il un moyen que j'aurais pu interdire lors de la définition Odp, et ainsi me suis sauvé le problème?

+1

Possible duplicate: http://stackoverflow.com/questions/3079306/how-to-protect-againt-typos-when-setting-value-for-class-members – detly

Répondre

16

Vous pouvez mettre en œuvre une méthode __setattr__ dans le but - qui est beaucoup plus robuste que le __slots__ qui est souvent mal utilisé dans le but (par exemple, __slots__ est automatiquement « perdu » lorsque la classe est héritée de, alors que __setattr__ survive à moins explicitement surchargé).

def __setattr__(self, name, value): 
    if hasattr(self, name): 
    object.__setattr__(self, name, value) 
    else: 
    raise TypeError('Cannot set name %r on object of type %s' % (
        name, self.__class__.__name__)) 

Vous devez vous assurer que le hasattr réussit pour les noms que vous faites veulent être en mesure de définir, par exemple en définissant les attributs à un niveau de classe ou en utilisant object.__setattr__ dans votre méthode __init__ plutôt que l'attribution directe d'attributs. (Pour interdire de définir des attributs sur une classe plutôt que sur ses instances vous devrez définir une métaclasse personnalisée avec une méthode spéciale similaire).

+0

Pourquoi avez-vous choisi 'TypeError'? Peut-être injustement, j'avais "AttributeError" à l'esprit. – n611x007

+2

"ne prend pas en charge les messages d'affectation XX" (par exemple pour les articles) utilisez 'TypeError', les termes" has no attribute XX "utilisant" AttributeError' "ne sont pas parfaits. –