65

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

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

为了不使用交错类,我的想法是覆盖__getattr__and__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__等等。我如何需要更改此代码,在这种情况下,创建一个新属性xself保存值1

或者有没有更好的方法来处理像instance.device.read被“映射”到的呼叫instance.read

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

4

5 回答 5

69

您必须调用父类__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
于 2013-06-10T08:55:55.660 回答
29

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

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
于 2014-08-07T10:21:04.573 回答
4

您也可以使用对象

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)
于 2018-02-12T02:26:45.893 回答
3

或者你可以只使用@property:

class MyTest(object):

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

    @property
    def device(self):
        return self
于 2019-06-22T15:14:12.593 回答
3

如果您不想指定可以或不能设置哪些属性,可以拆分类以延迟 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 将导致与之前相同的无限递归问题。

于 2020-06-03T13:01:18.060 回答