带有 tee 对象的 isinstance

isinstance with tee objects

作为记忆机制的一部分,我有一个生成器,我tee它,我需要用isinstnace检查它的类型。

>>> gen = (i for i in range(5))
>>> one, two = itertools.tee(gen, 2)

然后

>>> type(one), type(two)
(itertools.tee, itertools.tee)

符合预期,但是

>>> isinstance(one, itertools.tee)
TypeError: isinstance() arg 2 must be a class, type, or tuple of classes and types

那么 tee 的实例是什么?

itertools.tee 是一个函数,而不是 class(参见 type(itertools.tee))。它 returns 对象是 tee class 的实例(有点令人困惑),但是 class 在 itertools 命名空间中不可用。我只是使用 type() 从实例中获取它。如果您手边没有实例,请创建一个。这似乎是获得 tee 类型的最少代码量:

TeeType = type(itertools.tee(())[0])

看来 tee 每次调用都使用相同的 class。

tee 是 returns Python 使用的内部实现类型的函数。一般来说,它是 tee 或任何其他 iterator/generator 类型应该无关紧要。

就是说,如果你真的需要像这样输入测试,你可以这样做,你只需要像检查类型一样导出 "true" 实例的 tee 类型已经,通过使用 type。例如,要将 tee 实例的类型存储在名为 Tee 的变量中,您可以这样做:

Tee = type(itertools.tee(())[0])

它调用 tee 来获取实例,然后使用 type 来获取它们的 class。

这是唯一可移植的记录方式;实际类型涉及(内部实现)从一个版本到另一个版本的变化;在 Python 3.5 中,您可以像 itertools._tee 一样访问原始类型,但显然在您的版本中,它不会那样公开。

isinstance 用于检查某物是否说它是鸭子,无论它是否是鸭子。

为了回答您的直接问题,isinstance.tee 是一种方法,而不是 class,或者类型或类型的元组:

>>> type(itertools.tee)
<class 'builtin_function_or_method'>

(事实上,在我的 python 版本中,class 已完全从选项列表中删除)。 Python 是一种 'duck typed' 语言。基本上,为了 'isinstance' 说某物是另一物的实例,它必须以某种方式从它继承。

示例:

>>> type(str)
<class 'type'>
>>> s = "foo"
>>> isinstance(s,str)
True
>>> class myString(str): #myString inherits from str (a type)
...   def __init__(self,s):
...     super().__init__()
... 
>>> s = myString("foo")
>>> s
'foo'
>>> isinstance(s,str) 
True

首先,这些继承的基 class 应该是(只要可能)基类型或抽象基 class 。为什么是这样?好吧,Python 的开发人员希望避免这样一种情况,即我们有一百万种新的用户类型,例如人们开始检查的 FooString 和 BarInt。应该避免这种情况。

ABC 提供了一种允许对象说它是某种东西的方法,例如 Integral 或 String,而不必(必须)是字符串。

但是,Python 的鸭子类型是建立在实现协议的基础上的。协议由 class 中的一个或多个 "special"(或魔术或双下)方法定义。可以使用 dir(myObj):

确定哪些特殊方法是 class 的一部分
>>> dir(itertools.tee)
['__call__', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__self__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__text_signature__']

或者,甚至更好,在可能的情况下,尝试用它做点什么,如果失败了,你就知道它不是鸭子:

try: duck(something)
except: print("Not a duck!")

假设我们定义了一个 class MyClass:

class MyClass(object):
    pass

然后我们定义一个覆盖 class:

的函数
def MyClass(x=MyClass):
    return x()

如果我们调用那个函数,我们将得到原始 MyClass:

的一个实例
>>> instance = MyClass()
>>> type(instance)
<class '__main__.MyClass'>

看起来 MyClass 是一个 class 因为其 return 值的类型具有相同的名称,但请看一下:

>>> type(MyClass)
<type 'function'>

MyClass是一个函数,return是MyClass的一个实例,但它们是不同的。 tee也是一样。 tee 是一个函数,return 是 tee 的一个实例。当您查看该实例是否属于 tee 类型时,您实际上并不是在检查 class 或类型;你正在检查一个函数。 isinstance() 不允许这样做,因此会出现错误。获得 class 的方法是创建一个实例:

>>> tee = type(itertools.tee(())[0])
>>> isinstance(one, tee)
True

tee 是 returns 不是 itertools.tee 的实例的函数。一种检查方法是(有点老套)查询实例的 class 名称:

>> one.__class__.__name__ == "tee"
True