TypeError:*之后的function()参数必须是序列,而不是生成器

Noc*_*wer 6 python typeerror

在尝试编写一个模糊的,模糊的类型检查器时,发现了一种不可接受的代码模式.但是,它不一致地无法正常工作.这是最初用于测试它的代码.

def statictypes(a):
    def b(a, b, c):
        if b in a and not isinstance(c, a[b]): raise TypeError('{} should be {}, not {}'.format(b, a[b], type(c)))
        return c
    return __import__('functools').wraps(a)(lambda *c: b(a.__annotations__, 'return', a(*(b(a.__annotations__, *d) for d in zip(a.__code__.co_varnames, c)))))

@statictypes
def isallinstance(iterable: object, class_or_type_or_tuple: (type, tuple)) -> bool:
    """isallinstance(iterable, class_or_type_or_tuple) -> bool

    Return whether all items in an iterable are instances of a class or of a
    subclass thereof. With a type as second argument, return whether that is
    all items' type. The form using a tuple, isallinstance(x, (A, B, ...)),
    is a shortcut for any(isallinstance(x, y) for y in (A, B, ...)).
    """
    return all(isinstance(item, class_or_type_or_tuple) for item in iterable)
Run Code Online (Sandbox Code Playgroud)

以下显示了与Python解释器的对话,并突出显示出现的错误.TypeError生成A ,但不是预期的.虽然发电机很好,但现在它们都失败了.

>>> isallinstance(range(1000000), int)
True
>>> isallinstance(range(1000000), (int, float))
True
>>> isallinstance(range(1000000), [int, float])
Traceback (most recent call last):
  File "<pyshell#26>", line 1, in <module>
    isallinstance(range(1000000), [int, float])
  File "C:\Users\schappell\Downloads\test.py", line 5, in <lambda>
    return __import__('functools').wraps(a)(lambda *c: b(a.__annotations__, 'return', a(*(b(a.__annotations__, *d) for d in zip(a.__code__.co_varnames, c)))))
TypeError: isallinstance() argument after * must be a sequence, not generator
Run Code Online (Sandbox Code Playgroud)

statictypes函数可以重写,isallinstance函数重新定义和包装.最简单的解决方案是将生成器重写statictypes为列表理解.

def statictypes(a):
    def b(a, b, c):
        if b in a and not isinstance(c, a[b]): raise TypeError('{} should be {}, not {}'.format(b, a[b], type(c)))
        return c
    return __import__('functools').wraps(a)(lambda *c: b(a.__annotations__, 'return', a(*[b(a.__annotations__, *d) for d in zip(a.__code__.co_varnames, c)])))
Run Code Online (Sandbox Code Playgroud)

之后,isallinstance一旦从头开始重新创建,将开始按预期工作.该TypeError声明有什么错正如期望的正确生成的第二个参数.

>>> isallinstance(range(1000000), int)
True
>>> isallinstance(range(1000000), (int, float))
True
>>> isallinstance(range(1000000), [int, float])
Traceback (most recent call last):
  File "<pyshell#29>", line 1, in <module>
    isallinstance(range(1000000), [int, float])
  File "C:\Users\schappell\Downloads\test.py", line 5, in <lambda>
    return __import__('functools').wraps(a)(lambda *c: b(a.__annotations__, 'return', a(*[b(a.__annotations__, *d) for d in zip(a.__code__.co_varnames, c)])))
  File "C:\Users\schappell\Downloads\test.py", line 5, in <listcomp>
    return __import__('functools').wraps(a)(lambda *c: b(a.__annotations__, 'return', a(*[b(a.__annotations__, *d) for d in zip(a.__code__.co_varnames, c)])))
  File "C:\Users\schappell\Downloads\test.py", line 3, in b
    if b in a and not isinstance(c, a[b]): raise TypeError('{} should be {}, not {}'.format(b, a[b], type(c)))
TypeError: class_or_type_or_tuple should be (<class 'type'>, <class 'tuple'>), not <class 'list'>
Run Code Online (Sandbox Code Playgroud)

问题:

  1. 为什么第一个功能与发电机somtimes工作,其他时间失败?
  2. 为什么生成器不被视为序列(因为它生成序列)?
  3. 当发电机显然在某些时候工作时,为什么需要一个序列?

Jul*_*ian 8

  1. 因为isinstance,就像其他几个棘手的标准库函数一样,当你给它一个元组而不是其他序列时会做一些不同的事情.也就是说,它可以工作,并检查类型是否是给定的任何类型.
  2. 因为它不是.请参阅序列协议定义.它需要实现__getitem__为一个.
  3. 一个仍未合并的错误,它告诉您发生器已损坏,但错误消息不正确.

另外,请不要用这样的类型检查来弄脏我们可爱的语言,除了很好的理由:).

  • 好的,我知道 - 由于3中提到的错误,错误报告在错误的行中. (2认同)