在尝试编写一个模糊的,模糊的类型检查器时,发现了一种不可接受的代码模式.但是,它不一致地无法正常工作.这是最初用于测试它的代码.
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,...)). """ return all(isinstance(item,class_or_type_or_tuple) for item in iterable)
以下显示了与Python解释器的对话,并突出显示出现的错误.生成TypeError,但不生成预期的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),float]) File "C:\Users\schappell\Downloads\test.py",line 5,in <lambda> return __import__('functools').wraps(a)(lambda *c: b(a.__annotations__,c))))) TypeError: isallinstance() argument after * must be a sequence,not generator
可以重写statictypes函数,并重新定义和包装isallinstance函数.最简单的解决方案是将statictypes中的generatior重写为列表理解.
def statictypes(a): def b(a,a(*[b(a.__annotations__,c)])))
之后,一旦从头开始重新创建,isallinstance将按预期开始工作. TypeError指出第二个参数的错误是正确生成的.
>>> isallinstance(range(1000000),float]) Traceback (most recent call last): File "<pyshell#29>",c)]))) File "C:\Users\schappell\Downloads\test.py",in <listcomp> return __import__('functools').wraps(a)(lambda *c: b(a.__annotations__,line 3,in b if b in a and not isinstance(c,type(c))) TypeError: class_or_type_or_tuple should be (<class 'type'>,<class 'tuple'>),not <class 'list'>
问题:
>为什么第一个功能与发生器somtimes工作,其他时间失败?
>为什么生成器不被视为序列(因为它生成序列)?
>为什么当发电机显然在某些时候工作时需要一个序列?
解决方法
>因为isinstance,就像其他一些棘手的标准库函数一样,当你给它一个元组而不是其他序列时,它会做一些不同的事情.也就是说,它可以工作,并检查类型是否是给定的任何类型.
>因为不是.请参阅 sequence protocol definition.它需要实现__getitem__才能成为一个.
>一个仍然是 hasn’t been merged的错误,它告诉您发电机坏了,但错误消息不正确.
>因为不是.请参阅 sequence protocol definition.它需要实现__getitem__才能成为一个.
>一个仍然是 hasn’t been merged的错误,它告诉您发电机坏了,但错误消息不正确.
另外,请不要用这样的类型检查来弄脏我们可爱的语言,除了很好的理由:).