如果我有一个如下所示的类(只有更多属性),在调用特定方法之前是否有清晰的方法来记录哪些字段是必需的?
class Example():
def __init__(self):
pass
@property
"""Have to use property methods to have docstrings..."""
def prop1(self):
return self._prop1
@prop1.setter
def task(self, value):
# validation logic..
self._prop1 = value
def method(self):
# check all required properties have been added
我可以手工编写所有必需的属性数组并在方法中循环它们,但我想知道是否有更简洁的方法,例如通过实现@requiredProperty描述符。
该类用于生成Web API的POST请求。该请求有25个以上的参数,其中一些是必需的,一些是可选的。
而不是调用请求的方法必须循环遍历数组,如:
required_props = ['prop1','prop2',....]
我希望在Python中有一种向属性添加所需装饰器的方法,所以我不必手动跟踪。 E.g。
@property, @required
def prop1(self):
return self._prop1
答案 0 :(得分:6)
在初始化对象时,确保提供所有属性是不是最好?然后,当您尝试访问它们时,将定义所有属性。
例如,
class Example(object):
def __init__(self, prop1, prop2):
self.prop1 = prop1
self.prop2 = prop2
另请注意PEP8:
对于简单的公共数据属性,它 最好只公开属性 名字,没有复杂 accessor / mutator方法。
那么为什么要使用属性?
答案 1 :(得分:5)
这应该与任何OO语言的工作方式相同:必须在构建期间设置必需的属性。调用对象方法必须永远不要让对象处于“坏”状态,以便可以在任何构造对象上调用method
。
如果上述情况不成立,您应该考虑重构代码。
当然,总是可以通过在它的内脏中探索来改变python对象不再有效。除非你有充分的理由,否则你不会这样做。不要费心去检查这个问题,因为只要你做了一些愚蠢的事情,你的程序应该只是在你的脸上爆炸,这样你才能学习并停止。
答案 2 :(得分:1)
很难从你的例子中看出你实际想要解决的问题,但我不相信properties
就是答案。
如果您只想检查实例变量是否存在,则可以使用特殊属性__dict__
,因此:
% cat ./test.py
#!/usr/bin/env python
class Example():
def __init__(self):
self.foo = None
def method(self):
assert 'foo' in self.__dict__
assert 'bar' in self.__dict__
Example().method()
% ./test.py
Traceback (most recent call last):
File "./test.py", line 12, in <module>
Example().method()
File "./test.py", line 10, in method
assert 'bar' in self.__dict__
AssertionError
但请记住...... EAFP: Easier to ask for forgiveness than permission.
答案 3 :(得分:1)
正如其他人所说,我怀疑你是在过度工程。但是,您可以使用装饰器来定义“必需”属性。有点像:
import functools
class MissingAttributeError(Exception):
pass
def requires(*required_attrs):
def wrapper(method):
@functools.wraps(method)
def inner_wrapper(self, *args, **kargs):
if not all(hasattr(self, attr) for attr in required_attrs):
raise MissingAttributeError()
return method(self, *args, **kargs)
return inner_wrapper
return wrapper
class Test(object):
def __init__(self, spam, eggs):
self.spam = spam
self.eggs = eggs
@requires('spam', 'eggs', 'ham')
def something(self):
return 'Done'
t = Test('fu', 'bar')
t.something() ## fails
t.ham = 'nicer than spam'
t.something() ## succeeds
虽然以这种方式定义属性依赖关系具有一定的整洁性,但我不确定我是否推荐它。