类方法返回实例的MyPy注释

时间:2017-06-19 21:46:25

标签: python mypy

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

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"进行注释并不够好。

2 个答案:

答案 0 :(得分:11)

诀窍是明确向s2参数添加注释,并结合clsgenericsTypeVar添加到represent a class rather then the instance itself,像这样:

Type

通常情况下,您可以保留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)未注释,但如果您需要引用特定的子类,则可以添加explicit annotation。请注意,此功能仍处于试验阶段,在某些情况下可能存在问题。您可能还需要使用从Github克隆的最新版mypy,而不是pypi上可用的内容 - 我不记得该版本是否支持类方法的此功能。

答案 1 :(得分:2)

出于完整性考虑,在Python 3.7中,您可以通过在文件的开头导入postponed evaluation of annotations来使用PEP563中定义的from __future__ import annotations

然后输入您的代码

from __future__ import annotations

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

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