从元类访问基类变量

1 投票
2 回答
1117 浏览
提问于 2025-04-18 16:18

我正在尝试通过这个代码,从元类中读取基类的变量,以便覆盖类的变量:

class TypeBaseMeta(type):
    def __new__(cls, name, bases, namespace, **kwds):
        for base in bases:
            namespace['__validators__'] = base['__validators__'] + namespace['__validators__']

        return type.__new__(cls, name, bases, namespace, **kwds)

class TypeBase(metaclass=TypeBaseMeta):
    __validators__ = ('presence')

    def __init__(self, *args, **kwargs):
        pass

    def validate_presence(self, flag):
        if self.data:
            return True

class String(TypeBase):
    __validators__ = ('length')

    def validate_length(self, range):
        if len(self.data) in range(*range):
            return True

但是我遇到了这个错误:

Traceback (most recent call last):
  File "types.py", line 18, in <module>
    class String(TypeBase):
  File "types.py", line 4, in __new__
    namespace['__validators__'] = base['__validators__'] + namespace['__validators__']
TypeError: 'TypeBaseMeta' object is not subscriptable

我知道可以下标访问的对象必须有 __getitem__() 方法,并且要像字典和列表那样工作,但我不知道是什么导致了这个错误。

2 个回答

2

在父类中,__validators__ 这个变量不能像字典那样直接访问。你需要通过它的 __dict__ 属性来获取,或者使用 getattr 函数。

- namespace['__validators__'] = base['__validators__'] + namespace['__validators__']
+  namespace['__validators__'] = base.__dict__.get('__validators__', ()) + namespace['__validators__']
2

__validators__ 是父类的一个属性,不是字典里的一个项,所以你应该用 base.__validators__ 来访问它。也就是说,把 base['__validators__'] 改成 base.__validators__。而 namespace['__validators__'] 别改。

你用 namespace['__validators__'] 来访问当前类的属性,是因为这个类还没创建出来(它正在被元类创建中)。现在你手里只有一个它属性的字典而已。但是父类(base)已经创建好了,是一个真实的类,你可以用正常的方式通过 . 来访问它的属性。

正如 Dunes 在评论中提到的,你的代码还有另一个问题,就是你应该写 ('presence',)('length',) 来定义你的验证器,这样才能创建元组。否则它们只是字符串,这样子类的 __validators__ 就会被设置成单个字符串 'presencelength'

撰写回答