[英]__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.