Python: kwargs.pop() 和 kwargs.get() 之间的区别

47

我看过这两种方式,但我不明白它们之间的区别以及我应该使用哪一种作为“最佳实践”:

def custom_function(**kwargs):
    foo = kwargs.pop('foo')
    bar = kwargs.pop('bar')
    ...

def custom_function2(**kwargs):
    foo = kwargs.get('foo')
    bar = kwargs.get('bar')
    ...

3
Hint: see help(dict) - heemayl
6
@heemayl 或者更具体地说:help(dict.get)help(dict.pop)... 意思是请求获取 dict.get()dict.pop() 方法的帮助文档。 - Jon Clements
最佳实践通常是在需要调用超级函数但不想使用特定参数时使用pop,而对于其他任何事情,get是您的选择,或者使用get_object_or_404。 - ineedme
1
如果您已经找到了最佳答案来回答您的问题,请考虑接受它。 - JoYSword
1
如果您需要从字典中删除键/值,请使用pop。如果您只需要检索值,请使用get。提供默认值以避免抛出异常。下面的答案总结了所有内容。请参阅@DhiaTN的帖子https://dev59.com/g1UM5IYBdhLWcg3wKNyB#49218410。 - Carlos
4个回答

59

get(key[, default]): 如果 key 在字典中,返回对应的值;如果不在,则返回默认值 default。如果没有提供 default 参数,默认值为 None,因此该方法永远不会引发 KeyError 异常。

d = {'a' :1, 'c' :2}
print(d.get('b', 0)) # return 0
print(d.get('c', 0)) # return 2

pop(key[, default]) 如果字典中存在 key,则删除它并返回其值,否则返回默认值。如果未提供默认值且字典中不存在 key,则引发 KeyError 异常。

d = {'a' :1, 'c' :2}
print(d.pop('c', 0)) # return 2
print(d) # returns {'a': 1}
print(d.get('c', 0)) # return 0

NB:关于最佳做法的问题,我会说这取决于您的用例,但我默认使用.get,除非我真正需要.pop


13

区别在于pop还会从字典中移除该项。

没有最佳实践。使用更适合特定用例的那个。

大多数情况下,你只需要获取值。

其他情况下,你希望确保不提供额外/意外的kwargs。此时,使用pop很方便。例如:

a = kw.pop('a')
b = kw.pop('b')
if kw:
    raise TypeError('Unepxected kwargs provided: %s' % list(kw.keys()))

12

考虑下一个例子,在这个例子中使用getpop会有所不同:

让我们从get开始:

class Foo(object):
    def __init__(self, foo_param=None):
        print("In Foo: {}".format(foo_param))

class Bar(Foo):
    def __init__(self, **kwargs):
        bar_param = kwargs.get('bar_param')
        print("In Bar: {}".format(bar_param))
        super(Bar, self).__init__(**kwargs)

bar = Bar(foo_param='F', bar_param='B')

这段代码引发了TypeError异常:

TypeError: __init__() got an unexpected keyword argument 'bar_param'
当Bar执行super(Bar, self).__init__(**kwargs)时,它将收到的相同字典转发给了Foo:{foo_param='F', bar_param='B'}。然后Foo会抛出TypeError异常,因为输入参数不符合其接口规范。
如果在调用super之前使用pop方法从字典中移除bar_param,那么Foo只会收到所需的foo_param输入参数,程序就可以正常运行。
class Foo(object):
    def __init__(self, foo_param=None):
        print("In Foo: {}".format(foo_param))

class Bar(Foo):
    def __init__(self, **kwargs):
        bar_param = kwargs.pop('bar_param')
        print("In Bar: {}".format(bar_param))
        super(Bar, self).__init__(**kwargs)

bar = Bar(foo_param='F', bar_param='B')

输出结果为:

In Bar: B
In Foo: F

我建议这种用法很危险。为了使用后续类的预期参数,为其构建一个新的kwargs。不应修改父级kwargs以供后续使用。那样会有代码异味。 - Martlark

5

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接