3

適切なgetterメソッドとsetterメソッド、およびバッキング変数を含むプロパティをオブジェクトに自動的に追加するクラスレベルのデコレータを作成したいと思います。例えば:

@autoproperty("foo", can_get=True, can_set=True, allow_null=False, default_value=0)
@autoproperty("baz", can_get=True, can_set=False, allow_null=True, default_value=0)
@autoproperty("bar")
class SomeNonTrivialClass(object):
   def __init__(self):
      #lots of stuff going on here

   def discombobulate(self):
      #this is obviously a very trivial example
      local_foo = self.foo;

      if (local_foo > 10):
         raise RuntimeError("Foo can never be more than 10")
      else:
         #do whatever with foo

if __name__ == '__main__':
   test = SomeNonTrivialClass()

   test.foo = 5
   test.discombobulate()
   test.foo = 11
   test.discombobulate()

多くの場合、「半複雑な」ゲッター/セッターを作成していることに気付きます(これらは単純なプロパティで実行できますが、デフォルト値とnull保護が必要です。手間のかかるデコレーターを指定できるようにしたいと思います。クラスの新しいインスタンスにプロパティを作成します。

私がこのアプローチでベースから大きく外れている場合、私は同様に実行可能なアプローチを受け入れます。

どんな助けでもいただければ幸いです。

私はpython3.Xとpython2.7を使用しているので、どちらでも機能するものが推奨されますが、必須ではありません。

更新:私が探しているものにもう少し多様性を追加しました。一般に、これらの単純な自動プロパティを多数作成できる必要があります(C#の自動プロパティですが、もう少し柔軟性があります)。バッキングストアを公開する必要はありませんが、インスタンス化されたオブジェクト(必ずしもクラスである必要はありません)の検査で、作成されたプロパティが表示されることを確認したいと思います。

4

2 に答える 2

8

次のクラスデコレータはそれを行います:

def autoproperty(name, can_get=True, can_set=True, allow_null=False, default_value=0):
    attribute_name = '_' + name
    def getter(self):
        return getattr(self, attribute_name, default_value)
    def setter(self, value):
        if not allow_null and value is None:
            raise ValueError('Cannot set {} to None'.format(name))
        setattr(self, attribute_name, value)

    prop = property(getter if can_get else None, setter if can_set else None)

    def decorator(cls):
        setattr(cls, name, prop)
        return cls

    return decorator

ただし、プロパティファクトリを作成することもできます。

def autoproperty(attribute_name, can_get=True, can_set=True, allow_null=False, default_value=0):
    def getter(self):
        return getattr(self, attribute_name, default_value)
    def setter(self, value):
        if not allow_null and value is None:
            raise ValueError('Cannot set {} to None'.format(name))
        setattr(self, attribute_name, value)
    return property(getter if can_get else None, setter if can_set else None)

次に、それをクラスで次のように設定します。

class SomeNonTrivialClass(object):
    # ...

    foo = autoproperty('_foo', can_get=True, can_set=True, allow_null=False, default_value=0)

代わりに(おそらく相互依存性を持つ)複数のプロパティを作成する必要がある場合は、クラスデコレータの方が理にかなっています。

于 2013-02-28T19:00:53.327 に答える
1

これは、クラスの装飾を回避する、より直接的なアプローチです。

class SomeNonTrivialClass(object):
   def __init__(self):
      #lots of stuff going on here

   foo = autoproperty("foo", can_get=True, can_set=True, allow_null=False, default_value=0)

   def discombobulate(self):
      #this is obviously a very trivial example
      local_foo = self.foo;

class autoproperty(property):
    def __init__(self, name, can_get, can_set, allow_null, default_value):
        ...
于 2013-02-28T19:00:36.757 に答える