如何在Python中实现必需属性

8 投票
4 回答
14737 浏览
提问于 2025-04-16 20:12

如果我有一个像下面这样的类(其实里面有很多属性),有没有什么简单的方法可以标记哪些字段在调用某个特定方法之前是必须的?

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 的描述符。

这个类是用来生成一个发送给网络API的POST请求的。这个请求有25个以上的参数,其中一些是必需的,另一些是可选的。

与其让调用请求的方法去循环检查一个数组,比如:

required_props = ['prop1','prop2',....]

我希望在Python中能有一种方法,可以给属性添加一个必需的装饰器,这样我就不需要手动去跟踪了。例如:

    @property, @required
    def prop1(self):
        return self._prop1

4 个回答

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

虽然用这种方式来定义属性之间的依赖关系看起来挺整齐的,但我不太确定我是否推荐这样做。

8

在初始化一个对象的时候,确保所有的属性都被提供,这样是不是更好呢?这样的话,当你想访问这些属性时,它们就都已经定义好了。

举个例子,

class Example(object):
    def __init__(self, prop1, prop2):
        self.prop1 = prop1
        self.prop2 = prop2

另外,注意一下来自 PEP8 的内容:

对于简单的公共数据属性,最好只暴露属性的名称,而不是使用复杂的获取或修改方法。

那么,为什么还要使用属性呢?

7

这段话的意思是,在任何面向对象的编程语言中,必须在创建对象的时候设置好必要的属性。调用对象的方法时,不能让对象处于一种“坏”的状态,这样你就可以在任何创建好的对象上调用method

如果你发现以上这些不成立,那就要考虑重新整理你的代码了。

当然,你可以通过修改Python对象的内部结构,让它变得无效。但除非有很好的理由,否则不要这样做。也不用去检查这个,因为当你做错事的时候,程序应该直接崩溃,这样你才能吸取教训,避免再犯。

撰写回答