简体   繁体   English

Python中的__setattr__函数

[英]__setattr__ function in Python

I am trying to understand the concept of delegation in Python by using the getattr and setattr function . 我试图通过使用getattr和setattr函数来理解Python中委托的概念。 By basic idea is to first set the value of the attribute 'lang' in the Person class through the class Professional and then retrieve the same. 基本思想是首先通过Professional类在Person类中设置属性'lang'的值,然后再检索该值。 The problem is that the result is an infinite loop. 问题在于结果是无限循环。

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__ is called for all attribute setting. 所有属性设置将调用__setattr__ This includes the self.person = Person() call in __init__ : 这包括__init__self.person = Person()调用:

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

This'll call self.__setattr__('person', Person()) , which in turn tries to access self.person , which then calls self.__getattr__('person') because there is no such attribute yet. 这将称为self.__setattr__('person', Person()) ,后者继而尝试访问self.person ,然后再调用self.__getattr__('person')因为尚无此属性。 And in __getattr__ you then end up in an infinite loop as you try to continually access self.person . 然后在__getattr__中,当您尝试不断访问self.person ,您将self.person无限循环。

You could test for the specific person attribute in __setattr__ (and delegate that to the base implementation): 您可以在__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)

You probably also want to add a test in __getattr__ ; 您可能还想在__getattr__添加测试; if it is called with person , then that attribute hasn't been set yet and an AttributeError should be raised: 如果使用person调用,则该属性尚未设置,应引发AttributeError

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

The __setattr__ and __getattr__ also apply before your instance is fully initialized. 实例完全初始化之前, __getattr__ __setattr____getattr__也适用。 In this case, your line self.person = Person() , calls __setattr__ . 在这种情况下,您的一行self.person = Person()调用__setattr__ This then calls __getattr__ (because self.person is not yet defined), which then recursively calls __getattr__ again (for the same reason). 然后调用__getattr__ (因为self.person尚未定义),然后再递归调用__getattr__ (出于相同的原因)。

There are a few ways around this. 有几种解决方法。 Perhaps the simplest is to circumvent the __setattr__ call on the initial self.person assignment by doing, for instance super().__setattr__('person', Person()) . 也许最简单的方法是通过执行例如super().__setattr__('person', Person())来规避对初始self.person分配的__setattr__调用。

In general, you need to be careful when using these methods, since they may be called more often than you realize. 通常,使用这些方法时需要小心,因为调用它们的次数可能比您想像的要多。 If your special handling applies to only a few certain attributes, you may want to use a property instead. 如果特殊处理仅适用于某些特定属性,则可能需要使用property

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM