mypy可以根据当前对象的类型选择方法返回类型吗? [英] Can mypy select a method return type based on the type of the current object?

查看:44
本文介绍了mypy可以根据当前对象的类型选择方法返回类型吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在下面的代码中,对 A 的实例调用 clone() 方法将返回一个类型为 A 的实例,在 B 的实例上调用它将返回一个类型为 B 的实例,并且很快.目的是创建一个新实例,该实例与当前实例相同,但具有不同的内部生成主键,因此可以从那里进行编辑并安全地保存为新项目.

In the following code, calling the clone() method on an instance of A will return an instance of type A, calling it on an instance of B will return an instance of type B, and so on. The purpose is to create a new instance which is identical to the current one but has a different internally generated primary key, so it can be edited from there and safely saved as a new item.

??? 是某种类型限定符,但我不确定正确的选择是什么.

??? is some kind of type qualifier, but I'm not sure what the right choice is.

class A:
    def clone(self) -> ???:
        cls = self.__class__
        result = cls.__new__(cls)
        for k, v in self.__dict__.items():
            setattr(result, k, deepcopy(v))
        result.id = self.__generate_id()
        return result

class B(A):
   def do_b(self):
       pass

我目前用 'A' 替换了 ???.这是有效的,但是如果我想克隆一个 B 类型的对象,如果我想在它上面调用 B 特定的方法,我必须转换返回值:

I currently replaced ??? with 'A'. This works, but if I want to clone an object of type B, I have to cast the return value if I want to call B-specific methods on it:

b = B().clone()
b.do_b()  # type error!

b = cast(B, B().clone())
b.do_b()  # OK

但是,可以保证在 B 类型的对象上调用 .clone() 将返回另一个 B 类型的对象,这对我来说太像 Java 了.是否有一些基于泛型的方法可以告诉 mypy 该方法返回一个 __class__ 类型的对象,无论该类是什么?

However, it's guaranteed that calling .clone() on an object of type B will return another object of type B, and this smacks rather too much of Java for my taste. Is there some generic-based way I can tell mypy that the method returns an object of type __class__, whatever that class is?

推荐答案

您可以使用 具有通用 self 的通用方法 -- 基本上,将您的 self 变量注释为通用的:

You can do this by using generic methods with a generic self -- basically, annotate your self variable as being generic:

from typing import TypeVar

T = TypeVar('T', bound='A')

class A:
    def __generate_id(self) -> int:
        return 0

    def clone(self: T) -> T: 
        cls = self.__class__
        result = cls.__new__(cls)
        for k, v in self.__dict__.items():
            setattr(result, k, deepcopy(v))
        result.id = self.__generate_id()
        return result

class B(A):
    def do_b(self):
        pass

reveal_type(A().clone())  # Revealed type is A
reveal_type(B().clone())  # Revealed type is B

基本上,当我们调用 clone() 时,当 mypy 尝试对 clone 调用进行类型检查时,T 类型变量将绑定到当前实例的类型.这最终使返回类型与实例的类型匹配,无论它是什么.

Basically, when we call clone(), the T typevar will be bound to the type of the current instance when mypy tries type-checking the call to clone. This ends up making the return type match the type of the instance, whatever it is.

您可能想知道为什么我将 T 的上限设置为 A.这是因为 self.__generate_id() 行.基本上,为了对该行进行类型检查,self 不能是任何类型:它需要是 AA 的某个子类代码>.边界编码了这个要求.

You may be wondering why I set the upper bound of T to A. This is because of the line self.__generate_id(). Basically, in order for that line to type-check, self can't be literally any type: it needs to be A or some subclass of A. The bound encodes this requirement.

这篇关于mypy可以根据当前对象的类型选择方法返回类型吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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