小さな、難読化されたタイプのチェッカーを作成しようとしているときに、許容できないコードパターンが発見されました。しかし、それは一貫して正しく動作しません。これは最初にそれをテストするために書かれたコードです。TypeError:function()arguments after *は、ジェネレータではなくシーケンスでなければなりません。
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
のgeneratiorをリストの理解度に書き換えることです。その後
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
は、作業を開始します。 2番目の引数が間違っていたことを示す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'>
質問:
- なぜ発電機との最初の関数は、仕事や他の回は失敗somtimesのでしょうか?
- なぜジェネレータはシーケンスと見なされないのですか(シーケンスが生成されるため)
- ジェネレータが明らかに時間の一部を使っているときにシーケンスが必要なのはなぜですか?
広告1:エラーが発生した行を見てください。その行にはisinstance()コールがありません。 –
OK、私は参照してください - エラーは、3に記載されたバグのために間違った行で報告されています。 –
私はPythonで約6年間働いており、タイプチェックは必要ありません。これは機能的なタイプチェッカーがどれくらい小さく作られたかを見るための実験に過ぎませんでした。関数の注釈を利用している人はほとんどいませんが、これを使用する創造的な方法のようです。 –