类方法返回实例的 MyPy 注释 [英] MyPy annotation for classmethod returning instance

查看:50
本文介绍了类方法返回实例的 MyPy 注释的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我应该如何注释返回 cls 实例的 @classmethod?这是一个不好的例子:

How should I annotate a @classmethod that returns an instance of cls? Here's a bad example:

class Foo(object):
    def __init__(self, bar: str):
        self.bar = bar

    @classmethod
    def with_stuff_appended(cls, bar: str) -> ???:
        return cls(bar + "stuff")

这将返回一个 Foo 但更准确地返回 Foo 的任何子类,因此使用 -> 进行注释.Foo" 不够好.

This returns a Foo but more accurately returns whichever subclass of Foo this is called on, so annotating with -> "Foo" wouldn't be good enough.

推荐答案

诀窍是在 cls 参数中显式添加注释,并结合 TypeVar,用于genericsType,到 代表一个类而不是实例本身,像这样:

The trick is to explicitly add an annotation to the cls parameter, in combination with TypeVar, for generics, and Type, to represent a class rather than the instance itself, like so:

from typing import TypeVar, Type

# Create a generic variable that can be 'Parent', or any subclass.
T = TypeVar('T', bound='Parent')

class Parent:
    def __init__(self, bar: str) -> None:
        self.bar = bar

    @classmethod
    def with_stuff_appended(cls: Type[T], bar: str) -> T:
        # We annotate 'cls' with a typevar so that we can
        # type our return type more precisely
        return cls(bar + "stuff")

class Child(Parent):
    # If you're going to redefine __init__, make sure it
    # has a signature that's compatible with the Parent's __init__,
    # since mypy currently doesn't check for that.

    def child_only(self) -> int:
        return 3

# Mypy correctly infers that p is of type 'Parent',
# and c is of type 'Child'.
p = Parent.with_stuff_appended("10")
c = Child.with_stuff_appended("20")

# We can verify this ourself by using the special 'reveal_type'
# function. Be sure to delete these lines before running your
# code -- this function is something only mypy understands
# (it's meant to help with debugging your types).
reveal_type(p)  # Revealed type is 'test.Parent*'
reveal_type(c)  # Revealed type is 'test.Child*'

# So, these all typecheck
print(p.bar)
print(c.bar)
print(c.child_only())

通常情况下,您可以不注释cls(和self),但是如果您需要引用特定的子类,则可以添加一个显式注释.请注意,此功能仍处于试验阶段,在某些情况下可能存在问题.您可能还需要使用从 Github 克隆的最新版本的 mypy,而不是 pypi 上可用的版本——我不记得那个版本是否支持 classmethods 的此功能.

Normally, you can leave cls (and self) unannotated, but if you need to refer to the specific subclass, you can add an explicit annotation. Note that this feature is still experimental and may be buggy in some cases. You may also need to use the latest version of mypy cloned from Github, rather then what's available on pypi -- I don't remember if that version supports this feature for classmethods.

这篇关于类方法返回实例的 MyPy 注释的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆