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() 

Я часто ловлю себя на создании серии «пол-комплекс» геттеры/сеттеров (они могли бы быть сделаны только с простым свойством, но они нуждаются в значениях по умолчанию и нулевой защита, я хотел бы быть просто. возможность указать декоратор, который делает тяжелую работу по созданию свойств на новых экземплярах класса.

Если я способ покинуть базу в этом подходе, я открыт к столь же жизнеспособному подходу.

Любой помощь будет оценен.

Я работаю с python 3.X и python 2.7, поэтому что-то, что работает в любом случае, является предпочтительным, но не необходимым.

Обновление: Я добавил немного больше разнообразия в то, что я ищу. В общем, мне нужно иметь возможность создавать множество этих простых автоматических свойств (ala C# auto-property, но с немного большей гибкостью). Я не обязательно хочу раскрывать хранилище, но я хочу убедиться, что проверка экземпляра объекта (не обязательно класса) показывает свойства, которые были созданы.

+0

похоже, что вы можете написать некоторые [пользовательские дескрипторы] (http://me.veekun.com/blog/2012/05/23/python-faq-descriptors/). – Eevee

+0

Что вы думаете? –

+0

@ Robᵩ мой вопрос - как создать декоратор уровня класса, который автоматически создаст правильное свойство в классе при создании экземпляра. – GrayWizardx

ответ

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 ould имеет смысл, если вам нужно создать несколько объектов (возможно, с взаимозависимостями).

+0

Это именно то, что мне нужно сделать, у меня есть класс, у которого может быть дюжина свойств, которые нужно настроить на нем. – GrayWizardx

+0

Это работало довольно близко к тому, что я хотел. Благодарю. – GrayWizardx

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

Мне кажется, что мне нравится имя (поскольку autoproperty не определяется при попытке создать класс). В противном случае, хорошее предложение, насколько я могу видеть ... – mgilson

+0

@mgilson: no NameError, если вы создаете экземпляры после обоих классов. – cox

+0

Часть, почему мне нужно, чтобы украсить класс, заключается в том, что я не знаю во время разработки, какие свойства необходимы. Они создаются с завода-изготовителя прототипов, где впоследствии добавляются автопромышленности. – GrayWizardx