Python 中泛型函数的最佳实践

问题描述 投票:0回答:2

我读过很多关于泛型类的内容,虽然这些很酷,但有时,我只需要一个泛型函数。这是我写的一篇小文章:

def _matrix_map(self, mapper):
    """returns the matrix applying the mapper funcfunc"""
    return {key: mapper(value) for key, value in self._matrix.items()}

这应该如何为类型进行注释。在具有通用支持的静态类型语言中,我会这样写

private Dictionary<KeyType, ValueType> matrix;
private Dictionary<KeyType, T> matrix_map<T>(Func<ValueType, T>)

所以,我想我应该这样写:

T = TypeVar('T')
def _matrix_map(self, mapper: Callable[[Tile], T]) -> Dict[Coordinate, T]:

我像这样通过 mypy 传递了它,但 pylint 讨厌这个。

第一行:

C0103:Invalid class attribute name "T"

第二行:

E0602:Undefined variable 'T'

所以我觉得我做错了什么,我可以更改变量名称(

ttt
typ
?),但这并不能解决第二个问题。我不是第一个想要(静态类型)泛型函数的人,但我在任何地方都找不到任何好的资源。有什么推荐吗?

python pylint mypy
2个回答
10
投票

我猜你写的代码大致是这样的?

class Matrix:
    T = TypeVar('T')

    def _matrix_map(self, mapper: Callable[[Tile], T]) -> Dict[Coordinate, T]:
        # ...snip...

实际上在运行时没有问题/mypy 没有问题,但 pylint 似乎对您将“T”放在类定义的范围内不满意。为了满足 pylint 的要求,你可以这样做:

T = TypeVar('T')

class Matrix:
    def _matrix_map(self, mapper: Callable[[Tile], T]) -> Dict[Coordinate, T]:
        # ...snip...

这与前面的代码片段完全相同,并且也满足 pylint。

(顺便说一句,我认为 pylint 对前者不满意的事实实际上是一个错误。但公平地说,目前还没有任何关于类型提示最佳实践的既定风格指南/放置嵌套作用域内的 typevar 是一个不太常见的用例,所以我想我不能真的责怪他们没有考虑到这种情况。)

唯一的缺点是,将 TypeVar 放在外部确实看起来有点不整洁/似乎会污染全局名称空间。您可以通过将其重命名为类似

_T
之类的名称来部分缓解此问题,以表明它是私有的。每当您需要另一个泛型类或函数时,您也可以重用此类型变量,这也有望有助于减少命名空间污染。

有关使用带有 Python 类型提示的泛型的更多信息,请参阅 http://mypy.readthedocs.io/en/stable/generics.html


0
投票

随着 Python 3.12 中引入 类型参数列表,不再需要显式定义

TypeVar
。 (另请注意,
typing.Dict
在 Python 3.9 中已弃用,因为可以使用
dict
本身来代替。)

from collections.abc import Callable


class Matrix:
    def _matrix_map[T](self, mapper: Callable[[Tile], T]) -> dict[Coordinate, T]:
        ...

如果类型参数要被所有方法共享,也可以在类级别声明。

class Matrix[T]:
    def _matrix_map(self, mapper: Callable[[Tile], T]) -> dict[Coordinate, T]:
        ...
© www.soinside.com 2019 - 2024. All rights reserved.