9

カスタム属性アクセスを使用__setattr__して提供する python クラスを作成しています。__getattr__

ただし、一部の属性は一般的な方法で処理できないため、それらには記述子を使用したいと考えていました。

__get__記述子の場合、インスタンスを優先して記述子が呼び出され__getattr__ますが、属性に割り当てると__setattr__、記述子を優先して呼び出されるという問題が発生します__set__

例:

class MyDesc(object):

    def __init__(self):
        self.val = None

    def __get__(self, instance, owner):
        print "MyDesc.__get__"
        return self.val

    def __set__(self, instance, value):
        print "MyDesc.__set__"
        self.val = value

class MyObj(object):

    foo = MyDesc()

    def __init__(self, bar):
        object.__setattr__(self, 'names', dict(
            bar=bar,
        ))
        object.__setattr__(self, 'new_names', dict())

    def __setattr__(self, name, value):
        print "MyObj.__setattr__ for %s" % name
        self.new_names[name] = value

    def __getattr__(self, name):
        print "MyObj.__getattr__ for %s" % name

        if name in self.new_names:
            return self.new_names[name]

        if name in self.names:
            return self.names[name]

        raise AttributeError(name)

if __name__ == "__main__":
    o = MyObj('bar-init')

    o.bar = 'baz'
    print o.bar

    o.foo = 'quux'
    print o.foo

プリント:

MyObj.__setattr__ for bar
MyObj.__getattr__ for bar
baz
MyObj.__setattr__ for foo
MyDesc.__get__
None

記述子__set__は呼び出されません。

__setattr__定義は、限られた一連の名前の動作をオーバーライドするだけではないため、延期できる明確な場所はありません。object.__setattr__

属性への代入で記述子を使用する推奨される方法はあり__setattr__ますか?

4

2 に答える 2

5

各クラスの記述子を自動的にマークし、__setattr__それらの名前に対してオブジェクトの通常の動作を呼び出す方法でラップするメカニズムを持つことで、これにアプローチすると思います。

これは、メタクラス (および__setattr__

def setattr_deco(setattr_func):
    def setattr_wrapper(self, attr, value):
        if attr in self._descriptors:
            return object.__setattr__(self, attr, value)
        return setattr_func(self, attr, value)
    return setattr_wrapper

class MiscSetattr(type):
    def __new__(metacls, name, bases, dct):
        descriptors = set()
        for key, obj in dct.items():
            if key == "__setattr__":
                dct[key] = setattr_deco(obj)
            elif hasattr(obj, "__get__"):
                descriptors.add(key)
        dct["_descriptors"] = descriptors
        return type.__new__(metacls, name, bases, dct)

# and use MiscSetattr as metaclass for your classes
于 2012-02-06T16:37:15.093 に答える