Sta*_*vin 4 python type-hinting python-3.x mypy
尝试学习在 Python 中输入提示。鉴于这两个函数:
from typing import Union, TextIO
def myfunc_ok(file: TextIO):
mydump = file.read()
print(mydump)
def myfunc_error(file: Union[str, TextIO]):
mydump = file.read()
print(mydump)
Run Code Online (Sandbox Code Playgroud)
第一个对 mypy 没问题,但它抱怨第二个有错误
Item "str" of "Union[str, TextIO]" has no attribute "read"
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我是否错误地使用了类型提示?(使用 python3.7 和 mypy 0.610,也用 py3.6 测试)
你的签名
def myfunc_error(file: Union[str, TextIO]):
...
Run Code Online (Sandbox Code Playgroud)
说file参数可以是str或TextIO,在函数体中您试图访问后.read的属性file的对象,但在的情况下,file是str不存在这样的属性,因此错误。
您在这里至少有 3 种可能性:
fileis the typestr并替换Union[str, TextIO]为TextIO使用isinstance内置函数体添加显式类型检查,如
import io
...
def myfunc_error(file: Union[str, TextIO]):
if isinstance(file, io.TextIOWrapper):
mydump = file.read()
else:
# assuming ``file`` is a required object already
mydump = file
print(mydump)
Run Code Online (Sandbox Code Playgroud)
从长远来看,这可能会变得难以维持
为给定的任务编写 2 个不同的函数:一个用于str参数,一个用于TextIO参数,例如
def myfunc_error_str_version(file: str):
mydump = file
print(mydump)
def myfunc_error_text_io_version(file: TextIO):
mydump = file.read()
print(mydump)
Run Code Online (Sandbox Code Playgroud)
这可能会导致很多命名问题(但这取决于用例)
最后一种方法可以使用functools.singledispatch装饰器进行改进:简而言之,这将允许我们定义一个泛型函数并使用一个名称,myfunc_error并根据第一个位置参数的类型调用重载(file在我们的例子中):
import io
from functools import singledispatch
from typing import TextIO
@singledispatch
def myfunc_error(file: str):
mydump = file
print(mydump)
# using ``typing.TextIO`` will not work because it's just an interface for type annotations,
# "real" types are located at ``io`` module
@myfunc_error.register(io.TextIOWrapper)
def _(file: TextIO):
mydump = file.read()
print(mydump)
Run Code Online (Sandbox Code Playgroud)
注意:我们可以使用我们想要的任何名称而不是_except myfunc_error,因为后者mypy会引发名称冲突错误。
| 归档时间: |
|
| 查看次数: |
1632 次 |
| 最近记录: |