Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2008/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何向动态创建的类添加类型注释?_Python_Mypy - Fatal编程技术网

Python 如何向动态创建的类添加类型注释?

Python 如何向动态创建的类添加类型注释?,python,mypy,Python,Mypy,在一个应用程序中,我有生成动态类的代码,这大大减少了重复代码的数量。但是为mypy检查添加类型提示会导致错误。考虑下面的示例代码(简化为关注相关位): 使用mypy检查此选项将导致以下错误: dynamic_type.py:15: error: "type" has no attribute "action" dynamic_type.py:21: error: "type" has no attribute "action" mypy显然无法判断type调用的返回值是否是Mapper的子类,

在一个应用程序中,我有生成动态类的代码,这大大减少了重复代码的数量。但是为mypy检查添加类型提示会导致错误。考虑下面的示例代码(简化为关注相关位):

使用mypy检查此选项将导致以下错误:

dynamic_type.py:15: error: "type" has no attribute "action"
dynamic_type.py:21: error: "type" has no attribute "action"
mypy显然无法判断
type
调用的返回值是否是
Mapper
的子类,因此它抱怨在分配给“type”时,“type”没有属性“action”

请注意,代码功能完美,并完成了它应该做的事情,但mypy仍在抱怨

有没有办法将
cls
标记为
映射器的一种类型?我试图简单地将
#type:Mapper
附加到创建类的行中:

cls = type('%sMapper' % new_name.capitalize(), (Mapper,), {})  # type: Mapper
但是我得到了以下错误:

dynamic_type.py:10: error: Incompatible types in assignment (expression has type "type", variable has type "Mapper")
dynamic_type.py:15: error: Cannot assign to a method
dynamic_type.py:15: error: Incompatible types in assignment (expression has type "staticmethod", variable has type "Callable[[], None]")
dynamic_type.py:16: error: Incompatible return value type (got "Mapper", expected "type")
dynamic_type.py:21: error: "type" has no attribute "action"

一种可能的解决方案基本上是:

  • 键入带有预期输入和输出类型的
    magic
    函数
  • 明智地使用
    Any
    #type:ignore
  • 例如,类似这样的方法会起作用:

    class Mapper:
        @staticmethod
        def action() -> None:
            raise NotImplementedError('Not yet implemnented')
    
    
    def magic(new_name: str) -> Mapper:
    
        cls = type('%sMapper' % new_name.capitalize(), (Mapper,), {})
    
        def action() -> None:
            print('Hello')
    
        cls.action = staticmethod(action)  # type: ignore
        return cls  # type: ignore
    
    
    MyCls = magic('My')
    MyCls.action()
    
    让代码库的一部分保持动态类型似乎有点令人不快,但在这种情况下,我认为没有什么可以避免的:mypy(和pep484类型生态系统)故意不尝试像这样处理超级动态代码


    相反,您能做的最好的事情是清晰地记录“静态”接口,添加单元测试,并将代码的动态部分限制在尽可能小的区域内。

    我认为这是必须的;)实际上,“magic”函数的定义应该具有返回类型
    typing.type[Mapper]
    。这样就可以在
    返回
    行中删除
    类型:ignore
    class Mapper:
        @staticmethod
        def action() -> None:
            raise NotImplementedError('Not yet implemnented')
    
    
    def magic(new_name: str) -> Mapper:
    
        cls = type('%sMapper' % new_name.capitalize(), (Mapper,), {})
    
        def action() -> None:
            print('Hello')
    
        cls.action = staticmethod(action)  # type: ignore
        return cls  # type: ignore
    
    
    MyCls = magic('My')
    MyCls.action()