python 元类做类型检查

2019-12-12 18:00:14 浏览数 (1)

作为一个具体的应用例子,下面定义了一个元类,它会拒绝任何有混合大小写名字作为方法的类定义

class NoMixedCaseMeta(type): def new(cls, clsname, bases, clsdict): for name in clsdict: if name.lower() != name: raise TypeError('Bad attribute name: ' name) return super().new(cls, clsname, bases, clsdict)

class Root(metaclass=NoMixedCaseMeta): pass

class A(Root): def foo_bar(self): # Ok pass

class B(Root): def fooBar(self): # TypeError pass

检查元类的签名

from inspect import signature import logging

class MatchSignaturesMeta(type):

代码语言:javascript复制
def __init__(self, clsname, bases, clsdict):
    super().__init__(clsname, bases, clsdict)
    sup = super(self, self)
    for name, value in clsdict.items():
        if name.startswith('_') or not callable(value):
            continue
        # Get the previous definition (if any) and compare the signatures
        prev_dfn = getattr(sup,name,None)
        if prev_dfn:
            prev_sig = signature(prev_dfn)
            val_sig = signature(value)
            if prev_sig != val_sig:
                logging.warning('Signature mismatch in %s. %s != %s',
                                value.__qualname__, prev_sig, val_sig)

Example

class Root(metaclass=MatchSignaturesMeta): pass

class A(Root): def foo(self, x, y): pass

代码语言:javascript复制
def spam(self, x, *, z):
    pass

Class with redefined methods, but slightly different signatures

class B(A): def foo(self, a, b): pass

代码语言:javascript复制
def spam(self,x,z):
    pass

在元类中选择重新定义 new() 方法还是 init() 方法取决于你想怎样使用结果类。 new() 方法在类创建之前被调用,通常用于通过某种方式(比如通过改变类字典的内容)修改类的定义。 而 init() 方法是在类被创建之后被调用,当你需要完整构建类对象的时候会很有用。 在最后一个例子中,这是必要的,因为它使用了 super() 函数来搜索之前的定义。 它只能在类的实例被创建之后,并且相应的方法解析顺序也已经被设置好了。

最后一个例子还演示了Python的函数签名对象的使用。 实际上,元类将每个可调用定义放在一个类中,搜索前一个定义(如果有的话), 然后通过使用 inspect.signature() 来简单的比较它们的调用签名。

0 人点赞