检查对象是否为类型的正确方法是什么?泛型?

阿兰·费:

我正在尝试编写验证类型提示的代码,为了做到这一点,我必须找出注释是哪种对象。例如,考虑以下片段,该片段应告诉用户期望什么样的价值:

import typing

typ = typing.Union[int, str]

if issubclass(typ, typing.Union):
    print('value type should be one of', typ.__args__)
elif issubclass(typ, typing.Generic):
    print('value type should be a structure of', typ.__args__[0])
else:
    print('value type should be', typ)

这应该显示“值类型应该是(int,str)之一”,但它会引发异常:

Traceback (most recent call last):
  File "untitled.py", line 6, in <module>
    if issubclass(typ, typing.Union):
  File "C:\Python34\lib\site-packages\typing.py", line 829, in __subclasscheck__
    raise TypeError("Unions cannot be used with issubclass().")
TypeError: Unions cannot be used with issubclass().

isinstance 也不起作用:

>>> isinstance(typ, typing.Union)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python34\lib\site-packages\typing.py", line 826, in __instancecheck__
    raise TypeError("Unions cannot be used with isinstance().")
TypeError: Unions cannot be used with isinstance().

检查是否typ正确的方法typing.Generic什么?

如果可能的话,我希望看到一个由文档,PEP或其他资源支持的解决方案。通过访问未记录的内部属性来“工作”的“解决方案”很容易找到。但是很有可能,它将成为实现细节,并且在将来的版本中会有所变化。我正在寻找“正确的方法”来做到这一点。

阿兰·费:

没有获得此信息的官方方法。typing模块仍在大量开发中,并且没有公共API可言。(实际上,它可能永远不会有一个。)

我们所能做的就是查看模块的内部结构,并找到最简捷的方式来获取我们所需要的信息。并且由于该模块仍在开发中,其内部结构将发生变化。很多。


在python 3.5和3.6中,泛型具有一个__origin__属性,属性持有对原始泛型基类的引用(即List[int].__origin__会是List),但是在3.7中对此进行了更改。现在,找出某物是否通用的最简单方法可能是检查其__parameters____args__属性。

这是一组可用于检测泛型的函数:

import typing


if hasattr(typing, '_GenericAlias'):
    # python 3.7
    def _is_generic(cls):
        if isinstance(cls, typing._GenericAlias):
            return True

        if isinstance(cls, typing._SpecialForm):
            return cls not in {typing.Any}

        return False


    def _is_base_generic(cls):
        if isinstance(cls, typing._GenericAlias):
            if cls.__origin__ in {typing.Generic, typing._Protocol}:
                return False

            if isinstance(cls, typing._VariadicGenericAlias):
                return True

            return len(cls.__parameters__) > 0

        if isinstance(cls, typing._SpecialForm):
            return cls._name in {'ClassVar', 'Union', 'Optional'}

        return False
else:
    # python <3.7
    if hasattr(typing, '_Union'):
        # python 3.6
        def _is_generic(cls):
            if isinstance(cls, (typing.GenericMeta, typing._Union, typing._Optional, typing._ClassVar)):
                return True

            return False


        def _is_base_generic(cls):
            if isinstance(cls, (typing.GenericMeta, typing._Union)):
                return cls.__args__ in {None, ()}

            if isinstance(cls, typing._Optional):
                return True

            return False
    else:
        # python 3.5
        def _is_generic(cls):
            if isinstance(cls, (typing.GenericMeta, typing.UnionMeta, typing.OptionalMeta, typing.CallableMeta, typing.TupleMeta)):
                return True

            return False


        def _is_base_generic(cls):
            if isinstance(cls, typing.GenericMeta):
                return all(isinstance(arg, typing.TypeVar) for arg in cls.__parameters__)

            if isinstance(cls, typing.UnionMeta):
                return cls.__union_params__ is None

            if isinstance(cls, typing.TupleMeta):
                return cls.__tuple_params__ is None

            if isinstance(cls, typing.CallableMeta):
                return cls.__args__ is None

            if isinstance(cls, typing.OptionalMeta):
                return True

            return False


def is_generic(cls):
    """
    Detects any kind of generic, for example `List` or `List[int]`. This includes "special" types like
    Union and Tuple - anything that's subscriptable, basically.
    """
    return _is_generic(cls)


def is_base_generic(cls):
    """
    Detects generic base classes, for example `List` (but not `List[int]`)
    """
    return _is_base_generic(cls)


def is_qualified_generic(cls):
    """
    Detects generics with arguments, for example `List[int]` (but not `List`)
    """
    return is_generic(cls) and not is_base_generic(cls)

所有这些功能都应在所有<= 3.7的python版本中起作用(包括使用typing模块反向移植的所有<3.5版本)。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何检查对象是否为IncomingMessage(NodeJS)类型

检查对象是否为可观察对象

如何检查对象是否为Java中的集合类型?

检查对象是否为jQuery对象

Python:如何检查对象是否为datetime.date类型?

检查对象是否为数字的最pythonic方法是什么?

检查对象是否为空的更短方法?

检查对象是否使用Java正确构建

在Swift中检查对象是否为给定类型

C ++是否具有检查对象是否为派生类型的对象的现有方法?

如何检查对象是否为基类类型

有什么方法可以检查对象是否为TypeScript中的枚举类型?

如何检查对象是否是Haxe中的泛型实例

检查对象是否为QuerySet

如何检查对象是否为Blob类型?

如何快速检查对象是否为动态类类型?

c#使用lambda检查对象是否为某种动态类型(通过参数传递)

如何检查对象是否为方法定义?

如何在Java的arraylist中检查对象是否为枚举类型?

如何检查对象是否为联合类型之一

有什么方法可以检查对象是否为微风实体对象?

检查对象是否是具有多个类型参数的泛型类型

如何使用“ as”检查对象是否为参数传递的类型?

在Swift中,如何检查对象是否为任何类型的集合?

检查对象是否为 Google Closure 中的类型,并进行转换?

在条件语句中检查对象类型的正确方法是什么 - python

检查对象是否为十进制的正确方法

检查对象是否是 Typescript 中的泛型类型

检查对象是否为 Byte[]