我想编写在多个平台上mypy使用和工作的类型化代码asyncio。具体来说,我经常有显式绑定到事件循环的类和方法。我想为事件循环提供类型注释。
asyncio当我检查Linux 上的事件循环类型时,我得到:
>>> import asyncio
>>> type(asyncio.get_event_loop())
<class 'asyncio.unix_events._UnixSelectorEventLoop'>
Run Code Online (Sandbox Code Playgroud)
这种类型显然与 Unix/Linux 平台相关。
现在,我可以编写使用以下类型显式键入事件循环的代码:
>>> import asyncio
>>> type(asyncio.get_event_loop())
<class 'asyncio.unix_events._UnixSelectorEventLoop'>
Run Code Online (Sandbox Code Playgroud)
但您会注意到,我必须# type: ignore在导入中包含一个标签_UnixSelectorEventLoop,因为asyncio.unix_events没有类型存根。我还犹豫是否要导入一个私有方法,如类名开头的下划线所示。
作为替代方案,我可以使用AbstractEventLoop以下类型:
import asyncio
from asyncio.unix_events import _UnixSelectorEventLoop # type: ignore
def func(loop: _UnixSelectorEventLoop) -> None:
print(loop)
func(asyncio.get_event_loop())
Run Code Online (Sandbox Code Playgroud)
这成功地通过了 mypy 类型检查。我犹豫是否用作AbstractEventLoop我的类型,因为它是一个抽象类型。
是否存在跨平台工作、不需要使用抽象类定义并通过 mypy 类型检查的替代类型签名?
举个简单的例子:
from __future__ import annotations
import typing as t
class MyType:
def __init__(self, s: str, i: int) -> None:
self.s = s
self.i = i
class MyProto(t.Protocol):
s: str
i: int
class MyDict(t.TypedDict):
s: str
i: int
def my_serializer(inst: MyProto) -> MyDict:
return {"s": inst.s, "i": inst.i}
d = my_serializer(MyType("a", 1))
Run Code Online (Sandbox Code Playgroud)
所有类型检查均通过。
现在我们可以说这MyType实际上是一个具有许多属性的 ORM 类,它是协议和字典类型的真实来源。每次将属性添加到类中时,都必须在 Protocol 类主体和 TypedDict 类主体中维护相同的注释,这感觉有点多余。
我想知道是否有一种方法可以集中定义类型注释并告诉 mypy 这些是协议和 dict 类的类型定义。
我试过这个:
class TypeMixin:
s: str
i: int
class MyProto(TypeMixin, t.Protocol):
pass
class MyDict(TypeMixin, t.TypedDict): …Run Code Online (Sandbox Code Playgroud) 在 Python 中继承 Protocols 有什么好处吗?
例如。
class SampleProtocol(Protocol):
def do_something(self) -> int:
...
class Sample(SampleProtocol):
def do_something(self) -> int:
return 10
Run Code Online (Sandbox Code Playgroud)
或者应该Sample只是一个实现协议而不显式继承它的类?
import unittest
from typing import *
T = TypeVar("T", bound=unittest.TestCase)
def decorate(func: Callable[[T], None]) -> Callable[[T], None]:
def decorated_function(self: T) -> None:
return func(self)
return decorated_function
Run Code Online (Sandbox Code Playgroud)
现在我什至有一个生成器来创建这些装饰器并想要速记这些装饰器。我对存储装饰器的变量使用什么类型(省略生成器的简化示例)。
my_decorate: Callable[[Callable[[T], None]], Callable[[T], None]] = decorate
Run Code Online (Sandbox Code Playgroud)
这可行,但很笨拙。所以问题是:
如何为该类型别名以避免编写完整签名?
不起作用的事情:
TD = Callable[[Callable[[T], None]], Callable[[T], None]]
my_decorate: TD[T] = decorator_variable
Run Code Online (Sandbox Code Playgroud)
给出错误
error: Type variable "mypytest.T" is unbound
note: (Hint: Use "Generic[T]" or "Protocol[T]" base class to bind "T" inside a class)
note: (Hint: Use "T" in function signature …Run Code Online (Sandbox Code Playgroud) 我正在尝试使用 Python 3 的类型提示语法以及 MyPy 静态类型检查器。我现在正在编写一个接受requests响应对象的函数,我想知道如何指示类型。
也就是说,在下面这段代码中,我可以???用什么来代替?
import requests
def foo(request: ???) -> str:
return json.loads(request.content)['some_field']
r = requests.get("my_url")
return foo(r)
Run Code Online (Sandbox Code Playgroud) 如何在项目中的所有 .py 文件上运行 mypy?我已经看到我可以指定一个模块来运行 mypy 但不能指定一个文件掩码或类似的东西。
我最近开始在我的代码中使用类型提示,到目前为止发现它们(大部分)非常有用。
但是,我真正不喜欢的一件事是强制类型检查器假定变量属于某种类型的语法。鉴于这个例子:
import itertools
from typing import Iterable, Tuple
x: Iterable[Tuple[str, str]] = itertools.combinations('abc', 2)
# error: Incompatible types in assignment (expression has type "Iterable[Tuple[str, ...]]", variable has type "List[Tuple[str, str]]")
Run Code Online (Sandbox Code Playgroud)
据我所知,解决此问题的推荐方法是明确cast对象以强制类型检查器使用指定的类型,例如:
import itertools
from typing import Iterable, Tuple, cast
x = cast(Iterable[Tuple[str, str]], itertools.combinations('abc', 2))
Run Code Online (Sandbox Code Playgroud)
我个人觉得这个解决方案有点恶心。我主要担心的是,对于没有经验的读者来说,不清楚cast是否纯粹是为了帮助静态分析器。(如果我还不知道,我会根据名称和上下文假设它正在转换并复制到指定类型的对象,而实际上没有运行时成本。)
cast看起来像任何旧的函数调用。当我看到对某个值调用了一个函数时,我希望该值发生变异和/或发生其他一些副作用,但在这种情况下,唯一的副作用是mypy停止抱怨。类型提示本身具有独特的语法,但我觉得这使新类型语法和传统 Python 语法的混合使线条变得模糊。(它已经有点模糊,因为您必须import使用类型并可以组合它们,但这是另一个讨论。)
是否有cast类似行为的替代语法?我还没有找到任何东西,但我希望有类似的东西:
x1 = itertools.combinations('abc', 2)) # cast: Iterable[Tuple[str, str]]
x2: Iterable[Tuple[str, str]] = itertools.combinations('abc', 2)) # type: …Run Code Online (Sandbox Code Playgroud) 为什么“mypy”将“int”视为“float”的子类型?子类型应支持其超类型的所有方法,但“float”具有“int”不支持的方法:
测试.py:
def f(x : float) -> bool:
return x.is_integer()
print(f(123.0))
print(f(123))
Run Code Online (Sandbox Code Playgroud)
静态类型检查器接受为“float”参数传递“int”参数:
(3.8.1) myhost% mypy test.py
Success: no issues found in 1 source file
Run Code Online (Sandbox Code Playgroud)
但这并不能保证在运行时没有错误:
(3.8.1) myhost% python test.py
True
Traceback (most recent call last):
File "test.py", line 5, in <module>
print(f(123))
File "test.py", line 2, in f
return x.is_integer()
AttributeError: 'int' object has no attribute 'is_integer'
Run Code Online (Sandbox Code Playgroud)
因为“float”有额外的方法,而“int”没有。
我有一个装饰器,可以将用户添加到 Flask 全局上下文 g:
class User:
def __init__(self, user_data) -> None:
self.username: str = user_data["username"]
self.email: str = user_data["email"]
def login_required(f):
@wraps(f)
def wrap(*args, **kwargs):
user_data = get_user_data()
user = User(user_data)
g.user = User(user_data)
return f(*args, **kwargs)
return wrap
Run Code Online (Sandbox Code Playgroud)
我希望在控制器中访问 g.user 时知道 g.user 的类型(用户)。我怎样才能做到这一点?(我正在使用pyright)
如何对字典进行子类化,以便子类支持泛型类型提示?它需要在各方面都像字典一样,并支持键和值的类型提示。该子类将添加访问和操作字典数据的函数。例如,它将有一个valueat(self, idx:int)函数返回给定索引处的字典值。
它不需要OrderedDict作为其基类,但字典确实需要具有可预测的顺序。由于OrderedDict维护插入顺序并支持类型提示,这似乎是一个合理的起点。这是我尝试过的:
from collections import OrderedDict
class ApplicationSpecificDict(OrderedDict[str, int]):
...
Run Code Online (Sandbox Code Playgroud)
但是,它失败并出现错误:
TypeError: 'type' object is not subscriptable
这在 Python 3.7+ 中不支持,还是我遗漏了什么?
mypy ×10
python ×10
type-hinting ×3
dictionary ×1
flask ×1
pyright ×1
python-3.6 ×1
python-3.x ×1
typechecking ×1
typing ×1