2016-05-10 11 views
1

私は、getattrとsetattr関数を使って、Pythonの委譲の概念を理解しようとしています。基本的な考え方は、Personクラスの属性 'lang'の値をまずProfessionalクラスを通して設定し、それを取得することです。問題は、結果が無限ループであることです。あなたのインスタンスが完全に初期化される前に、Pythonの__setattr__関数

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) 

答えて

3

__setattr__すべて属性設定と呼ばれます。

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

これはself.__setattr__('person', Person())と呼ぶことにします、順番にself.personにアクセスしようとする、そのような属性がまだ存在しないため、その後self.__getattr__('person')を呼び出します。これは__init__self.person = Person()コールが含まれています。そして__getattr__では、あなたは無限ループに終わり、いつもself.personにアクセスしようとします。

あなたは __setattr__内の特定の person属性をテスト(ベースの実装に委任すること)ができ

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) 

あなたはおそらくも__getattr__にテストを追加したいです。それはpersonで呼び出された場合、その属性が設定されていないとAttributeErrorを提起する必要があります。

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

__getattr__も適用されます。この場合、self.person = Person()という行は__setattr__となります。これは__getattr__を呼び出します(self.personはまだ定義されていないため)、再帰的に同じ理由で__getattr__を呼び出します。

これを回避する方法はいくつかあります。おそらく最も簡単なのは、例えばsuper().__setattr__('person', Person())のように、self.personの最初の呼び出しで__setattr__コールを迂回することです。

一般的に、これらのメソッドを使用する際には、わかりやすく呼び出される可能性があるため、注意する必要があります。あなたの特殊な取り扱いがいくつかの特定の属性にのみ適用される場合は、代わりにpropertyを使用するとよいでしょう。

+0

[OK]を、その場合には、私は専門 –

+0

の__init__メソッド内から人のオブジェクトを初期化することはできませんので、@ SubhayanBhattacharya:できます。なぜあなたはできないと思いますか? – BrenBarn

+0

私はその呼び出しを置き換えることを考えていました:self.person = Person()のようなもの:self .__ dict __ ['person'] = Person()。これは、呼び出しを__setattr__にルーティングすべきではありません。私は正しいですか? –