6
在嘗試編寫一個很小的混淆類型檢查器時,發現了一個不可接受的代碼模式。但是,它不一致地正常工作。這是最初編寫的用於測試的代碼。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)
以下顯示了與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'>
問題:
- 爲什麼與發電機的第一個函數somtimes工作等次失敗?
- 爲什麼生成器不被視爲序列(因爲它會生成一個序列)?
- 爲什麼當發電機顯然在某些時間工作時,需要一個序列?
廣告1:看看錯誤發生在哪一行 - 在該行中沒有'isinstance()'調用。 – 2012-07-27 14:34:15
好的,我看到了 - 由於在3中提到的錯誤,錯誤報告在錯誤的行中。 – 2012-07-27 14:37:58
我一直在使用Python大約6年,並且不需要類型檢查。這只是一個實驗,可以看出功能類型檢查器可以做多少。幾乎沒有人似乎利用功能註釋,這似乎是一個創造性的方式來使用它們。 – 2012-07-27 14:38:19