Generic [T]基类-如何从实例中获取T的类型? [英] Generic[T] base class - how to get type of T from within instance?

查看:161
本文介绍了Generic [T]基类-如何从实例中获取T的类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设您有一个从Generic [T]继承的Python类.是否有任何方法可以保留从类/实例内部传入的实际类型?

Assume you have a Python class that inherits from Generic[T]. Is there any way to get a hold of the actual type passed in from within the class/instance?

例如,

from typing import TypeVar, Type
T = TypeVar('T')

class Test(Generic[T]):
    def hello(self):
      my_type = T  # this is wrong!
      print( "I am {0}".format(my_type) )

Test[int]().hello() # should print "I am int"

此处上,建议arg类型将出现在该类型的args字段中.确实,

On here, it is suggested the type arg would be present in in the args field of the type. And indeed,

print( str( Test[int].__args__ ) )

将打印(< class'int'> ;,).但是,我似乎无法直接从实例中访问它,例如替代

would print (<class 'int'>,). However, I can't seem to access this from within the instance directly, e.g. substituting

      my_type = self.__class__.__args__ # this is also wrong (None)

似乎没有窍门.

谢谢

推荐答案

没有为此提供支持的API.在有限的情况下,如果您愿意弄乱未记录的实现细节,有时可以这样做,但这根本不可靠.

There is no supported API for this. Under limited circumstances, if you're willing to mess around with undocumented implementation details, you can sometimes do it, but it's not reliable at all.

首先,mypy不需要在分配给通用类型的变量时提供类型参数.您可以执行x: Test[int] = Test()之类的操作,而Python和mypy都不会抱怨. mypy推断类型参数,但是在运行时使用Test代替Test[int].由于显式类型参数难以编写并且会降低性能,因此许多代码仅在注释中使用类型参数,而不是在运行时使用.

First, mypy doesn't require you to provide type arguments when assigning to a generically-typed variable. You can do things like x: Test[int] = Test() and neither Python nor mypy will complain. mypy infers the type arguments, but Test is used at runtime instead of Test[int]. Since explicit type arguments are awkward to write and carry a performance penalty, lots of code only uses type arguments in the annotations, not at runtime.

无法在运行时恢复从未在运行时提供的类型参数.

There's no way to recover type arguments at runtime that were never provided at runtime.

在运行时提供类型参数时,实现确实会尝试保留此信息,但仅保留在完全未记录的内部属性中,该属性可能会随时更改,恕不另行通知,甚至该属性也可能不会出席.具体来说,当您致电

When type arguments are provided at runtime, the implementation does currently try to preserve this information, but only in a completely undocumented internal attribute that is subject to change without notice, and even this attribute might not be present. Specifically, when you call

Test[int]()

,新对象的类是Test而不是Test[int],但是typing实现会尝试设置

, the class of the new object is Test rather than Test[int], but the typing implementation attempts to set

obj.__orig_class__ = Test[int]

在新对象上.如果无法设置__orig_class__(例如,如果Test使用__slots__),则它将捕获AttributeError并放弃.

on the new object. If it cannot set __orig_class__ (for example, if Test uses __slots__), then it catches the AttributeError and gives up.

__orig_class__是Python 3.5.3引入的;它在3.5.2和更低版本中不存在. typing中的任何内容均未真正使用__orig_class__.

__orig_class__ was introduced in Python 3.5.3; it is not present on 3.5.2 and lower. Nothing in typing makes any actual use of __orig_class__.

__orig_class__分配的时间因Python版本而异,但当前为

The timing of the __orig_class__ assignment varies by Python version, but currently, it's set after normal object construction has already finished. You will not be able to inspect __orig_class__ during __init__ or __new__.

这些实现细节从CPython 3.8.2开始是最新的.

These implementation details are current as of CPython 3.8.2.

__orig_class__是实现细节,但是至少在Python 3.8上,您不必访问任何其他实现细节即可获取类型参数. Python 3.8引入了 typing.get_args ,它返回一个元组typing类型的类型实参,或()表示无效的实参. (是的,从Python 3.5一直到3.8,实际上并没有公开的API.)

__orig_class__ is an implementation detail, but at least on Python 3.8, you don't have to access any additional implementation details to get the type arguments. Python 3.8 introduced typing.get_args, which returns a tuple of the type arguments of a typing type, or () for an invalid argument. (Yes, there was really no public API for that all the way from Python 3.5 until 3.8.)

例如,

typing.get_args(Test[int]().__orig_class__) == (int,)

如果存在__orig_class__并且您愿意访问它,则__orig_class__get_args一起提供您想要的内容.

If __orig_class__ is present and you're willing to access it, then __orig_class__ and get_args together provide what you're looking for.

这篇关于Generic [T]基类-如何从实例中获取T的类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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