__setattr__ Python 中的函数

__setattr__ function in Python

我试图通过使用 getattr 和 setattr 函数来理解 Python 中委托的概念。基本思路是先通过 class Professional 在 Person class 中设置属性 '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)

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

有几种解决方法。也许最简单的方法是绕过 __setattr__ 对初始 self.person 赋值的调用,例如 super().__setattr__('person', Person()).

一般来说,您在使用这些方法时需要小心,因为它们的调用频率可能比您意识到的要高。如果您的特殊处理仅适用于少数特定属性,您可能需要使用 property

__setattr__ 调用all 属性设置。这包括 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.

时,您将陷入无限循环

您可以测试 __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)