2013-02-28 108 views
1

我想创建一个类级别的装饰器,自动添加一个属性到一个对象,包括适当的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方法的(他们可能只是一个简单的属性来完成,但他们需要的默认值和零保护,我想只是。能够指定一个装饰,做创建的类的新实例的属性繁重。

如果我对这个做法大错特错,我打开一个同样可行的方法。

任何帮助将不胜感激。

我正在使用python 3.X和python 2.7,所以在其中任何一个工作是首选但不是必要的。

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

+0

听起来你可能想写一些[自定义描述符](http://me.veekun.com/blog/2012/05/23/python-faq-descriptors/)。 – Eevee 2013-02-28 19:17:26

+0

你的问题是什么? – 2013-02-28 20:17:00

+0

@Robᵩ我的问题是如何创建一个类实例级别的装饰器,它将自动在实例化类上创建正确的属性。 – GrayWizardx 2013-02-28 23:12:47

回答

4

下面的类的装饰会做到这一点:

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) 

类装饰器w如果你需要创建多个属性(或许有相互依赖关系),那么应该更有意义。

+0

这正是我需要做的,我有一个类可能有一打需要配置的属性。 – GrayWizardx 2013-02-28 23:06:48

+0

这工作非常接近我想要的。谢谢。 – GrayWizardx 2013-03-01 02:02:47

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

这对我来说似乎是一个NameError(因为当您尝试创建类时未定义自动属性)。否则,据我所见,一个很好的建议... – mgilson 2013-02-28 19:05:37

+0

@mgilson:如果您在两个类的主体之后创建实例,则为NameError。 – cox 2013-02-28 19:18:07

+0

为什么我需要装饰课堂的一部分是我不一定知道在设计时需要什么属性。它们是从一个原型工厂设施创建的,其后自动添加功能。 – GrayWizardx 2013-02-28 23:18:13

相关问题