【问题标题】:TypeError: function() argument after * must be a sequence, not generatorTypeError:*后的函数()参数必须是序列,而不是生成器
【发布时间】:2012-07-26 06:05:04
【问题描述】:

在尝试编写一个小型的混淆类型检查器时,发现了一个不可接受的代码模式。但是,它始终无法正常工作。这是最初为测试它而编写的代码。

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)

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

>>> 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

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)])))

之后,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'>

问题:

  1. 为什么生成器的第一个函数有时会工作而其他时候会失败?
  2. 为什么不将生成器视为序列(因为它会生成序列)?
  3. 当生成器在某些时候明显工作时,为什么需要序列?

【问题讨论】:

    标签: python typeerror


    【解决方案1】:
    1. 因为isinstance 和其他一些棘手的标准库函数一样,当你给它一个元组时,它的作用与其他序列不同。也就是说,它可以工作,并检查类型是否为给定的任何类型。
    2. 因为它不是。请参阅sequence protocol definition。它需要实现 __getitem__ 为一。
    3. 一个错误,仍然是hasn't been merged,它告诉您您的生成器已损坏,但错误消息不正确。

    另外,请不要为了任何正当理由而使用像这样的类型检查来玷污我们可爱的语言:)。

    【讨论】:

    • 广告 1.:查看发生错误的行 - 该行中没有 isinstance() 调用。
    • 好的,我明白了——由于3中提到的错误,错误在错误的行中报告。
    • 我已经使用 Python 大约 6 年了,不需要类型检查。这只是一个实验,看看功能类型检查器可以做得有多小。似乎几乎没有人利用函数注释,这似乎是一种创造性的使用方式。
    • 啊!酷,好吧,希望它现在可以工作了:)?您可以向tuple() 添加呼叫,或确保始终告知您的呼叫者传入tuple
    • 用列表推导替换生成器表达式效果很好。或者,生成器表达式可能有 tuple 前缀。感谢您的解释!你认为这个错误会很快修复吗?该补丁似乎需要审查。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多