web-dev-qa-db-ja.com

__setattr__を正しく使用して、無限再帰を回避する方法

readおよびwriteメソッドを含むクラスを定義します。これらは次のように呼び出すことができます。

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__などを呼び出します。このコードを変更するにはどうすればよいですか?この場合、xの新しい属性selfが作成され、値1を保持しますか?

または、instance.device.readのような呼び出しを処理して、instance.readに「マッピング」するより良い方法はありますか?

理由については常に疑問があります。xmlrpc呼び出しの抽象化を作成する必要があります。そのためにmyxmlrpc.instance,device.readなどの非常に簡単なメソッドを作成できます。このようなマルチドットメソッド呼び出しを模倣するために、これを「模擬」する必要があります。

47
Alex

親クラスを呼び出す必要があります__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
49
Bakuriu

または、__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
18
Vindolin

objectを使用することもできます。

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)
4
Danny Harpigny

または、単に@propertyを使用できます。

class MyTest(object):

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

    @property
    def device(self):
        return self
0
Aviad Rozenhek