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

为何Python的create_autospec访问下划线字段会触发Property getter且触发两次?

使用create_autospec时访问下划线字段触发属性getter的问题

我用Python的unittest.mock.create_autospec()创建类的mock对象时,遇到了异常行为:直接访问下划线前缀字段mock._val时,会触发val属性的getter方法,我原本以为访问下划线前缀字段不会触发getter。另外,getter方法还被调用了两次。这是预期行为吗?如果是,为什么要这么设计?

复现代码

from unittest.mock import create_autospec

def test_strange_behavior():
    class MyCls:
        def __init__(self):
            self._val = None

        @property
        def val(self):
            print("Inside Get")
            return self._val

        @val.setter
        def val(self, value):
            print("Inside Set")
            self._val = value

    mock = create_autospec(spec=MyCls(), spec_set=True)
    print("Before")
    print(mock._val)  # 此行触发val的getter方法
    print("After")

环境信息

$ python --version
Python 3.10.6
$ pip list | grep pytest
pytest                7.1.3

运行输出

$ pytest my_test.py -s
============================================================================================================================== test session starts ===============================================================================================================================
platform linux -- Python 3.10.6, pytest-7.1.3, pluggy-1.0.0
rootdir: /home/david/PycharmProjects/test
plugins: Faker-13.3.4, postgresql-5.0.0
collected 1 item

my_test.py Inside Get  # 第一次调用
Inside Get  # 第二次调用
Before
<NonCallableMagicMock name='mock._val' id='140286340235120'>
After
.

=============================================================================================================================== 1 passed in 0.02s ================================================================================================================================

解答

这是预期行为吗?

是,这属于create_autospec结合spec_set=True时的预期行为。

为什么会出现这种情况?

原因在于create_autospec的工作机制:

  1. 第一次getter调用:当你传入spec=MyCls()(实例对象)时,create_autospec会遍历该实例的所有可访问属性,包括val(property)和_val(实例属性)。为了模拟val这个property的行为,函数会调用一次其getter方法来获取返回值的类型,以此生成匹配的mock属性,这就触发了第一次"Inside Get"。
  2. 第二次getter调用:当spec_set=True时,mock会严格限制只能访问spec对象中存在的属性。访问mock._val时,mock会先验证该属性是否存在于spec实例中。在这个验证过程中,mock的内部实现会间接触发val的getter——这是因为mock在处理属性检查时,依赖Python的属性查找逻辑,而val的getter恰好关联了_val字段,导致调用链被触发。

如何避免这种行为?

建议将spec参数传入类而非实例,即:

mock = create_autospec(spec=MyCls, spec_set=True)

这样create_autospec会模拟类的结构而非实例的具体属性,访问mock._val时就不会触发val的getter方法了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 04:17:07