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

Python中如何模拟类属性调用的函数(不直接mock类属性)?

如何模拟Python类属性中调用的函数(避免直接模拟类属性)

在Python中,当尝试模拟类属性初始化时调用的外部函数时,会遇到这样的问题:实例化对象时的模拟有效,但直接访问未实例化的类属性时模拟失效。具体场景如下:

代码示例

methods.py

def bar():
    return "bar"

foo.py

from methods import bar

class Foo:
    class_attribute = bar()
    
    def __init__(self):
        self.class_attribute = bar()

原测试代码(test_foo.py)

from foo import Foo
import unittest
from unittest.mock import patch

class FooTestCase(unittest.TestCase):
    @patch("foo.bar")
    def test_mock_foo(self, mock):
        mock.return_value = "patched foo"
        print(Foo.class_attribute) # 输出 "bar"
        print(Foo().class_attribute) # 输出 "patched foo"

unittest.main(argv=[''], verbosity=0,exit=False)

问题原因

Foo.class_attribute 在模块导入阶段就已经执行了 bar() 并完成赋值,此时测试中的 patch 还未生效,所以拿到的是原始的"bar";而实例化时的 self.class_attribute 是在 patch 生效后调用的 bar(),因此能拿到模拟值。

解决方案(不直接模拟类属性)

方案1:patch生效后重新加载模块

通过重新加载 foo 模块,让类的定义重新执行,此时 bar() 会使用已经被patch的版本,从而更新类属性的值。

修改后的test_foo.py:

import unittest
from unittest.mock import patch
import importlib
import foo

class FooTestCase(unittest.TestCase):
    @patch("foo.bar")
    def test_mock_foo(self, mock):
        mock.return_value = "patched foo"
        # 重新加载foo模块,触发类的重新定义
        importlib.reload(foo)
        # 更新当前测试模块中的Foo引用
        Foo = foo.Foo
        
        print(Foo.class_attribute) # 输出 "patched foo"
        print(Foo().class_attribute) # 输出 "patched foo"

unittest.main(argv=[''], verbosity=0,exit=False)

方案2:延迟类属性的计算时机

修改 foo.py,将类属性的计算延迟到第一次访问时,确保调用 bar() 时 patch 已经生效。可以使用类级别的 property 实现:

修改后的foo.py:

from methods import bar

class Foo:
    @classmethod
    def _get_class_attribute(cls):
        if not hasattr(cls, '_cached_class_attribute'):
            cls._cached_class_attribute = bar()
        return cls._cached_class_attribute
    
    # 将class_attribute定义为类属性的property
    class_attribute = property(_get_class_attribute)
    
    def __init__(self):
        self.class_attribute = bar()

此时原测试代码无需修改,运行后 Foo.class_attribute 会输出"patched foo"。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 20:50:10