python中泛型函数的最佳实践

McK*_*Kay 5 python pylint mypy

我已经阅读了很多关于泛型类的文章,虽然这些很酷,但有时,我只需要一个泛型函数。这是我写的一小段:

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

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

private Dictionary<KeyType, ValueType> matrix;
private Dictionary<KeyType, T> matrix_map<T>(Func<ValueType, T>)
Run Code Online (Sandbox Code Playgroud)

所以,我想我会这样写:

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

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

在第一行:

C0103:Invalid class attribute name "T"
Run Code Online (Sandbox Code Playgroud)

在第二行:

E0602:Undefined variable 'T'
Run Code Online (Sandbox Code Playgroud)

所以,我觉得我做错了什么,我可以改变的变量名(ttttyp?),但不会解决第二个问题。我不能成为第一个想要(静态类型的)泛型函数的人,但我在任何地方都找不到任何好的资源。有什么建议吗?

Mic*_*x2a 6

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

class Matrix:
    T = TypeVar('T')

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

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

T = TypeVar('T')

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

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

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

唯一的缺点是,将 TypeVar 放在外部确实看起来有点不整洁/似乎会污染全局名称空间。您可以通过将其重命名为类似的名称来部分缓解此问题_T,以表明它是私有的。每当您需要另一个泛型类或函数时,您也可以重用此类型变量,这也有望有助于减少命名空间污染。

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