You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

numpy.apply_along_axis触发mypy类型不兼容错误的解决方法

问题:numpy.apply_along_axis触发mypy类型不兼容错误

2024年10月18日补充:简化复现代码

以下是最小化的问题复现代码:

mypy_arg_type.py:

import numpy as np
from numpy.typing import NDArray
import random

def winner(_: NDArray[np.bytes_]) -> bytes | None:
    return b"." if bool(random.randint(0, 1)) else None

board = np.full((2, 2), ".", "|S1")
for w in np.apply_along_axis(winner, 0, board):
    print(w)

运行Python代码输出:

b'.'
None

运行mypy检查报错:

mypy_arg_type.py:9: error: Argument 1 to "apply_along_axis" has incompatible type "Callable[[ndarray[Any, dtype[bytes_]]], bytes | None]"; expected "Callable[[ndarray[Any, dtype[Any]]], _SupportsArray[dtype[Never]] | _NestedSequence[_SupportsArray[dtype[Never]]]]"  [arg-type]
mypy_arg_type.py:9: note: This is likely because "winner" has named arguments: "_". Consider marking them positional-only
Found 1 error in 1 file (checked 1 source file)

原始问题背景

我正在实现四子棋的获胜判断功能,棋盘尺寸为6x7,列标从A到G,获胜条件是横、竖、斜向或反斜向连成4枚同色棋子。

示例

  • 输入:["A_Red", "B_Yellow", "A_Red", "B_Yellow", "A_Red", "B_Yellow", "G_Red", "B_Yellow"]
  • 棋盘状态:
R Y . . . . R
R Y . . . . .
R Y . . . . .
. Y . . . . .
. . . . . . .
. . . . . . .
  • 获胜者:Yellow

实现代码

import itertools
import numpy as np
from numpy.typing import NDArray

def who_is_winner(pieces: list[str]) -> str:
    def parse_board() -> NDArray[np.bytes_]:
        m, n = 6, 7
        indices = [0] * n
        # 单字节编码,字节序为‘|’(不适用)
        board = np.full((m, n), ".", "|S1")
        for p in pieces:
            col = ord(p[0]) - ord("A")
            board[indices[col], col] = p[2]
            indices[col] += 1

        return board

    def winner(arr: NDArray[np.bytes_]) -> np.bytes_ | None:
        i = len(arr)
        xs = next(
            (xs for j in range(i - 3) if (xs := set(arr[j : j + 4])) < {b"R", b"Y"}),
            {None},
        )
        return xs.pop()

    def axis(x: int) -> np.bytes_ | None:
        # Axis 0是按列处理,1是按行处理
        return next(
            (w for w in np.apply_along_axis(winner, x, board) if w is not None), None
        )

    def diag(d: int) -> np.bytes_ | None:
        # 对角线编号相对于主对角线
        b = board if bool(d) else np.fliplr(board)
        return next(
            (w for d in range(-3, 4) if (w := winner(b.diagonal(d))) is not None), None
        )

    board = parse_board()
    match next(
        (
            w
            for f, i in itertools.product((axis, diag), (0, 1))
            if (w := f(i)) is not None
        ),
        None,
    ):
        case b"Y":
            return "Yellow"
        case b"R":
            return "Red"
        case _:
            return "Draw"

mypy报错信息

error: Argument 1 to "apply_along_axis" has incompatible type "Callable[[ndarray[Any, dtype[bytes_]]], bytes_ | None]"; expected "Callable[[ndarray[Any, dtype[Any]]], _SupportsArray[dtype[bytes_]] | _NestedSequence[_SupportsArray[dtype[bytes_]]]]"  [arg-type]
note: This is likely because "winner" has named arguments: "arr". Consider marking them positional-only

根据apply_along_axis的文档,该函数允许返回单个值,和我的代码逻辑一致。将winner改为位置参数后,仅移除了提示信息,但错误依然存在。使用环境:Python 3.12.5、mypy 1.11.2。


解决方案

方法1:调整winner函数的类型注解

mypy对apply_along_axis的类型定义要求输入函数能接受任意dtype的数组,同时返回值需符合数组或嵌套序列的约束。可以放宽输入参数类型,并将返回的单个值包装成数组:

def winner(arr: NDArray[np.generic]) -> NDArray[np.bytes_] | None:
    result = b"." if bool(random.randint(0, 1)) else None
    return np.array(result, dtype="|S1") if result is not None else None

方法2:用typing.cast绕过类型检查

若确认逻辑正确,仅需绕过mypy的类型推断,可强制转换函数类型:

from typing import cast, Callable
import numpy as np
from numpy.typing import NDArray, _SupportsArray, dtype

# 在调用处转换类型
winner_cast = cast(Callable[[NDArray[np.generic]], _SupportsArray[dtype[np.bytes_]] | None], winner)
for w in np.apply_along_axis(winner_cast, 0, board):
    print(w)

方法3:升级依赖版本

numpy的部分类型定义问题在新版本中已修复,尝试升级到numpy 2.0+和mypy 1.12+,可能自动解决类型不兼容问题。

方法4:手动遍历替代apply_along_axis

避免使用apply_along_axis,直接遍历数组的行/列,完全控制类型:

# 替代apply_along_axis(winner, 0, board)的循环
for col in board.T:
    w = winner(col)
    if w is not None:
        print(w)

内容的提问来源于stack exchange,提问作者Abhijit Sarkar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 05:07:21