【问题标题】:How to make a decorator for defining required properties of a class?如何制作用于定义类所需属性的装饰器?
【发布时间】:2017-11-07 06:03:17
【问题描述】:

我尝试编写这样的装饰器(内存不足,请原谅代码中的任何问题):

def required(fn):
    def wrapped(self):
        self.required_attributes += [fn.__name__]
        fn(self)

    return wrapped

我用它来装饰类中的@property 属性,例如:

@property
@required
def some_property(self):
    return self._some_property

...这样我就可以做这样的事情:

def validate_required_attributes(instance):
    for attribute in instance.required_attributes:
        if not hasattr(instance, attribute):
            raise ValueError(f"Required attribute {attribute} was not set!")

现在我忘记了这不起作用,因为要使用属性名称更新 required_attributes,我必须先检索该属性。所以本质上,当我在课堂上做 init 时,我可以只做一个 self.propertyname 来添加它......但是这个解决方案一点都不好,我还不如创建一个列表init 中的必需属性名称。

据我所知,装饰器是在编译时应用的,所以我无法在定义包装函数之前修改 required_attributes。还有其他方法可以使这项工作吗?我只想要一个漂亮、优雅的解决方案。

谢谢!

【问题讨论】:

  • def __init__(self, required_one, required_two) 有什么问题?

标签: python python-3.6 python-decorators


【解决方案1】:

我认为attrs library 可以满足您的需求。您可以像这样定义一个类,其中xy 是必需的,z 是可选的。

from attr import attrs, attrib

@attrs
class MyClass:
    x = attrib()
    y = attrib()
    z = attrib(default=0)

测试一下:

>>> instance = MyClass(1, 2)
>>> print(instance)
MyClass(x=1, y=2, z=0)

【讨论】:

    【解决方案2】:

    这是我对使用类装饰器和方法装饰器的看法。使用元类可能有更好的方法来做到这一点(很好的是 API 而不是实现;))。

    def requiredproperty(f):
        setattr(f, "_required", True)
        return property(f)
    
    
    def hasrequiredprops(cls):
        props = [x for x in cls.__dict__.items() if isinstance(x[1], property)]
        cls._required_props = {k for k, v in props if v.fget._required}
        return cls
    
    
    @hasrequiredprops
    class A(object):
    
        def __init__(self):
            self._my_prop = 1
    
        def validate(self):
            print("required attributes are", ",".join(self._required_props))
    
        @requiredproperty
        def my_prop(self):
            return self._my_prop
    

    这应该可以在不需要调用者先触摸属性的情况下进行验证:

    >>> a = A()
    >>> a.validate()
    required attributes are my_prop
    >>> a.my_prop
    1
    

    类装饰器需要确保它在实例化过程中具有所需的属性名称。 requiredproperty 函数只是根据需要标记属性的一种方式。

    话虽如此,我不完全确定您在这里想要实现什么。也许验证属性应该返回的实例属性值?

    【讨论】:

    • 我喜欢这个答案。但是,我必须做一个小的编辑来支持同一类上的@property 和@requiredproperty:从cls._required_props = {k for k, v in props if v.fget._required} 到=> cls._required_props = {k for k, v in props if '_required' in vars(v.fget) and v.fget._required} 否则,在非必需属性中缺少_required 将使其失败。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-25
    • 2015-10-23
    • 1970-01-01
    • 2020-08-27
    • 1970-01-01
    相关资源
    最近更新 更多