如何确保模块中的所有方法都具有相同的签名?

How do I ensure all methods in a module have the same signature?

模块中 class 中的所有函数都需要具有以下签名:

def func(i, x, y):
  return ('done', (1,2) ) 

所有函数都是静态的。 我的 class 中的每个函数都应该有三个参数。 return 应该是一个元组。

可以吗?那里可以用metaclass吗?

您可以结合使用类型注释、静态类型检查和单元测试来强制执行此操作。

使用带有 inspect 的单元测试来遍历 class 中的所有方法并验证它们是否使用正确的签名进行注释:

https://docs.python.org/3/library/inspect.html

然后使用mypy验证方法的实现是否与注释匹配:

https://mypy.readthedocs.io/en/stable/

所以,问题中缺少的关键,您作为评论完成了 - 您希望在导入时进行检查。

只需创建一个基础 class 并使用适当的 __init_subclass__ 进行检查。

class Base:
    def __init_subclass__(cls, **kw):
        super().__init_subclass__(**kw)
        for name, obj in cls.__dict__.items():
            if callable(obj) or isinstance(obj, classmethod):
                raise TypeError(f"All methods in class {cls.__name__} should be declared static")
            if isinstance(obj, staticmethod) and len(inspect.signature(obj.__get__(None, cls)).parameters) != 3:
                raise TypeError(f"All functions inside class {cls.__name__} must accept exactly 3 parameters")
            # class attributes that are not methods are ignored

如果您想将 staticmethod 装饰器自动应用到 class:

中所有已声明的函数,则可以改用 metaclass
class CheckPlugin(type):
    def __new__(mcls, name, bases, namespace, **kw):
        for attr_name, obj in namespace.items():
            if callable(obj):
                obj = staticmethod(obj)
                namespace[attr_name] = obj
            if isinstance(obj, classmethod):
                raise TypeError(f"All methods in class {name} should be written as static methods")
            if isinstance(obj, staticmethod) and len(inspect.signature(obj.__get__(None, cls)).parameters) != 3:
                raise TypeError(f"All functions inside class {name} must accept exactly 3 parameters")
            # class attributes that are not methods are ignored
        return super().__new__(mcls, name, bases, namespace, **kw)

(再想一想,没有什么可以阻止您将 __init_subclass__ 上的方法更改为静态方法——实际上不需要 metaclass):

class Base:
    def __init_subclass__(cls, **kw):
        super().__init_subclass__(**kw)
        for name, obj in list(cls.__dict__.items()):  # the list() call iterates on a static copy of the class's proxy dict, as it will be modified in interation
            if callable(obj):
                obj = staticmethod(obj)
                setattr(cls, name, obj)
                
            if isinstance(obj, classmethod):
                raise TypeError(f"All methods in class {cls.__name__} should be declared static")
            if isinstance(obj, staticmethod) and len(inspect.signature(obj.__get__(None, cls)).parameters) != 3:
                raise TypeError(f"All functions inside class {cls.__name__} must accept exactly 3 parameters")
            # class attributes that are not methods are ignored

最后,如问题评论中所述,无法仅使用函数来检查每个函数的 return 值类型 - 它们可以被注释,并且上面的代码可以检查但是注释(如果 return 值未正确注释,则会引发错误)。要验证注释不是“说谎”,唯一的方法是在 运行.

之前正确使用 Mypy 和静态类型检查