TypeError:*后面的function()参数必须是序列,而不是gen

2024-05-17 04:03:10 发布

您现在位置:Python中文网/ 问答频道 /正文

在尝试编写一个小型的、模糊的类型检查器时,发现了一个不可接受的代码模式。然而,它不一致地不能正常工作。这是初始编写用来测试它的代码。

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中重写generatio,使其成为列表理解。

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. 为什么当一个生成器在某些时候明显工作时需要一个序列?

Tags: orlambdainforreturntypenotrange
1条回答
网友
1楼 · 发布于 2024-05-17 04:03:10
  1. 因为isinstance和其他一些糟糕的标准库函数一样,当给它一个元组时,它的作用与其他序列不同。也就是说,它工作,并检查类型是否是给定的任何类型。
  2. 因为不是。看sequence protocol definition。它需要实现__getitem__才能成为一个。
  3. 一个bug,它仍然hasn't been merged,它告诉您生成器已损坏,但错误消息不正确。

另外,请不要因为这样的类型检查而弄脏我们可爱的语言,除非有好的理由:)。

相关问题 更多 >