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

使用mypy检查代码时赋值类方法引用报错的原因与疑问

mypy检查Python代码时的方法赋值报错问题

问题场景

类B是抽象类A的子类,必须实现抽象方法foo。由于foo的实际逻辑依赖B的初始化参数shouldUseG,因此在__init__中通过工厂方法_factory_to_generate_function为self.foo赋值,同时在类中声明了空的foo方法(第25行)。运行mypy检查时,第17行出现报错:

原代码

from typing import Callable
from abc import ABCMeta, abstractmethod

class A(metaclass = ABCMeta):

    def __init__(self):
        pass

    @abstractmethod
    def foo(self):
        raise NotImplementedError

class B(A):

    def __init__(self, shouldUseG: bool):
        super().__init__()
        self.foo: Callable = self._factory_to_generate_function(shouldUseG) # line 17

    def _factory_to_generate_function(self, shouldUseG: bool) -> Callable:

        read_data_function: Callable = {True:  self.g,
                                        False: self.h}[shouldUseG]
        return read_data_function

    def foo(self): # line 25
        pass

    def g(self):
        print('This is g.')

    def h(self):
        print('This is h.')

mypy报错信息

test.py:17: error: Cannot assign to a method  [assignment]
Found 1 error in 1 file (checked 1 source file)

删除第25行的foo方法声明后,报错消失,想明确两个问题:

  1. 该报错为何出现?
  2. 是否可以通过第17行的赋值方式实现抽象方法,无需再声明foo方法?

问题解答

1. 报错原因

当你在类B中声明def foo(self): pass时,这个foo是类层面的方法属性。而在__init__中执行self.foo = ...,是给实例属性赋值,此时实例属性会隐藏类的同名方法。mypy会将这种“给已存在的类方法赋值实例属性”的行为判定为错误,因为它违背了Python中方法的定义逻辑(方法属于类,实例调用时自动绑定),所以抛出Cannot assign to a method的报错。

2. 可以通过赋值实现抽象方法,无需声明空方法

只需调整类型注解,让mypy识别foo是实例属性而非类方法即可,步骤如下:

  • 删除第25行的空foo方法声明
  • 在类B中添加foo: Callable的类型注解,明确告知mypy这是一个实例属性,类型为可调用对象

修改后的代码

from typing import Callable
from abc import ABCMeta, abstractmethod

class A(metaclass=ABCMeta):
    def __init__(self):
        pass

    @abstractmethod
    def foo(self):
        raise NotImplementedError

class B(A):
    foo: Callable  # 明确标注实例属性类型

    def __init__(self, shouldUseG: bool):
        super().__init__()
        self.foo = self._factory_to_generate_function(shouldUseG)

    def _factory_to_generate_function(self, shouldUseG: bool) -> Callable:
        read_data_function: Callable = {True: self.g, False: self.h}[shouldUseG]
        return read_data_function

    def g(self):
        print('This is g.')

    def h(self):
        print('This is h.')

补充说明

  • 若使用Python 3.10+,可以用typing.InstanceVar更精准地标注实例属性:
    from typing import Callable, InstanceVar
    # ...
    class B(A):
        foo: InstanceVar[Callable]
    
    这样mypy会更清晰地区分实例属性和类属性,避免混淆。
  • 修改后,mypy会认可这种实现方式,因为抽象类A只要求实例拥有可调用的foo属性,不管它是类方法还是实例属性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 17:50:21