Pau*_*aul 48 python dictionary scope function
使用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))这种修改可能是一个问题?
use*_*968 57
它总是安全的.正如规范所说
如果存在"**标识符"形式,则将其初始化为 接收任何多余关键字参数的新有序映射,默认为相同类型的新空映射.
强调补充说.
始终保证在可调用内部获取新的映射对象.看这个例子
def f(**kwargs):
    print((id(kwargs), kwargs))
kwargs = {'foo': 'bar'}
print(id(kwargs))
# 140185018984344
f(**kwargs)
# (140185036822856, {'foo': 'bar'})
因此,尽管f可以修改通过的对象**,但它无法修改调用者的对象**本身.
更新:既然你问过角落的情况,这里有一个特殊的地狱,实际上修改了调用者kwargs:
def f(**kwargs):
    kwargs['recursive!']['recursive!'] = 'Look ma, recursive!'
kwargs = {}
kwargs['recursive!'] = kwargs
f(**kwargs)
assert kwargs['recursive!'] == 'Look ma, recursive!'
不过,你可能不会在野外看到这一点.
use*_*ica 14
对于Python级代码,kwargs函数内的字典总是一个新的字典.
但是对于C扩展,请注意.C API版本kwargs有时会直接通过dict.在以前的版本中,它甚至会直接通过dict子类,导致bug(现在已修复)在哪里
'{a}'.format(**collections.defaultdict(int))
会产生'0'而不是提高KeyError.
如果您必须编写C扩展(可能包括Cython),请不要尝试修改kwargs等效项,并注意旧Python版本上的dict子类.