2016-05-10 9 views
1

Ich versuche, das Konzept der Delegation in Python zu verstehen, indem Sie die Funktionen getattr und setattr verwenden. Grundidee ist, zunächst den Wert des Attributs 'lang' in der Person-Klasse durch die Klasse Professional zu setzen und dann dasselbe zu erhalten. Das Problem ist, dass das Ergebnis eine Endlosschleife ist.__setattr__ Funktion in Python

class Person: 
    def __init__(self,name='Subhayan',job='Engineer',unique='Unique'): 
     print ("Inside init function of Person") 
     self.name = name 
     self.job = job 
     self.salary = 50000 
     self.lang = "Perl" 

    def __setattr__(self,att,value): 
     self.__dict__[att] = value 


class Professional: 
    job = 'Engineer' 
    salary = 75000 
    def __init__(self): 
     print ("Inside Professional init function") 
     self.person = Person() 

    def __getattr__(self,attr): 
     print ("Calling the getattr function") 
     return getattr(self.person, attr) 

    def __setattr__(self,att,value): 
     # print ("calling the setattr function setting the value of %s to %s" %(attr,value)) 
     self.person.__setattr__(self,att,value) 


if __name__ == '__main__': 
    print ("Calling the script as main") 
    Prof = Professional() 
    print ("Salary is",Prof.salary) 
    print ("name is",Prof.__class__) 
    print ("Setting the value of lang") 
    Prof.lang = 'Python' 
    value = Prof.lang 
    print ("The value of lang is ;",value) 

Antwort

3

__setattr__ wird für alle Attributeinstellung aufgerufen. Dazu gehört auch die self.person = Person() Anruf in __init__:

def __init__(self): 
    print ("Inside Professional init function") 
    self.person = Person() 

Diese self.__setattr__('person', Person()) nennen werde, die wiederum versucht self.person, zuzugreifen, die dann self.__getattr__('person') nennt, weil es noch kein solches Attribut ist. Und in __getattr__ enden Sie dann in einer Endlosschleife, während Sie versuchen, fortlaufend auf self.person zuzugreifen.

Sie für das spezifische person Attribut in __setattr__ testen konnte (und übertragen, der an der Basis-Implementierung):

def __setattr__(self, att, value): 
    # print ("calling the setattr function setting the value of %s to %s" %(attr,value)) 
    if att == 'person': 
     return super().__setattr__(att, value) 
    return self.person.__setattr__(self,att,value) 

Sie wahrscheinlich auch einen Test in __getattr__ hinzufügen möchten; wenn es mit person aufgerufen wird, dann hat das Attribut noch nicht festgelegt und ein AttributeError soll erhöht werden:

def __getattr__(self,attr): 
    print ("Calling the getattr function") 
    if attr == 'person': 
     raise AttributeError('person') 
    return getattr(self.person, attr) 
1

Die __setattr__ und __getattr__ gelten auch vor Ihrer Instanz vollständig initialisiert ist. In diesem Fall ruft Ihre Leitung self.person = Person()__setattr__ auf. Dies ruft dann __getattr__ auf (weil self.person noch nicht definiert ist), die dann wieder rekursiv __getattr__ (aus dem gleichen Grund) ruft.

Es gibt verschiedene Möglichkeiten. Am einfachsten ist es vielleicht, den __setattr__ Anruf auf der ursprünglichen self.person Zuweisung zu umgehen, zum Beispiel super().__setattr__('person', Person()).

Im Allgemeinen müssen Sie vorsichtig sein, wenn Sie diese Methoden verwenden, da sie häufiger aufgerufen werden können, als Sie wissen. Wenn Ihre spezielle Handhabung nur für einige bestimmte Attribute gilt, können Sie stattdessen eine property verwenden.

+0

Ok, so in diesem Fall ich nicht ein Objekt der Person aus dem Innern der __init__ Methode of Professional –

+0

initialisieren kann @ SubhayanBattacharya: Sicher kannst du. Warum denkst du, kannst du nicht? – BrenBarn

+0

Ich dachte daran, den Aufruf zu ersetzen: self.person = Person() mit etwas wie: self .__ dict __ ['person'] = Person(). Dies sollte keine Anrufe an __setattr__ weiterleiten. Hab ich recht ? –