使用Python函数语法def f(**kwargs)
,在函数中创建一个关键字参数字典kwargs
,并且字典是可变的,所以问题是,如果我修改kwargs
字典,是否有可能在函数的作用域之外产生一些影响?
从我对字典解包和关键字参数打包工作原理的理解来看,我没有任何理由相信它可能是不安全的,而且在我看来,在Python 3.6中没有这种危险:
def f(**kwargs):
kwargs['demo'] = 9
if __name__ == '__main__':
demo = 4
f(demo=demo)
print(demo) # 4
kwargs = {}
f(**kwargs)
print(kwargs) # {}
kwargs['demo'] = 4
f(**kwargs)
print(kwargs) # {'demo': 4}
但是,这个实现是特定的,还是Python规范的一部分?我是否忽略了任何情况或实现(除非对自身可变的参数进行修改,比如kwargs['somelist'].append(3)
),这种修改可能是一个问题?
它总是安全的。作为spec says
增加了强调。
您总是可以保证在可调用的内部得到一个新的映射对象。看这个例子
因此,尽管
f
可以修改通过**
传递的对象,但它不能修改调用方的**
对象本身。更新:既然你问过角落里的案子,这里有一个特别的地狱给你,它实际上修改了来电者的
kwargs
:不过,在野外你可能看不到这个。
对于Python级别的代码,函数中的
kwargs
dict将始终是一个新的dict不过,对于C扩展,请注意。API版本的
kwargs
有时会直接传递dict。在以前的版本中,它甚至会直接传递dict子类,从而导致错误(now fixed),其中会产生
'0'
,而不是引起KeyError
。如果必须编写C扩展(可能包括Cython),请不要试图修改
kwargs
等价项,并注意旧Python版本上的dict子类。以上两个答案都是正确的,说明技术上,变异
kwargs
永远不会对父作用域产生影响。但是。。。这不是故事的结尾。在函数作用域之外共享到
kwargs
的引用是可能的,然后您会遇到所有常见的共享变异状态问题。从技术上讲,这回答了您的问题,因为共享对
mutable
kwargs的引用确实会导致超出函数作用域的效果在生产代码中,我已经多次被这个问题困扰,现在,无论是在我自己的代码中,还是在审查其他代码时,我都明确地注意到了这个问题。这个错误在我上面设计的例子中很明显,但是在创建共享一些公共选项的工厂函数时,它在实际代码中更隐蔽。
相关问题 更多 >
编程相关推荐