In Python, there are two types of arguments : Positional arguments and keyword arguments.
A positional argument is a normal argument in Python. You pass in some data as input, and that becomes your positional argument.
def foo(posArg): print(posArg)
There’s nothing unique or inherently special about positional arguments, but let’s say you have a function that evaluates your pet. Is your pet happy? Is your pet healthy? Is your pet playful?
def evaluatePet(isHappy, isHealthy, isPlayful): if(isHappy): print('Your pet is happy!') if(isHealthy): print('Your pet is healthy!') if(isPlayful): print('Your pet is playful!')
That’s fine and dandy, but what does it look like when we call the function?
evaluatePet(True, True, False)
We get the output :
Your pet is happy! Your pet is healthy!
The result is correct, but the function call is absolutely unreadable.
A reader who has never read the documentation for evaluatePet will have a difficult time understanding what it does. From a quick glance, it takes three booleans. But what do those booleans describe? Whether it’s alive? Whether it’s a ghost? Whether it’s a flying ten thousand feet tall purple dinosaur?
The solution to this issue of readability is to avoid using a positional argument, and instead use a keyword argument.
A keyword argument is an argument that follows a positional argument, and allows the user to pass in arguments by explicitly stating the argument’s name, and then assigning a value to it.
In other words, you can call evaluatePet(True, True, False) in any of the following ways, without changing anything in the evalulatePet function.
#Explicitly calling the names and #assigning all three of the arguments evaluatePet(isHappy = True, isHealthy = True, isPlayful = False) #Switching the order of the arguments. #Since the arguments are named, #the order can be anything you like. evaluatePet(isHealthy = True, isPlayful = False, isHappy = True) #You can use positional arguments AND keyword arguments #at the same time, as long as the keyword arguments #are AFTER the positional arguments. evaluatePet(True, isHealthy = True, isPlayful = False) #Keyword arguments can ALWAYS #be switched around in any order evaluatePet(True, isPlayful = False, isHealthy = True)
However, there are some things that you can’t do.
#Putting keyword argument before #positional argument is illegal #Will error, #"Positional argument follows keyword argument." evaluatePet(isPlayful = False, isHealthy = True, True,) #Also will error for the same reason. evaluatePet(isPlayful = False, True, isHealthy = True)
You can see that with keyword arguments, the arguments are explicitly assigned. There is no confusion. The reader can simply look at a line like :
evaluatePet(isHealthy = True, isPlayful = False, isHappy = True)
And they will automtaically know, “Oh. This function takes in three booleans which are, isHealthy, isPlayful, and isHappy.”
It would be a huge understatement to say that this is the only thing that keyword arguments can do.
You can also load in defaults.
def evaluatePet(isHappy = False, isHealthy = False, isPlayful = False): if(isHappy): print('Your pet is happy!') if(isHealthy): print('Your pet is healthy!') if(isPlayful): print('Your pet is playful!')
Now, all three arguments become optional, and become automatically assigned to False if that specific argument has not been assigned.
#All three are automatically set to False, #so nothing is printed. evalulatePet() #You can set just one to True, #and the rest will automatically be False. evaluatePet(isHappy = True) evaluatePet(True)
Convenient, isn’t it? You can give your function a ton of default values, and then allow the user to change any defaults they don’t like, without requiring them to rewrite all the default values.
Underneath all of this magic, Python created a dictionary with a key value pair, where the keys are the argument names, and the values are the values you assign to those argument names.
If you want to prove this fact, you can use a true keyword argument by putting a double asterisk before an argument.
def foo(**kwargs): print(str(kwargs)) foo(bar = "henry", baz = "dang", foobar = "prg")
Output :
{'bar': 'henry', 'foobar': 'prg', 'baz' : 'dang'
In other words, Python has been converting evaluatePet’s arguments into a dictionary.
Naturally, Python wants the group of keyword arguments together, because it is cheaper to lump all the arguments together if they are all within one specific range (and not broken up between multiple ranges). In addition to this, Python can’t accept a positional argument after a keyword argument because it is impossible to determine which argument you are referring to. Are you referring to the first argument? Or the argument after the keyword argument?
These two reasons combined are why you can’t put in positional arguments, and then keyword arguments, and then another positional argument.
You might argue that Python should be able to do this :
evaluatePet(isHappy = False, isHealthy = False, False)
Since there are only three arguments, and two of them are keyword arguments, the third argument must be “isPlayful”.
However, Python’s philosophy is
“Special cases aren’t special enough to break the rules.”
So instead of Python automatically iterating over your arguments to figure out which argument hasn’t been assigned yet (you shouldn’t do this anyway since iterating over a list is expensive), Python simply says, “This is a special case. Follow the rules and deal with it.”
So while Python could potentially have allowed this special case to work, their mantra of sticking strongly to rules prevents you from doing so.
In a nutshell, keyword arguments are simply augments to Python’s core philosophy that “readability counts”. Without keyword arguments, readers must examine the documentation to understand what the arguments mean, especially if there are many arguments. The use of defaults also makes functions shorter if the user is unlikely to modify the defaults.
Shorter argument lists? Argument defaults? Understandable parameters? That’s elegant.