4

一度に多くのプロパティを作成するデコレータを書くことは可能ですか?

書く代わりにいいね

class Test:
    @property
    def a(self):
        return self.ref.a
    @property
    def b(self):
        return self.ref.b

書きたい

class Test:
    @properties("a", "b")
    def prop(self, name):
        return getattr(self.ref, name)

出来ますか?あなたはそれをお勧めしますか?

4

4 に答える 4

3

デコレータであることを思い出してください

@decorator(dec_args)
def foo(args):
    pass

書くための単なる構文糖衣です

def foo(args):
    pass
foo = decorator(dec_args)(foo)

そのため、メソッド デコレーターによって複数のメソッド (またはプロパティなど) がクラスに追加されることはありません。

別の方法として、プロパティを注入するクラス デコレータを使用できます。

def multi_property(prop, *names):
    def inner(cls):
        for name in names:
            setattr(cls, name, property(lambda self, name=name: prop(self, name)))
    return inner

@multi_property(prop, 'a', 'b')
class Test:
    pass

ただし、通常は、クラスの本体内に各プロパティが存在する方が明確です。

a = forward_property('ref', 'a')
b = forward_property('ref', 'b')

whereforward_propertyは、記述子プロトコルを適切に実装するプロパティ オブジェクトを返します。これは、ドキュメンテーションやその他の静的分析ツール、そして (通常は) 読者にとってより使いやすいものです。

于 2012-08-06T12:51:24.877 に答える
2

あなたがおそらく本当に意図していることのためのラグニュアージュの1つの規定は __setattr__、クラスのメソッドを書くことです。

このメソッドは、通常は存在しない属性がインスタンスでアクセスされるたびに調整されます。

>>> class Test(object):
...    a = 0
...    def __getattr__(self, attr):
...       return attr
... 
>>> t = Test()
>>> t.a
0
>>> t.b
'b'
>>> t.c
'c'

あなたが直接求めていることも可能ですが、しかし、いくつかのハックが必要です-常識的にはお勧めできませんが、野生の生産で広く使用されています。つまり、プロパティがPythonに存在するためには、それは特別なタイプのオブジェクト(少なくとも__get__メソッドを持つオブジェクト)にバインドされたクラス属性です。(Pythonドキュメントの「記述子プロトコル」の詳細を確認してください)。

ここで、例で貼り付けたコードのように、一度に複数のプロパティを作成しようとすると、呼び出された関数からクラスの名前空間にプロパティ名を挿入する必要があります。それは_可能_であり、Pythonの本番環境でも使用されており、実現するのは難しくありません。しかし、それにもかかわらず、きれいではありません。

したがって、これを回避するための可能な方法は、一連の「プロパティ」オブジェクトを返す呼び出しを行うことです。これは、クリーンで、読み取り可能で、保守可能です。

class MultiProperty(object):
    def __init__(self, getter, setter, name):
        self.getter = getter
        self.setter = setter
        self.name = name
    def __get__(self, instance, owner):
        return self.getter(instance, self.name)
    def __set__(self, instance, value):
        return self.setter(instance, self.name, value)

def multi_property(mgetter, msetter, *args):
    props = []
    for name in args:
        props.append(MultiProperty(mgetter, msetter, name))
    return props


class Test(object):
    def multi_getter(self, attr_name):
        # isf desired, isnert some logic here
        return getattr(self, "_" + attr_name)

    def multi_setter(self, attr_name, value):
        # insert some logic here
        return setattr(self, "_" + attr_name, value)        
    a,b,c = multi_property(multi_getter, multi_setter, *"a b c".split())
于 2012-08-06T13:01:53.937 に答える
2

別のオブジェクトのプロキシを作成する最も簡単な方法は、次を実装すること__getattr__()です。

class Proxy(object):
    def __init__(self, ref1, ref2):
        self._ref1 = ref1
        self._ref2 = ref2
    def __getatrr__(self, name):
        if name in ["a", "b", "c"]:
            return getattr(self._ref1, name)
        if name in ["d", "e", "f"]:
            return getattr(self._ref2, name)

__getattr__()は、現在のインスタンスで見つからない属性に対してのみ呼び出されることに注意してください。そのため、さらにメソッドと属性を に追加することもできますProxy

于 2012-08-06T12:52:47.117 に答える
0

これは、クラス内からは不可能です。ただし、後でクラスを変更できます。ここを参照してください:

def makeprop(meth, name):
    # make a property calling the given method.
    # It is not really a method, but it gets called with the "self" first...
    return property(lambda self: meth(self, name))

def propfor(cls, *names):
    def wrap(meth):
        for name in names:
            # Create a property for a given object, in this case self,
            prop = makeprop(meth, name)
            setattr(cls, name, prop)
        return meth # unchanged
    return wrap

class O(object):
    # just a dummy for your ref
    a = 9
    b = 12
    c = 199

class C(object):
    ref = O()

# Put the wanted properties into the class afterwards:
@propfor(C, "a", "b", "c")
def prop(self, name):
    return getattr(self.ref, name)

# alternative approach with a class decorator:
def propdeco(*names):
    meth = names[-1]
    names = names[:-1]
    def classdeco(cls):
        propfor(cls, *names)(meth) # not nice, but reuses code above
        return cls
    return classdeco

@propdeco("a", "b", "c", lambda self, name: getattr(self.ref, name))
class D(object):
    ref = O()

print C().a
print C().b
print C().c

print D().a
print D().b
print D().c

2番目のアプローチを好む場合は、次のように記述propdecoしてください。

def propdeco(*names):
    meth = names[-1]
    names = names[:-1]
    def classdeco(cls):
        for name in names:
            # Create a property for a given object, in this case self,
            prop = makeprop(meth, name)
            setattr(cls, name, prop)
        return cls
    return classdeco
于 2012-08-06T13:05:28.447 に答える