【问题标题】:Create a class level decorator to automatically add a property创建一个类级别的装饰器来自动添加一个属性
【发布时间】:2013-02-15 02:32:44
【问题描述】:

我想创建一个类级别的装饰器,它可以自动将属性添加到对象,包括适当的 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()

我经常发现自己创建了很多“半复杂”的 getter/setter(它们可以只用一个简单的属性来完成,但它们需要默认值和 null 保护。我希望能够指定一个装饰器在类的新实例上创建属性的繁重工作。

如果我在这种方法上偏离了基础,我愿意接受同样可行的方法。

任何帮助将不胜感激。

我正在使用 python 3.X 和 python 2.7,因此首选但不是必需的。

更新:我在寻找的内容中添加了更多种类。一般来说,我需要能够创建很多这些简单的自动属性(ala C# auto-property,但具有更多的灵活性)。我不一定想公开后备存储,但我确实想确保对实例化对象(不一定是类)的检查显示已创建的属性。

【问题讨论】:

  • 听起来你可能想写一些custom descriptors
  • 你有什么问题?
  • @Robᵩ 我的问题是如何创建一个类级别的装饰器,它会在实例化时自动在类上创建正确的属性。
  • @Eevee,我对 python 还很陌生,我可以自己创建描述符,但我无法弄清楚如何连接它,这样当我创建类的新实例时,我就有了属性可用,对创建的实例有正确的约束,不一定在类上。

标签: python python-2.7 python-3.x properties python-decorators


【解决方案1】:

下面的类装饰器会这样做:

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)

如果您需要创建多个属性(可能具有相互依赖关系),类装饰器会更有意义。

【讨论】:

  • 这正是我需要做的,我有一个类可能有十几个需要配置的属性。
【解决方案2】:

这是一种更直接的方法,它避免了装饰类。

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):
        ...

【讨论】:

  • 这对我来说似乎是一个 NameError(因为在您尝试创建类时未定义自动属性)。否则,据我所知,这是一个很好的建议......
  • @mgilson : 如果在两个类主体之后创建实例,则不会出现 NameError。
  • 我需要装饰类的部分原因是我在设计时不一定知道需要哪些属性。它们是从原型工厂设施创建的,然后在其中添加自动属性。
猜你喜欢
  • 2019-10-08
  • 2020-11-11
  • 2015-03-28
  • 1970-01-01
  • 2018-03-05
  • 1970-01-01
  • 2014-02-09
  • 2013-09-19
  • 2017-11-16
相关资源
最近更新 更多