Je rencontre ce code aujourd'hui, et cela semble déroutant
class ClassOne: def __init__(self,some_object): self.not_important_attribute=some_object class ClassTwo: def __init__(self,some_object): self.tmp=ClassOne(some_object) def __getattr__(self,attr): return getattr(self.tmp,attr) a=ClassTwo('not_important_string') print(getattr(a,'undefined_attribute',3))
Lorsque nous utilisons getattr
à la dernière ligne, nous déclenchons le __getattr__
dans la Sous-classe
, puis déléguez à la fonction getattr (self.tmp, attr)
qui lèvera une exception si l'attribut n'est pas défini et qu'aucune valeur par défaut n'a été donnée. Mais comment la valeur 3 à la dernière ligne passe-t-elle toujours par tout le processus, et revient finalement à la fonction getattr (a, 'undefined_attribute', 3)
?. Parce que nous n'avions pas d'espace pour la valeur par défaut lorsque nous déléguons getattr (self.tmp, attr)
, comment est-ce possible?
4 Réponses :
Dans votre cas,
getattr(self.tmp,attr)
lève AttributeError et si getattr a un troisième argument (valeur par défaut), alors il renvoie la valeur par défaut au lieu de lever AttributeError
"si getattr a un troisième argument" De quel getattr vous parlez, le getattr (self.tmp, attr)
ou le getattr (a, 'undefined_attribute', 3)
en dehors de la classe.
@ TuấnĐoàn appellent tous les deux à l'attribut not_important_attribute
de la classe ClassOne
, regardez ma réponse pour plus de détails
Je parle de getattr (a, 'undefined_attribute', 3). getattr (self.tmp, attr) lève AttributeError et getattr (a, 'undefined_attribute', 3) renvoie 3 à cause de la valeur par défaut
@AndreyBerenda lorsque la méthode __getattr__
est appelée, elle retournera la valeur que nous l'avons définie à l'intérieur de la fonction, pas la valeur par défaut en dehors de la classe, vérifiez ceci
Je parle de l'impression de cas (getattr (b, 'undefined_attribute', 3))
Pas à pas pourquoi la valeur 3
est affichée:
la super classe a un attribut
not_important_attribute
et il est défini lorsque le constructeur est appelé
b = ClassOne("not_important_string") print(getattr(b,'not_important_attribute',3)) not_important_string # founds the method print(getattr(b,'any',3)) 3 # doesn't found method, returns default
Ici, dans le constructeur
ClassTwo
, vous créez une instance deClassOne
et l'enregistrez dans la variabletmp
. Cela signifie que lorsque vous remplacez__getattr__
, vous demanderez la valeur de l'attribut deClassOne
print(getattr(a,'not_important_attribute',3)) not_important_string # founds the method print(getattr(a,'any',3)) 3 #doesn't found method, returns default
C'est la même chose de faire directement:
class ClassOne: def __init__(self,some_object): self.not_important_attribute=some_object
Lorsque vous appelez getattr (a, 'undefined_attribute', 3)
, vous appelez la fonction standard python getattr et lui passez une valeur par défaut. Cela enveloppe en fait votre getattr personnalisé dans ClassTwo. Nous pouvons le voir en modifiant un petit peu getattr .
def __getattr__(self, attr, *args, **kwargs): print(args) # -> empty print(kwargs) # -> empty return getattr(self.tmp, attr)
Vous pouvez contourner ce wrapping et appeler getattr directement depuis ClassTwo, en utilisant print (a .__ getattr __ ('undefined_attribute', 3))
. Cette méthode soulèverait une exception.
Donc, essentiellement getattr (a, 'undefined_attribute', 3)
est la méthode python standard qui appelle en interne le getattr personnalisé de ClassTwo.
class ClassTwo: ... def __getattr__(self,attr): return getattr(self.tmp,attr) getattr(a,'undefined_attribute',3) method is a wrapper to call __getattribute__ and if __getattribute__ fails, it will call __getattr__. It is implemented with handling of exception AttributeError. In your case, getattr(a,'undefined_attribute',3) calls ClassTwo.__getattr__ above. It seems you think when it reaches return getattr(self.tmp,attr), it will throw errors or return some kind of errors and break and stop at that point complete. However, in python, program will pass exception up the call stack. Along the upstream of the call stack, if that exception gets handle, it will exit/complete normally. In this case, AttributeError get passed back along the call stack to getattr(a,'undefined_attribute',3). this getattr has default value for AttributeError so it returns 3 and exits normally.
Ouais, ce n'est pas un mécanisme d'héritage, je vais éditer ça
Si _ getattr_ lève AttributeError alors la fonction getattr renvoie la valeur par défaut si elle existe (dans votre cas, 3).
@AndreyBerenda Je ne suis pas sûr que ce soit correct, lorsque la méthode
__getattr__
est appelée, elle retournera la valeur que nous l'avons définie à l'intérieur de la fonction, pas la valeur par défaut en dehors de la classe, vérifiez ceci