Python 如何正确使用_usetattr _;,避免无限递归

Python 如何正确使用_usetattr _;,避免无限递归,python,python-2.7,getattr,setattr,Python,Python 2.7,Getattr,Setattr,我想定义一个包含read和write方法的类,可以如下调用: instance.read instance.write instance.device.read instance.device.write class MyTest(object): def __init__(self, x): self.x = x def __setattr__(self, name, value): if name=="device":

我想定义一个包含
read
write
方法的类,可以如下调用:

instance.read
instance.write
instance.device.read
instance.device.write
class MyTest(object):
    def __init__(self, x):
        self.x = x

    def __setattr__(self, name, value):
        if name=="device":
            print "device test"
        else:
            setattr(self, name, value)

test = MyTest(1)
为了不使用交错类,我的想法是覆盖
\uuu getattr\uuuuuuuuuu
\uuuuuuu setattr\uuuuuuuuu
方法,并检查给定名称是否为
设备
,以将返回重定向到
self
。但是我遇到了一个问题,给出了无限递归。示例代码如下所示:

instance.read
instance.write
instance.device.read
instance.device.write
class MyTest(object):
    def __init__(self, x):
        self.x = x

    def __setattr__(self, name, value):
        if name=="device":
            print "device test"
        else:
            setattr(self, name, value)

test = MyTest(1)
正如在
\uuuuu init\uuuuuuuuu
中,代码试图创建一个新的属性
x
,它调用
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu setattr
,再次调用
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。我需要如何更改此代码,在这种情况下,将创建一个新的
self
属性
x
,并保存值
1

或者有没有更好的方法来处理像
instance.device.read
这样的调用以“映射”到
instance.read


因为总是有关于为什么的问题:我需要创建
xmlrpc
调用的抽象,可以为其创建非常简单的方法,如
myxmlrpc.instance、device.read
和类似的方法。我需要对其进行“模拟”以模拟此类多点方法调用。

您必须调用父类
\uuuu setattr\uuu
方法:

class MyTest(object):

    def __init__(self, x):
        self.x = x

    def __setattr__(self, name, value):
        if name=="device":
            print "device test"
        else:
            super(MyTest, self).__setattr__(name, value)
            # in python3+ you can omit the arguments to super:
            #super().__setattr__(name, value)
关于最佳实践,由于您计划通过
xmlrpc
使用此方法,因此我认为在方法内部进行此操作可能更好

一个快速而肮脏的方法就是简单地做:

class My(object):
    def __init__(self):
        self.device = self

或者您可以从
\uuuuuu setattr\uuuuuuuu()内部修改
self.\uuuuu dict\uuuuuuuuuuuuuuuu


您也可以使用对象

class TestClass:
    def __init__(self):
            self.data = 'data'
    def __setattr__(self, name, value):
            print("Attempt to edit the attribute %s" %(name))
            object.__setattr__(self, name, value)

或者您可以只使用@property:

类MyTest(对象):
定义初始化(self,x):
self.x=x
@财产
def设备(自身):
回归自我

如果不想指定哪些属性可以设置,哪些属性不能设置,可以拆分类以将get/set挂钩延迟到初始化之后:

类MyTest(对象):
定义初始化(self,x):
self.x=x
self.\uuuuu类\uuuuu=\uMyTestWithHooks
类_MyTestWithHooks(MyTest):
定义设置属性(自身、名称、值):
...
def _ugetattr _;(self,name):
...
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
a=MyTest(12)
...

正如代码中所指出的,您将需要实例化MyTest,因为用hooks实例化_MyTestWithHooks将导致与以前相同的无限递归问题。

我喜欢快速而肮脏的方式:只需一行代码即可获得所需的行为!谢谢这句话在《巴库留》中也提到过。你能解释一下这句话到底在做什么吗?super(MyTest,self)。\uuuuu setattr\uuuuuuu(name,value)@Shahryar我的答案的第一行解释了这一点。它正在调用父类
\uuuuu setattr\uuuu
方法
super(Class,instance)
创建一个对象,该对象能够在
instance
上调用
Class
的父类的方法。在这种情况下,您也可以执行
object.\uuuuu setattr\uuuuu(实例、名称、值)
,但是
super
能够正确处理多重继承,应该是首选。@Shahryar,因为这甚至不是有效的python语法
self[name]=value
相当于
self.\uuuuu setitem\uuuuuu(name,value)
,大多数情况下未实现。如果您尝试使用
setattr
内置函数,那么会发生
setattr(self,name-value)
将递归调用
\uuuuuuuu setattr\uuuuuuu
并最终进入无限循环。为什么不调用
setattr(self,“\uu dict\uuuuuuuuuuu”,value)
,重复最初的无限递归问题?因为这不是设置
\uuuuu dict\uuuuu
属性,gut获取它,然后在返回的dict上设置一个项,例如,它调用类似以下内容:
getattr(self,“\uu dict\uuuuuu”)。\uuuuu setitem\uuuuuu(名称,值)
使用@propertyth这一内置类可以更轻松地解决此用例。所有类都继承自该类(即使是
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。请注意,所有对象都有uuu setattr_uuu方法,甚至一个字符串:
“a”。uuu setattr_uuu
,因为所有类都继承自内置类
对象
偶数字符串