如何正确使用__ setattr__,避免无限递归

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

instance.read
instance.write
instance.device.read
instance.device.write

为了不使用交错类,我的想法是覆盖 __getattr____setattr__方法,并检查给定名称是否为 device,以将返回值重定向到 self。但我遇到了一个问题,给出了无穷递归。示例代码如下:

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)

__init__中,代码尝试创建一个新的属性 x,它调用 __setattr____setattr__再次调用 __setattr__,以此类推。我需要如何改变这个代码,在这种情况下,一个新的属性 xself创建,保持值 1

或者有什么更好的方法来处理像 instance.device.read这样被映射到 instance.read的调用?

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

83731 次浏览

必须调用父类 __setattr__方法:

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)

关于最佳实践,因为您计划通过 xml-rpc使用它,所以我认为在 _dispatch方法中使用它可能更好。

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

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

或者你可以从 __setattr__()内部修改 self.__dict__:

class SomeClass(object):


def __setattr__(self, name, value):
print(name, value)
self.__dict__[name] = value


def __init__(self, attr1, attr2):
self.attr1 = attr1
self.attr2 = attr2




sc = SomeClass(attr1=1, attr2=2)


sc.attr1 = 3

也可以使用 对象

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:

class MyTest(object):


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


@property
def device(self):
return self

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

class MyTest(object):
def __init__(self, x):
self.x = x
self.__class__ = _MyTestWithHooks


class _MyTestWithHooks(MyTest):
def __setattr__(self, name, value):
...
def __getattr__(self, name):
...


if __name__ == '__main__':
a = MyTest(12)
...

正如在代码中指出的那样,您需要实例化 MyTest,因为实例化 _ MyTestWithHooks 将导致与前面相同的无限递归问题。