Python中的__setattr__函数

时间:2016-05-10 07:26:20

标签: python python-3.x setattribute setattr

我试图通过使用getattr和setattr函数来理解Python中委托的概念。基本思想是首先通过类Professional在Person类中设置属性'lang'的值,然后检索相同的值。问题是结果是无限循环。

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)

2 个答案:

答案 0 :(得分:3)

__setattr__是为所有属性设置调用的。这包括self.person = Person()中的__init__电话:

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

这会打电话给self.__setattr__('person', Person()),后者会尝试访问self.person,然后调用self.__getattr__('person'),因为还没有这样的属性。在__getattr__中,当您尝试不断访问self.person时,您最终会陷入无限循环。

您可以在person中测试特定的__setattr__属性(并将其委托给基础实现):

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 :(得分:1)

在您的实例完全初始化之前,__setattr____getattr__也适用。在这种情况下,您的第self.person = Person()行会调用__setattr__。然后调用__getattr__(因为self.person尚未定义),然后再次递归调用__getattr__(出于同样的原因)。

有几种方法可以解决这个问题。也许最简单的方法是通过执行__setattr__来绕过对self.person初始super().__setattr__('person', Person())调用的property调用。

通常,在使用这些方法时需要小心,因为它们可能比您意识到的更频繁地被调用。如果您的特殊处理仅适用于少数特定属性,则可能需要使用{{1}}。