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

Python 3.5与3.6自定义对象**解包行为差异及相关疑问

关于Python 3.5与3.6中Container(**data0, b=7)行为差异的解答

先还原问题场景中的核心代码:

class Container:
    KEYS = ('a', 'b', 'c')
    def __init__(self, a=None, b=None, c=None):
        self.a = a
        self.b = b
        self.c = c
    def keys(self):
        return Container.KEYS
    def __getitem__(self, key):
        if key not in Container.KEYS:
            raise KeyError(key)
        return getattr(self, key)
    def __str__(self):
        # Python 3.6写法
        # return f'{self.__class__.__name__}(a={self.a}, b={self.b}, c={self.c})'
        # Python 3.5写法
        return ('{self.__class__.__name__}(a={self.a}, b={self.b}, '
                'c={self.c})').format(self=self)

data0 = Container(a=1, b=2, c=3)
print(data0)
data3 = Container(**data0, b=7)
print(data3)

两种Python版本的行为差异:

  • Python 3.6:抛出TypeError: type object got multiple values for keyword argument 'b'
  • Python 3.5:抛出KeyError: 0

问题1:Python 3.5与3.6之间的哪些变更导致了这种行为差异?

核心差异在于**操作符对自定义对象的处理逻辑:

  • 在Python 3.5中,解释器判断一个对象能否被**展开为键值对,严格依赖它是否属于collections.abc.Mapping类型(或完全符合mapping接口规范)。你的Container类虽然实现了keys()和__getitem__,但缺少__iter__方法,也没有继承自Mapping抽象类,因此不会被当作mapping处理。

    这时解释器会退而求其次,尝试将对象视为可迭代的(key, value)对序列。但因为类没有实现__iter__,Python会启用默认迭代器逻辑:从整数0开始,依次调用__getitem__(0)、__getitem__(1)……直到抛出IndexError。而你的__getitem__只接受'a'/'b'/'c'作为键,所以第一次调用__getitem__(0)就抛出了KeyError: 0。

  • 在Python 3.6中,官方调整了**操作符的处理逻辑:只要对象实现了keys()和__getitem__方法,就会被当作mapping来处理,直接遍历keys()返回的键生成对应键值对。因此**data0会正确展开为a=1, b=2, c=3,后续传入的b=7会和展开的b=2产生参数冲突,抛出TypeError——这其实是更符合预期的正确行为。


问题2:这些整数序列的来源是什么?

当Python尝试迭代一个没有实现__iter__方法的对象时,会自动启用默认迭代器实现:它会从整数0开始,依次以递增的整数作为参数调用__getitem__,直到调用时抛出IndexError才停止迭代。

你修改__getitem__后没有抛出异常,而是打印key并返回,所以这个默认迭代器会无限生成0、1、2、3……这样的连续整数,这就是你看到的整数序列的来源。


更新说明:实现__iter__后行为一致的原因

当你为Container添加以下__iter__方法后:

def __iter__(self):
    return iter(Container.KEYS)

Python 3.5的解释器会将Container对象视为可迭代的键序列(迭代'a'、'b'、'c'),此时**data0会遍历这些键生成对应的键值对a=1, b=2, c=3,后续的b=7同样会引发参数冲突,因此行为和Python 3.6完全一致。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:21:37