标签: python-typing

如何使用可选导入输入提示?

当使用可选导入时,包仅在函数内部导入,因为我希望它成为我包的可选依赖项,有没有办法将函数的返回类型提示为属于此可选的类之一依赖?

举一个简单的例子,pandas作为一个可选的依赖:

def my_func() -> pd.DataFrame:                                                  
    import pandas as pd                                                         
    return pd.DataFrame()                                                       

df = my_func()
Run Code Online (Sandbox Code Playgroud)

在这种情况下,由于import语句在 内my_func,因此该代码将毫不奇怪地引发:

NameError: 名称 'pd' 未定义

如果改为使用字符串文字类型提示,

def my_func() -> 'pd.DataFrame':                                                
    import pandas as pd                                                         
    return pd.DataFrame()                                                       

df = my_func()
Run Code Online (Sandbox Code Playgroud)

该模块现在可以毫无问题地执行,但mypy会抱怨:

错误:未定义名称“pd”

如何使模块成功执行并保留静态类型检查功能,同时还可以选择此导入?

python mypy python-typing

6
推荐指数
1
解决办法
474
查看次数

Python 3.6 类型提示接受同一泛型类型的泛型类类型和实例类型的函数

我有一个具有以下签名的函数:

def wait_for_namespaced_objects_condition(
    obj_type: Type[NamespacedAPIObject],
    obj_condition_fun: Callable[[NamespacedAPIObject], bool],
) -> List[NamespacedAPIObject]:
...
Run Code Online (Sandbox Code Playgroud)

这里的重要部分是NamespacedAPIObject参数。此函数采用obj_typeas 类型规范,然后创建该类型(类)的对象(实例)。然后将该类型的其他一些对象添加到列表中,然后使用mypy`obj_condition_fun类型List[NamespacedAPIObject]. This works fine and also evaluates OK with 对其进行过滤并返回。

现在,我想让这个函数通用,以便NamespacedAPIObject可以使用它的任何子类型。我的尝试是这样做的:

T = TypeVar("T", bound=NamespacedAPIObject)

def wait_for_namespaced_objects_condition(
    obj_type: Type[T],
    obj_condition_fun: Callable[[T], bool],
) -> List[T]:

Run Code Online (Sandbox Code Playgroud)

但是Type[T]TypeVar,所以这不是要走的路。问题是:应该使用什么类型的obj_type参数才能使这项工作起作用?我试过Generic[T],这对我来说似乎是最合理的,但它不起作用。如果我把它放在那里obj_type: Tmypy评估这可以,但对我来说似乎是错误的。在我看来,这意味着它obj_type是一个子类型的类的实例NamespacedAPIObject,而我想说的是“T 是一个表示 子类型的类变量NamespacedAPIObject。如何解决这个问题?

[编辑] 为了更好地解释(请参阅下面的评论)为什么Type[T]对我不起作用:在我的情况下, T 的所有子类型都实现了 class method objects(),但是当我尝试像这样编写代码时:

obj_type.objects() …
Run Code Online (Sandbox Code Playgroud)

python type-hinting python-3.x mypy python-typing

6
推荐指数
1
解决办法
912
查看次数

检查类型提示是否被注释的正确方法是什么?

Python 3.9 引入了Annotated允许向类型提示添加任意元数据的类,例如,

class A:
    x: Annotated[int, "this is x"]
Run Code Online (Sandbox Code Playgroud)

可以通过设置 的新include_extras参数来获得带注释的类型提示get_type_hints

>>> get_type_hints(A, include_extras=True)
{'x': typing.Annotated[int, 'this is x']}
Run Code Online (Sandbox Code Playgroud)

并且元数据本身可以通过__metadata__类型提示的属性访问。

>>> h = get_type_hints(A, include_extras=True)
>>> h["x"].__metadata__
('this is x',)
Run Code Online (Sandbox Code Playgroud)

但是,我的问题是,测试类型提示是否正确的正确方法 Annotated什么?也就是说,类似于:

if IS_ANNOTATED(h["x"]):
    # do something with the metadata
Run Code Online (Sandbox Code Playgroud)

据我所知,没有记录在案的方法可以这样做,并且有几种可能的方法,但似乎都不理想。

比较typetoAnnotated不起作用,因为类型提示不是 的实例Annotated

>>> type(h["x"])
typing._AnnotatedAlias
Run Code Online (Sandbox Code Playgroud)

所以我们必须这样做:

if type(h["x"]) is _AnnotatedAlias:
    ...
Run Code Online (Sandbox Code Playgroud)

但是,鉴于 中的前导下划线_AnnotatedAlias,这可能需要使用实现细节。

另一种选择是直接检查__metadata__属性:

if hasattr(h["x"], "__metadata__"):
    ... …
Run Code Online (Sandbox Code Playgroud)

python type-hinting python-typing

6
推荐指数
2
解决办法
94
查看次数

是否可以将 Literal 类型传递给函数并让该函数输出该 Literal 类型的值?

我正在尝试编写一个函数来断言用户输入与定义的文字类型匹配。

基本上,给出:

MyLiteral = Literal["foo", "bar"]
Run Code Online (Sandbox Code Playgroud)

我想编写一个函数来执行此操作:

some_user_provided_value = input()   # For example

good_value = assert_literal(MyLiteral, some_user_provided_value)
Run Code Online (Sandbox Code Playgroud)

现在应该将的类型good_value推断为MyLiteral。如果用户值与任何定义的文字字符串都不匹配,则会引发断言错误。

这应该具有与以下相同的效果:

some_user_provided_value = input()   # For example

good_value: MyLiteral

if some_user_provided_value == "foo":
    good_value = "foo"
elif some_user_provided_value == "bar":
    good_value = "bar"
else:
    raise AssertionError(f"Value {some_user_provided_value!r} is not a MyLiteral")
Run Code Online (Sandbox Code Playgroud)

这是我的项目中经常重复的模式,因此我想将其包装在一个函数中。

该函数看起来像这样:

from typing import Any, TypeVar

T = TypeVar("T")


def assert_literal(literal_type: T, value: Any) -> T:
    if value not in typing.get_args(literal_type):
        raise AssertionError(f"Value {value!r} is not …
Run Code Online (Sandbox Code Playgroud)

python mypy python-typing

6
推荐指数
1
解决办法
361
查看次数

是否可以使用 dataclass 而不是 typeddict 来定义 dict 类型并使 mypy 满意?

我有一个数据类,比方说:

from dataclasses import dataclass

@dataclass
class Foo:
    bar: int
    baz: int
Run Code Online (Sandbox Code Playgroud)

我有一个从接收 json 并将其作为字典加载的 API 调用的函数:

def handler(foo) -> Foo:
    return Foo(**foo)
Run Code Online (Sandbox Code Playgroud)

有没有一种方法可以输入 foo 而无需实际创建TypedDict数据类的镜像?

例如:

from typing_extensions import TypedDict


class SerializedFoo(TypedDict):
    bar: int
    baz: int
Run Code Online (Sandbox Code Playgroud)

我觉得必须定义两者很奇怪。

python mypy python-dataclasses python-typing typeddict

6
推荐指数
1
解决办法
2415
查看次数

Python Callable 的等效协议是什么?

我总是认为 Callable 相当于拥有 dunder__call__但显然也有__name__,因为以下代码是正确的mypy --strict

def print_name(f: Callable[..., Any]) -> None:
    print(f.__name__)

def foo() -> None:
    pass

print_name(foo)

print_name(lambda x: x)

Run Code Online (Sandbox Code Playgroud)

python Callable 的实际接口是什么?

我挖出了什么functools.wraps。AFAIU 设定('__module__', '__name__', '__qualname__', '__doc__', '__annotations__')- 这与Callable预期的相同吗?

python mypy python-typing

6
推荐指数
1
解决办法
424
查看次数

Python 类型 - 限制列表仅允许一种类型的子类

我有 3 个简单的类,例如:

class Animal(abc.ABC):
    ...

class Cat(Animal):
    ...

class Dog(Animal):
    ...
Run Code Online (Sandbox Code Playgroud)

然后我有一个注释如下的函数:

def speak(animals: List[Animal]) -> List[str]:
   ...
Run Code Online (Sandbox Code Playgroud)

我的问题是我想限制List[Animal]只包含一种动物,所以:

speak([Dog(), Dog()]) # OK
speak([Cat(), Cat()]) # OK
speak([Cat(), Dog()]) # typing error
Run Code Online (Sandbox Code Playgroud)

我将如何注释该speak函数以实现此目的?是否可以使用打字来完成,或者我是否被迫在运行时检查这一点?

我尝试使用上面的方法,但是在调用likeList[Animal]时不会出现错误。speakspeak([Cat(), Dog()])

我也尝试过使用泛型,TypeVar('T', bound=Animal)但这仍然允许我传递子List类的任意组合。

python python-typing

6
推荐指数
1
解决办法
602
查看次数

Python 重载单个参数

假设我有一个带有许多参数的函数,例如

import pandas as pd

def f(df: pd.DataFrame, a: int, b: int, c: int, d: int, inplace: bool = True) -> Optional[pd.DataFrame]:
    raise NotImplementedError
Run Code Online (Sandbox Code Playgroud)

该函数将修改数据帧 ifinplace=True并返回修改后的副本 if inplace=False

我知道我能做到

@overload
def f(df: pd.DataFrame, a: int, b: int, c: int, d: int, inplace: Literal[True] = True) -> None:
    ...

@overload
def f(df: pd.DataFrame, a: int, b: int, c: int, d: int, inplace: Literal[False] = True) -> pd.DataFrame:
    ...
Run Code Online (Sandbox Code Playgroud)

通知打字系统这一事实。

但是,我想知道是否有一种方法可以在不重复整个函数定义的情况下执行此操作,如果有很多参数,这似乎很麻烦。我正在寻找类似的东西

@overload
def f(..., inplace: Literal[True]) -> None:
    ... …
Run Code Online (Sandbox Code Playgroud)

python overloading python-typing

6
推荐指数
1
解决办法
191
查看次数

“至少一个参数属于 X 类型”的类型注释

我试图使用重载来使可变参数函数的返回类型以某种方式依赖于其参数的类型。具体来说,当且仅当其任何参数的类型为 X 时,我希望返回类型为X。

考虑以下最小示例:

from typing import overload

class Safe:
    pass

class Dangerous:
    pass

@overload
def combine(*args: Safe) -> Safe: ...

@overload
def combine(*args: Safe | Dangerous) -> Safe | Dangerous: ...

def combine(*args: Safe | Dangerous) -> Safe | Dangerous:
    if all(isinstance(arg, Safe) for arg in args):
        return Safe()
    else:
        return Dangerous()

reveal_type(combine())
reveal_type(combine(Safe()))
reveal_type(combine(Dangerous()))
reveal_type(combine(Safe(), Safe()))
reveal_type(combine(Safe(), Dangerous()))
Run Code Online (Sandbox Code Playgroud)

这输出

example.py:21: note: Revealed type is "example.Safe"
example.py:22: note: Revealed type is "example.Safe"
example.py:23: note: Revealed …
Run Code Online (Sandbox Code Playgroud)

python overloading type-hinting mypy python-typing

6
推荐指数
1
解决办法
500
查看次数

指定通过输入接受的特定函数。Literal

如何指定typing我的函数仅接受特定的可调用对象?例如,我想要类似于这样的功能:

import typing

def accepted_function1():
    pass
def accepted_function2():
    pass

def function_accepting_functions(foo: Literal[accepted_function1, accepted_function2]):
    foo()
Run Code Online (Sandbox Code Playgroud)

python typing python-typing

6
推荐指数
1
解决办法
347
查看次数