有没有办法确定一个对象是否是一个"实例"运行时pep484样式表达式?

时间:2016-11-20 14:27:10

标签: python

我经常发现自己编写多语句表达式来在运行时验证变量的类型。例如,假设我想验证特定输入是Foo对象的列表,我可能必须编写以下表达式:

assert(_isinstance(x, list) and all(_isinstance(y, Foo) for y in x))

我更愿意写下这样的内容:

# pseudocode
_assert(isinstance(x, typing.List[Foo]))

换句话说,我想问x是Foo的实例列表。

如果可以这样做,这会更好,因为Pep484语法是简明地指定嵌套结构类型的好方法。当然,我们都知道这不是Python内置的实例功能的工作原理......但只是想了我一会儿:

我们都熟悉isnstance函数,如果结构的外部类型是类的实例,则返回True:

# real python:
isinstance(["a", "b", "c"], list) => True

但是假设我想做更深入的检查:我想做类似的事情:

# pseudocode:
import typing
_isinstance("x", str) => True
_isinstance(["a", "b", "c"], typing.List[str]) => True
_isinstance(["a", "b", "c"], typing.List[float]) => False
_isinstance([{"x":3}], typing.List[typing.Map[str,int]]) => True

因此,如果第一个参数完全对应于第二个参数的Pep484样式表达式,则该函数将返回True。

当然,你们中的一些人会指出明确的静态和运行时类型检查违背了" duck-typing"的精神。这是真的 - 但没有用。有时你确实想要验证输入的结构。随着项目变得越来越大,你有时希望能够确切地知道你正在处理什么类型,而在其他时候你需要灵活的鸭子打字给你。

所以,我的问题是:有没有人看到过将Pep484风格表达与类型进行比较的方法?如果已经有一个库或函数来执行它,那么我宁愿不重新发明轮子。也许打字库已经有办法做到这一点。请指点我!

1 个答案:

答案 0 :(得分:-1)

你可以这样做:

def _isinstance(var, type):
    if not isinstance(var, type):
        return False

    if isinstance(var, Iterable) and not isinstance(var, Generator):
        return all(any(isinstance(v, t) for t in type.__parameters__) for v in var)

    return True

当然,这与你已经拥有的东西有很大的不同,但是它提供了简单的'做assert(isinstance(x, List[Foo]))。这里x必须是可迭代的。

请注意,无法在不迭代生成的情况下确定生成器将生成的数据类型,从而丢失所有数据。

Python是 duck-typed 并且并不关心类型。如果有什么东西像鸭子一样嘎嘎叫,那么它就是Python的鸭子。