2016-12-23 6 views
0

den folgenden Code zu haben:Python Ignorieren Eltern __setattr__

class Parent(): 
    def __init__(self): 
     pass 

    def __setattr__(self, name, value): 
     raise RuntimeError() 


class Child(Parent): 
    def __init__(self): 
     super().__init__() 
     self.y = 2 


if __name__ == '__main__': 
    print(Child().y) 

und die folgenden Bedingungen/Annahmen:

  • Klasse Parent hat etwas in seiner __setattr__ Implementierung, die Child hebt eine Ausnahme macht, wenn neue Einstellung Klassenattribute.
  • Klasse Parent Quellcode kann nicht geändert werden (könnte Affe-Patched sein, aber es ist eine externe Abhängigkeit).

Gibt es eine Möglichkeit, das zu beheben? Könnte ich die Parent Implementierung __setattr__ vor der Einstellung y "Müll"? Kann ich diese Methode in Child erneut implementieren, damit es wie erwartet funktioniert?

object.__setattr__(self, 'y', 2) 

Beachten Sie, dass diese vollständig umgeht Parent ‚s __setattr__, so dass dies tun könnten verschiedene Invarianten in Parent brechen:

+1

Sie überlasten '__setattr__' in der' Child' Klasse. –

+0

@hiroprotagonist: Ja, ich habe versucht mit 'object .__ setattr__', das hat nicht funktioniert, und das ist, wenn ich die Frage gestellt habe. Jetzt kenne ich den Unterschied zwischen 'super' und 'super (Eltern, selbst) .__ setattr__'. :-) – Peque

+0

ich meinte eigentlich was ich als antwort unten gepostet habe; Rufen Sie nicht '__setattr__' auf' Objekt' auf, sondern nur auf 'self'. dies umgeht alle "__setatrs__", die in der MRO-Kette definiert worden sein könnten. –

Antwort

2

Sie können die Methode umgehen, indem Sie im MRO die nächste__setattr__ Methode aufrufen. Sagen super()VergangenheitParent aussehen:

class Child(Parent): 
    def __init__(self): 
     super().__init__() 
     self.y = 2 

    def __setattr__(self, name, value): 
     # skip Parent.__setattr__ 
     super(Parent, self).__setattr__(name, value) 

Beachten Sie, dass Sie sollten in der Regel nicht eine andere Klasse von der aktuellen in super() verwenden; Dies ist eine geeignete Ausnahme, enthält jedoch einen Kommentar in Ihrem Produktionscode, um zu erklären, warum Sie dies tun.

Sie könnteobject.__setattr__(self, name, value) verwenden, aber nur, wenn Parent erbt direkt von object und nicht von einer anderen Klasse, die auch __setattr__ implementiert. Mit super() finden Sie die nächste__setattr__ Implementierung in Ihrem Vererbungsbaum.

Demo:

>>> class Parent(): 
...  def __init__(self): 
...   pass 
...  def __setattr__(self, name, value): 
...   raise RuntimeError() 
... 
>>> class Child(Parent): 
...  def __init__(self): 
...   super().__init__() 
...   self.y = 2 
...  def __setattr__(self, name, value): 
...   # skip Parent.__setattr__ 
...   super(Parent, self).__setattr__(name, value) 
... 
>>> Child().y 
2 
+0

Sie immer gelingt, mit einer vollständigeren Antwort zu kommen. Vielen Dank! lernt immer wieder einen neuen "Trick". –

+0

Ich habe es mit 'object .__ setattr__' versucht, aber irgendwie ist das gescheitert (obwohl mein, jetzt weiß ich, ein schlecht reduziertes Code-Beispiel damit funktioniert). Irgendwie kamst du mit einer tatsächlichen Lösung und einer guten Antwort auf meine schlechte Frage (lol). – Peque

+0

Vielen Dank für Ihre Antwort aktualisiert und Ihre Beratung. Vielleicht möchten Sie einen Kommentar wie @ Bakuriu hinzufügen, der erklärt, dass es einen tatsächlichen Unterschied zwischen "object .__ setattr__" und Ihrem Ansatz gibt (und das muss der Grund sein, warum der erste bei mir nicht funktionierte, als ich es versuchte). Nur um es vollständiger zu machen, und wenn Sie Zeit haben. ;-) – Peque

1

können Sie die Basis __setattr__ aufrufen.

+0

Oder besser: benutze 'super (Parent, self) .__ setattr__' auf diese Weise, wenn es mehrere Klassen zwischen' object' und 'Parent' gibt und du * potenziell * das, was sie damit tun, bewahren kannst , während 'object' alle * Implementierungen überspringt. – Bakuriu

+0

Ich versuchte es mit 'Objekt.__setattr__', bevor er fragt, aber irgendwie, dass versagt (obwohl mein, jetzt weiß ich, schlecht reduziertes Codebeispiel mit dem funktioniert). Sorry für eine schlechte Frage und danke für eine korrekte Antwort. :-) – Peque

+0

@Bakuriu Guter Punkt, aber beachten Sie, dass 'Super (Elternteil, Selbst-) ...' wird auch die '__setattr__' Implementierungen in Mixins liegt zwischen' Child' und 'Parent', wenn überhaupt überspringen. Man kann nicht überspringen 'Eltern .__ setattr__' sowieso ohne ein sorgfältiges Verständnis das, was es tut. Ein Teil dieses Verständnis ist, herauszufinden, welche '__setattr__' Sie angerufen werden soll, und nannte es. Wenn ich diese Art von Magie mache, finde ich es am besten so explizit wie möglich zu sein. – user4815162342

0

eine __setattr__ Methode in Child Hinzufügen können Sie die man in Parent ignorieren:

class Child(Parent): 
    ... 
    def __setattr__(self, name, value): 
     # do whatever you want; 
Verwandte Themen