Python: Difference between kwargs.pop() and kwargs.get()

43,299

Solution 1

get(key[, default]): return the value for key if key is in the dictionary, else default. If default is not given, it defaults to None, so that this method never raises a KeyError.

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

pop(key[, default]) if key is in the dictionary, remove it and return its value, else return default. If default is not given and key is not in the dictionary, a KeyError is raised.

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: Regarding best practice question, I would say it depends on your use case but I would go by default for .get unless I have a real need to .pop

Solution 2

The difference is pop also removes the item from the dict.

There is no best practice. Use the one which is more convenient for your particular use case.

Most times, all you need is getting the value.

Other times, you want to make sure no extra/unexpected kwargs are provided. In this case, it is convenient to use pop. E.g.:

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

Solution 3

Consider the next example, where the use of get or pop makes a difference:

Let's begin with 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')

This code snippet raises TypeError exception:

TypeError: __init__() got an unexpected keyword argument 'bar_param'

When Bar executes super(Bar, self).__init__(**kwargs) it is forwarding to Foo the same dict he has recived: {foo_param='F', bar_param='B'}. Then Foo raises TypeError because input paramteres doesn't respect its interface.

If you pop bar_param before executing the call to super, Foo only recives its required input parameter foo_param, and all goes fine.

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')

Output is:

In Bar: B
In Foo: F

Solution 4

So the get and pop functions do very different things

get is used to return a value for a given key in the dictionary

pop removes the value from the dictionary and returns the removed value

All of the dictionary functions are documented here (for python3): https://docs.python.org/3/library/stdtypes.html#mapping-types-dict

Share:
43,299
Aliquis
Author by

Aliquis

Updated on July 30, 2020

Comments

  • Aliquis
    Aliquis almost 4 years

    I have seen both ways but I do not understand what the difference is and what I should use as "best practice":

    def custom_function(**kwargs):
        foo = kwargs.pop('foo')
        bar = kwargs.pop('bar')
        ...
    
    def custom_function2(**kwargs):
        foo = kwargs.get('foo')
        bar = kwargs.get('bar')
        ...
    
  • Martlark
    Martlark over 3 years
    I'd suggest that this use case is dangerous. Build a new kwargs for any subsequent class intialization with the expected parameters. You should not modify the parent kwargs for onward use. That has a code smell.