如何使用 __future__ 注释从 self.__annotations__ 获取可调用的类对象?

Posted

技术标签:

【中文标题】如何使用 __future__ 注释从 self.__annotations__ 获取可调用的类对象?【英文标题】:How to get callable class objects from self.__annotations__ with __future__ annotations? 【发布时间】:2021-11-01 01:30:14 【问题描述】:

如果使用 py3.10 from __future__ import annotations,从注释中查找类的最佳方法是什么?以前,self.__annotations__[name] 会给你一个对象,但现在它返回一个字符串。如图所示,您可以使用globals(),但这对我来说似乎不合适。有没有更好的办法?

@dataclass
class Person:
    height: float
    def stack(self, other: Person):
        return Person(self.height + other.height) #gymnasts
@dataclass
class Chair:
    height: float
    def stack(self, other: Chair):
        return Chair(0.6*(self.height + other.height) ) #stackable chairs
@dataclass
class Room:
    person: Person
    chair: Chair
    
    def set(self, name: str, val: float):
        # lots of complicated validation
        # factory = self.__annotations__[name] # this worked before from __future__ import annotations
        factory = globals()[self.__annotations__[name]]
        self.__setattr__(name, factory(height=val))

【问题讨论】:

【参考方案1】:

使用typing.get_type_hints 访问“函数、方法、模块或类对象”的评估__annotations__。值得注意的是,它知道基本的继承——它合并继承的注解并使用当前类的globals 而不是方法的模块。

@dataclass
class Room:
    person: Person
    chair: Chair

    def set(self, name: str, val: float):
        factory = get_type_hints(type(self))[name]
        self.__setattr__(name, factory(height=val))

虽然typing.get_type_hints 比仅检查globals 做了一些额外的工作,但__future__.annotations 本质上会擦除非全局信息。对于在locals 范围内定义的类的罕见情况,必须显式提供命名空间。

【讨论】:

不错。 “__future__.annotations 固有地擦除非全局信息”是什么意思? @mmdanziger pre-__future__.annotations 和 PEP 649 注解根据 Python 的正常作用域规则捕获注解;例如,这意味着它们可以捕获仅在函数内部定义的类型。 __future__.annotations 不捕获任何内容,因此函数局部类型将超出函数的范围; typing.get_type_hints 无法获取此类类型。

以上是关于如何使用 __future__ 注释从 self.__annotations__ 获取可调用的类对象?的主要内容,如果未能解决你的问题,请参考以下文章

py2.7 from __future__ import error

在 python 3.5 中模拟异步调用

__future__ 进口如何在幕后工作

__future__ 模块在 Python 2.7 中如何工作? [复制]

如何从类变量中引用静态方法[重复]

使用__future__实现从python2.7到python3.x的过渡