【问题标题】:Class Decorator Compatible for Mypy与 Mypy 兼容的类装饰器
【发布时间】:2021-05-09 22:25:26
【问题描述】:

假设我有以下没有任何类型提示的简单示例:

def wrapper(cls):
    class Subclass(cls):
        def subclass_method(self):
            pass
    return Subclass


@wrapper
class Parent:
    def parent_method(self):
        pass


p = Parent()
p.parent_method()
p.subclass_method()

如何使用类型提示重构此代码,以便当我针对 Parent 的实例运行 mypy 时,它会同时识别 subclass_methodparent_method

可能的解决方案:

  • 使用 mixin Parent(Mixin):有效,但避免使用装饰器。没有就可以实现吗?
  • 将方法修补到现有类上:在 mypy 中解析 subclass_method 仍然存在相同的问题
  • 自定义 Mypy 插件:不确定从哪里开始使用这个插件,或者如果没有它是否可能。

【问题讨论】:

  • 您是否尝试过类似def wrapper(cls) -> Callable[[...], "Subclass"]: 的方法。也许您必须将类定义移到装饰器之外。
  • @schwobaseggl 是的,这就是我的想法,但我想Subclass 必须扩展一些Generic[T] 才能让parent_method 仍然得到验证。我在想这可能需要某种存根 .pyi 文件。
  • 这种包装器的实际用例是什么?似乎比将Subclass once 定义为混合并直接使用(多重)继承更复杂。
  • 你装饰的每个类都有一个不同的类提供subclass_method,使你的类层次结构不必要地臃肿。
  • 一旦实现Intersection,您可以将mixin 类移动到全局范围,然后使用类型提示Intersection[T, SomeMixin]。不过目前这是不可能的。

标签: python decorator type-hinting mypy class-decorator


【解决方案1】:

完全没有包装器会简单得多。

class SomeMixin:
    def subclass_method(self):
        pass


class Parent(SomeMixin):
    def parent_method(self):
        pass


p = Parent()
p.parent_method()
p.subclass_method()

在这里,您定义SomeMixin一次,而不是每次调用包装器一次,并且SomeMixin 类是静态已知的。名称为Subclass 的所有各种类都是动态地创建的,而mypy 无法静态地知道名称Parent 实际绑定到哪个类。

【讨论】:

  • 我认为这是一个很好的折衷方案,但我还是想看看装饰器的方法是否可行!归根结底,我只想看到@wrapper class Parent: pass 能够解析subclass_method 方法。
  • 装饰器方法与mypy 根本不一致。 mypy 检查 static 类型,而装饰器对绑定到 Parent 的值的类型进行 dynamic 更改。
  • 如果您真的想使用装饰器,我建议您编写一个 直接 将新方法添加到装饰类的装饰器,而不是在运行时创建新类通过继承。
  • 我发现看到 @dataclass 支持有点令人惊讶,但也许这在 mypy 中是相当特殊的?
  • dataclass 不会更改静态类型。它对原始类进行了大量修补,而不是创建一个继承自原始类的新类(这与我在您提到 dataclass 时的建议一致)。
猜你喜欢
  • 1970-01-01
  • 2019-11-13
  • 2017-01-20
  • 2019-04-30
  • 2021-10-22
  • 2014-09-23
  • 2022-06-14
  • 2021-09-26
  • 2019-06-18
相关资源
最近更新 更多