In Python, what does dict.pop(a,b) mean?
class a(object):
data={'a':'aaa','b':'bbb','c':'ccc'}
def pop(self, key, *args):
return self.data.pop(key, *args)#what is this mean.
b=a()
print b.pop('a',{'b':'bbb'})
print b.data
self.data.pop(key, *args)
←------ why is there a second argument?
The pop
method of dicts (like self.data
, i.e. {'a':'aaa','b':'bbb','c':'ccc'}
, here) takes two arguments -- see the docs
The second argument, default
, is what pop
returns if the first argument, key
, is absent.
(If you call pop
with just one argument, key
, it raises an exception if that key's absent).
In your example, print b.pop('a',{'b':'bbb'})
, this is irrelevant because 'a'
is a key in b.data
. But if you repeat that line...:
b=a()
print b.pop('a',{'b':'bbb'})
print b.pop('a',{'b':'bbb'})
print b.data
you'll see it makes a difference: the first pop
removes the 'a'
key, so in the second pop
the default
argument is actually returned (since 'a'
is now absent from b.data
).
So many questions here. I see at least two, maybe three:
- What does pop(a,b) do?/Why are there a second argument?
- What is
*args
being used for?
The first question is trivially answered in the Python Standard Library reference:
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.
The second question is covered in the Python Language Reference:
If the form “*identifier” is present, it is initialized to a tuple receiving any excess positional parameters, defaulting to the empty tuple. If the form “**identifier” is present, it is initialized to a new dictionary receiving any excess keyword arguments, defaulting to a new empty dictionary.
In other words, the pop
function takes at least two arguments. The first two get assigned the names self
and key
; and the rest are stuffed into a tuple called args
.
What's happening on the next line when *args
is passed along in the call to self.data.pop
is the inverse of this - the tuple *args
is expanded to of positional parameters which get passed along. This is explained in the Python Language Reference:
If the syntax *expression appears in the function call, expression must evaluate to a sequence. Elements from this sequence are treated as if they were additional positional arguments
In short, a.pop()
wants to be flexible and accept any number of positional parameters, so that it can pass this unknown number of positional parameters on to self.data.pop()
.
This gives you flexibility; data
happens to be a dict
right now, and so self.data.pop()
takes either one or two parameters; but if you changed data
to be a type which took 19 parameters for a call to self.data.pop()
you wouldn't have to change class a
at all. You'd still have to change any code that called a.pop()
to pass the required 19 parameters though.
def func(*args):
pass
When you define a function this way, *args
will be array of arguments passed to the function. This allows your function to work without knowing ahead of time how many arguments are going to be passed to it.
You do this with keyword arguments too, using **kwargs
:
def func2(**kwargs):
pass
See: Arbitrary argument lists
In your case, you've defined a class which is acting like a dictionary. The dict.pop
method is defined as pop(key[, default])
.
Your method doesn't use the default
parameter. But, by defining your method with *args
and passing *args
to dict.pop()
, you are allowing the caller to use the default
parameter.
In other words, you should be able to use your class's pop
method like dict.pop
:
my_a = a()
value1 = my_a.pop('key1') # throw an exception if key1 isn't in the dict
value2 = my_a.pop('key2', None) # return None if key2 isn't in the dict