我试着写一个装饰器(关闭内存,原谅代码中的任何问题):
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。有没有其他方法可以让这项工作?我只想要一个漂亮,优雅的解决方案。
谢谢!
答案 0 :(得分:0)
我认为attrs library可以满足您的需求。您可以定义这样的类,其中x
和y
是必需的,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)
答案 1 :(得分:0)
这是我用类装饰器和方法装饰器做的事情。使用元类可能是一种更好的方法(很好的是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
函数只是一种根据需要标记属性的方法。
话虽如此,我并不完全确定你在这里想要实现的目标。也许验证属性应返回的实例属性值?