python 的 **kwargs 效率
python's **kwargs efficiency
像这样建立python3流程可以吗?
def foo(**kwargs):
kwargs['kw'] = 1
return bar(**kwargs, wk=2)
def bar(**kwargs):
process(1,2,'sss',**kwargs)
for i in kwargs:
print(i)
...etc...
kwargs 是否会成为单个可变对象 (dict
),并且只有它的引用会传递到流程中,还是我会被解压并一遍又一遍地创建?
更精确的问题。如果我这样做:
def a(**kwargs):
return b(**kwargs)
def b(**kwargs):
return c(**kwargs)
...
def z(**kwargs):
print(**kwargs)
会不会一次只有 1 个 dict?如果是这样,每次调用都会创建新对象吗?
或者我会堆叠它们吗?
实际情况是我是与AVRO通信的子服务之一。所以我有一个包可以将该二进制文件转换为 dict
,然后我需要做一些事情并创建一个新的 AVRO。
有些字段在新模式中不存在,有些是添加的,有些只是通过而不触及它们。
所以我只是拿了第一个字典,一遍又一遍地传递它添加越来越多的数据然后最后我有另一个模式和 avro 包可以接受这么大的字典并只序列化模式中定义的内容。
这种方法可以吗?
为每个函数中的每个 **kwargs
参数构建一个新字典。那是因为 call **kwargs
语法不同于函数签名中的语法
- 在调用中使用
**kwargs
会导致字典被解压缩到单独的关键字参数中。
- 使用
**kwargs
作为 catch-all 参数会导致根据传入的关键字参数生成 字典。
即使情况并非如此,Python 也无法通过共享词典进行优化。调用 bar()
的函数 foo()
必须处理传递给调用的字典 kwargs
可能发生变异的可能性。
所以,不,在一系列连接函数中使用 **kwargs
不会提高效率。
一个快速演示,展示传递给一系列函数的字典是不同的:
>>> def a(**kwargs):
... print('a', id(kwargs))
... b(**kwargs)
...
>>> def b(**kwargs):
... print('b', id(kwargs))
...
>>> a(foo='bar')
a 4556474552
b 4557517304
如果共享词典,它们的 id()
值也会相同。
如果您想在函数之间传递共享状态,请明确地进行。直接传字典,例如:
def foo(**state):
state['kw'] = 1
state['wk'] = 2
return bar(state) # kwargs passed in as a single argument
def bar(state):
# etc.
很容易直接找出发生了什么:
def a(**kwargs):
b(**kwargs)
print(kwargs) # prints {'x': 1}, not {'x': 1, 'y': 2}
def b(**kwargs):
kwargs['y'] = 2
a(x=1)
所以每次都有一个新的dict。
郑重声明,我非常喜欢 Martijn 的回答。要按照我相信的方式回答您的问题,您需要像 Martijn 所说的那样跳过 **
;
def a(some_dict):
# do some operations on this dict
b(some_dict)
def b(some_dict):
# do some more operations on this dict
c(some_dict)
def c(some_dict):
# you know how this goes by know, don't you?
# Careful thing to note here: you do not need to reassign here,
# since each function are dealing with a reference to the same
# original object, there is no need to pass it back when we are
# done.
a(some_dict)
进一步补充,这在我认为是工厂模式的地方很常见;
class CookLasagna:
def __init__(self, lasagna=None):
self.lasagna = lasagna
self.build()
def build(self):
self.preheat_oven()
self.cook_minced_meat()
self.soak_pasta()
self.layer()
def preheat_oven(self):
# preheat the oven with lasagna object reference
def cook_minced_meat(self):
# cook minced meat with lasagna object reference
def soak_pasta(self):
# soak pasta with lasagna object reference
def layer(self):
# layer with lasagna object reference
像这样建立python3流程可以吗?
def foo(**kwargs):
kwargs['kw'] = 1
return bar(**kwargs, wk=2)
def bar(**kwargs):
process(1,2,'sss',**kwargs)
for i in kwargs:
print(i)
...etc...
kwargs 是否会成为单个可变对象 (dict
),并且只有它的引用会传递到流程中,还是我会被解压并一遍又一遍地创建?
更精确的问题。如果我这样做:
def a(**kwargs):
return b(**kwargs)
def b(**kwargs):
return c(**kwargs)
...
def z(**kwargs):
print(**kwargs)
会不会一次只有 1 个 dict?如果是这样,每次调用都会创建新对象吗? 或者我会堆叠它们吗?
实际情况是我是与AVRO通信的子服务之一。所以我有一个包可以将该二进制文件转换为 dict
,然后我需要做一些事情并创建一个新的 AVRO。
有些字段在新模式中不存在,有些是添加的,有些只是通过而不触及它们。
所以我只是拿了第一个字典,一遍又一遍地传递它添加越来越多的数据然后最后我有另一个模式和 avro 包可以接受这么大的字典并只序列化模式中定义的内容。
这种方法可以吗?
为每个函数中的每个 **kwargs
参数构建一个新字典。那是因为 call **kwargs
语法不同于函数签名中的语法
- 在调用中使用
**kwargs
会导致字典被解压缩到单独的关键字参数中。 - 使用
**kwargs
作为 catch-all 参数会导致根据传入的关键字参数生成 字典。
即使情况并非如此,Python 也无法通过共享词典进行优化。调用 bar()
的函数 foo()
必须处理传递给调用的字典 kwargs
可能发生变异的可能性。
所以,不,在一系列连接函数中使用 **kwargs
不会提高效率。
一个快速演示,展示传递给一系列函数的字典是不同的:
>>> def a(**kwargs):
... print('a', id(kwargs))
... b(**kwargs)
...
>>> def b(**kwargs):
... print('b', id(kwargs))
...
>>> a(foo='bar')
a 4556474552
b 4557517304
如果共享词典,它们的 id()
值也会相同。
如果您想在函数之间传递共享状态,请明确地进行。直接传字典,例如:
def foo(**state):
state['kw'] = 1
state['wk'] = 2
return bar(state) # kwargs passed in as a single argument
def bar(state):
# etc.
很容易直接找出发生了什么:
def a(**kwargs):
b(**kwargs)
print(kwargs) # prints {'x': 1}, not {'x': 1, 'y': 2}
def b(**kwargs):
kwargs['y'] = 2
a(x=1)
所以每次都有一个新的dict。
郑重声明,我非常喜欢 Martijn 的回答。要按照我相信的方式回答您的问题,您需要像 Martijn 所说的那样跳过 **
;
def a(some_dict):
# do some operations on this dict
b(some_dict)
def b(some_dict):
# do some more operations on this dict
c(some_dict)
def c(some_dict):
# you know how this goes by know, don't you?
# Careful thing to note here: you do not need to reassign here,
# since each function are dealing with a reference to the same
# original object, there is no need to pass it back when we are
# done.
a(some_dict)
进一步补充,这在我认为是工厂模式的地方很常见;
class CookLasagna:
def __init__(self, lasagna=None):
self.lasagna = lasagna
self.build()
def build(self):
self.preheat_oven()
self.cook_minced_meat()
self.soak_pasta()
self.layer()
def preheat_oven(self):
# preheat the oven with lasagna object reference
def cook_minced_meat(self):
# cook minced meat with lasagna object reference
def soak_pasta(self):
# soak pasta with lasagna object reference
def layer(self):
# layer with lasagna object reference