标签: python-typing

装饰器更改返回类型时键入函数

如何正确编写返回类型被装饰器修改的函数的类型?

简单的例子:

def example_decorator(fn):
    def wrapper(data):
        res = fn(data)
        return ', '.join(res)

    return wrapper


@example_decorator
def func(data: list):  # -> ???? str ? list ?
    new_data = data
    new_data.append('XYZ')
    return new_data


# When we type func -> list

def test() -> str:
    result = func(['ABC', 'EFG'])
    print(type(result))  # <class 'str'>
    return result  # Incompatible return type [7]: Expected str but got list.


test()
Run Code Online (Sandbox Code Playgroud)

python python-3.x mypy python-typing pyre-check

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

当子类和父类都满足祖父母类型定义时,为什么 mypy 会报告类型不兼容?

给出以下代码:

from typing import Tuple


class Grandparent:
    items: Tuple[str, ...] = ()


class Parent(Grandparent):
    items = ('foo',)


class Child(Parent):
    items = ('foo', 'bar')
Run Code Online (Sandbox Code Playgroud)

mypy报告以下错误:

error: Incompatible types in assignment (expression has type "Tuple[str, str]", base class "Parent" defined the type as "Tuple[str]")
Run Code Online (Sandbox Code Playgroud)

像这样更改代码(在Parent类中再次指定相同的类型)满足mypy

error: Incompatible types in assignment (expression has type "Tuple[str, str]", base class "Parent" defined the type as "Tuple[str]")
Run Code Online (Sandbox Code Playgroud)

鉴于所有位置items的分配都满足相同/原始定义,为什么我需要在类层次结构中的多个位置重新指定相同的类型?items有没有办法避免这样做?

python mypy python-typing

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

如何从类变量引用静态方法

鉴于班级

from __future__ import annotations
from typing import ClassVar, Dict, Final
import abc

class Cipher(abc.ABC):
    @abc.abstractmethod
    def encrypt(self, plaintext: str) -> str:
        pass

    @abc.abstractmethod
    def decrypt(self, ciphertext: str) -> str:
        pass

class VigenereCipher(Cipher):
    @staticmethod
    def rotate(n: int) -> str:
        return string.ascii_uppercase[n:] + string.ascii_uppercase[:n]

    _TABLE: Final[ClassVar[Dict[str, str]]] = dict({(chr(i + ord("A")), rotate(i)) for i in range(26)})
Run Code Online (Sandbox Code Playgroud)

编译失败(使用 3.8.0

../cipher.py:19: in <module>
    class VigenereCipher(Cipher):
../cipher.py:24: in VigenereCipher
    _TABLE: Final[ClassVar[Dict[str, str]]] = dict({(chr(i + ord("A")), rotate(i)) for i in range(26)})
../cipher.py:24: …
Run Code Online (Sandbox Code Playgroud)

python static-methods decorator class-variables python-typing

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

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

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

举一个简单的例子,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
查看次数

__init__ 类中的 TypeVar 类型提示

我试图使用 TypeVar 来指示 init 参数为某种类型。但我做错了,或者根本不可能。

from typing import TypeVar

T=TypeVar("T")

class TestClass:
    def __init__(self,value:T):
        self._value=value

a = TestClass(value=10)
b = TestClass(value="abc")

reveal_type(a._value)
reveal_type(b._value)
Run Code Online (Sandbox Code Playgroud)

我希望揭露类型a._value会是int并且b._value一直是string。但它们都显示为“T`-1”

任何帮助或见解表示赞赏!

[编辑]

稍微扩展一点的例子。BaseClass 将被覆盖,实际类型提示由覆盖类提供。

from typing import TypeVar

T=TypeVar("T")

class BaseClass:
    def __init__(self,value):
        self._value = value

class Class1(BaseClass):
    def __init__(self,value:str):
        super().__init__(value)

class Class2(BaseClass):
    def __init__(self,value:int):
        super().__init__(value)

a = Class1("A value")
b = Class2(10)

reveal_type(a._value)
reveal_type(b._value)
Run Code Online (Sandbox Code Playgroud)

python python-typing

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

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

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
查看次数

Typing.NamedTuple 和可变默认参数

鉴于我想正确使用类型注释来命名来自打字模块的元组:

from typing import NamedTuple, List

class Foo(NamedTuple):
    my_list: List[int] = []

foo1 = Foo()
foo1.my_list.append(42)

foo2 = Foo()
print(foo2.my_list)  # prints [42]
Run Code Online (Sandbox Code Playgroud)

避免 Python 中可变默认值痛苦的最佳或最干净的方法是什么?我有一些想法,但似乎没有什么是好的

  1. None默认使用

    class Foo(NamedTuple):
        my_list: Optional[List[int]] = None
    
    foo1 = Foo()
    if foo1.my_list is None
      foo1 = foo1._replace(my_list=[])  # super ugly
    foo1.my_list.append(42)
    
    Run Code Online (Sandbox Code Playgroud)
  2. 覆盖__new____init__不起作用:

    AttributeError: Cannot overwrite NamedTuple attribute __init__
    AttributeError: Cannot overwrite NamedTuple attribute __new__
    
    Run Code Online (Sandbox Code Playgroud)
  3. 特别的 @classmethod

    class Foo(NamedTuple):
        my_list: List[int] = []
    
        @classmethod
        def use_me_instead(cls, my_list=None):
           if not my_list: …
    Run Code Online (Sandbox Code Playgroud)

python type-hinting namedtuple python-typing

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

键入一个带有可调用的函数

我有很多具有相同签名的函数,比如(int, int) -> int.

有没有办法用 a Callable(或其他东西)来输入这些函数,以避免为每个函数指定参数类型和返回类型?我想做类似的事情(但显然失败了):

from typing import Callable

f: Callable[[int, int], int]
def f(x, y):  #  with the previous line, this is equivalent to 'def f(x: int, y: int) -> int:'
    ...
Run Code Online (Sandbox Code Playgroud)

运行 mypy 结果:

file.py:4: error: Name "f" already defined on line 3
Found 1 error in 1 file (checked 1 source file)
Run Code Online (Sandbox Code Playgroud)

python type-hinting mypy python-typing

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

如何注释函数生成数据类?

dataclass假设你想像这样包装装饰器:

from dataclasses import dataclass

def something_else(klass):
    return klass

def my_dataclass(klass):
    return something_else(dataclass(klass))
Run Code Online (Sandbox Code Playgroud)

应该如何my_dataclass和/或something_else注释以指示返回类型是数据类?请参阅以下示例,了解内置函数如何@dataclass工作但自定义函数@my_dataclass则不然:


@dataclass
class TestA:
    a: int
    b: str

TestA(0, "") # fine


@my_dataclass
class TestB:
    a: int
    b: str

TestB(0, "") # error: Too many arguments for "TestB" (from mypy)
Run Code Online (Sandbox Code Playgroud)

python python-3.x mypy python-typing

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

使键入的字典中的所有键都不需要

我有一个包含多个条目的现有 TypedDict:

from typing import TypedDict
class Params(TypedDict):
    param1:str
    param2:str
    param3:str
Run Code Online (Sandbox Code Playgroud)

我想创建完全相同的 TypedDict 但所有键都是可选的,以便用户只能指定某些参数。我知道我可以做类似的事情:

class OptionalParams(TypedDict, total=False):
    param1:str
    param2:str
    param3:str
Run Code Online (Sandbox Code Playgroud)

但这种方法的问题是我必须复制代码。有没有办法通过使键可选来继承 Params ?我尝试做

class OptionalParams(Params, total=False):
    pass
Run Code Online (Sandbox Code Playgroud)

但 linter 不明白参数是可选的

python python-typing typeddict

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