如何在Python中实现Required属性

时间:2011-06-24 09:07:08

标签: python

如果我有一个如下所示的类(只有更多属性),在调用特定方法之前是否有清晰的方法来记录哪些字段是必需的?

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

4 个答案:

答案 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

虽然以这种方式定义属性依赖关系具有一定的整洁性,但我不确定我是否推荐它。