Python类数据描述符列表

4

我似乎无法弄清如何获取类的数据描述符列表。基本上,我想对字段运行一些验证并取消设置的字段。例如:

class Field (object):
    def __init__ (self, name, required=False):
        self.name = name
        self.required = required

    def __set__ (self, obj, val):
        obj.__dict__[self.name] = val

    def __get__ (self, obj):
        if obj == None:
            raise AttributeError
        if self.name not in obj.__dict__:
            raise AttributeError
        return obj.__dict__[self.name]

然后我想将它实现在一个模型中,就像这样:

class BaseModel (object):
    some_attr = Field('some_attr', required=True)
    def save (self):
        for field in fields:
            if field.required and field.name not in self.__dict__:
                raise Exeception, 'Validation Error'

我该如何获取我定义的字段列表?我想,我可以采取以下方法:

import inspect

fields = []
for attr in self.__class__.__dict__:
    if inspect.isdatadescriptor(self.__class__.__dict__[attr]):
        fields.append(attr)

但我在继承方面遇到了问题,有什么建议吗?
1个回答

3
为了迭代类的成员,需要使用 inspect.getmembers。因此,您的最后一个示例将如下所示:
import inspect

fields = []
for member_name, member_object in inspect.getmembers(self.__class__):
    if inspect.isdatadescriptor(member_object):
         fields.append(member_name)

在你的描述器中,你应该用Python的getattrsetattr内置函数替换直接访问__dict__。同时要注意,在类上和实例下,描述器属性名要有所区别。在这种情况下,我通常会在其前面加一个下划线,例如:
class Field (object):
    def __init__(self, name, required=False):
        self.name = '_' + name
        self.required = required 

    def __set__(self, obj, val):
        setattr(obj, self.name, val)

    def __get__(self, obj):
        return getattr(obj, self.name)

我只是在想,是否有可能使它仅执行一次,因为字段不会更改,我不想在每个对象实例化时都执行它。 - Ian Livingstone
1
我不确定我是否理解你的意思。这是要验证类,使其仅包含字段属性的问题吗?然后只需在创建类时执行该验证一次,而不是每次调用“保存”时都进行验证? - Mark Gemmill
1
如果是这种情况,我会考虑在元类或者类装饰器中封装这样的验证。 - Mark Gemmill
2
getmembers函数直接使用谓词参数,因此您可以将for循环简化为:for name, descriptor in inspect.getmembers(self.class, inspect.isdatadescriptor)。 - mckoss

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接