16 Python Function Things I Regret Not Knowing Earlier
1) Type hinting in functions
I started off learning Python without using type hints at all. And so for the first few years of writing Python, I never wrote a single type hint.
As a simple example, let’s say we want to write a function that finds the average of 2 integer numbers. How I used to write my function:
How I write my functions now at work (adding type hints and docstring):
a: int means that a should ideally be an integer
b: int means that b should ideally be an integer
-> float means that the function should ideally return a float value
However, do note that type hints hint, but do not enforce. If we pass in strings or other data types into a and b, Python is actually ok with that (until it attempts to divide a string by 2 which causes error)
The purpose of type hinting is more of 1) making code readable for humans and 2) enabling your IDE eg. PyCharm or VSCode to do checks for you.
As much as possible, try to add type hints into your functions so that other programmers (or even future you) will have an easier time understanding the function.
2) Default arguments
^ in the above function, greeting=‘hi’ is a default argument.
if we decide to not pass anything to greeting, it is automatically assigned ‘hi’
if we decide to pass something to greeting, it takes that value
In greet(‘tom’) , we don’t pass anything into greeting. Which means it defaults to ‘hi’
In greet(‘tom’, greeting=‘hello’) , we pass ‘hello’ into greeting. Which means that we override the default argument, and assign greeting = ‘hello’
This is useful if we have a large number of parameters in a function, and do not wish to have to pass in every single parameter each time we call the function.
3) Arguments VS Parameters
In my first few years of learning Python, I thought they meant the same thing.
But not really. There’s a slight difference.
Let’s say we have a simple function that takes in (a, b) and returns their average.
A parameter is a variable written inside the brackets when we define our function. Here, a and b are parameters.
An argument is the value that we actually pass into our function when calling it. Here, when we call the avg(a, b) function, 3 and 5 are arguments.
4) Positional VS Keyword Arguments
A simple trivial function just to show an example.
Let’s call this function by passing in some positional arguments.
^ here, 4 and 7 are positional arguments. Positional arguments need to be in order — 4 is passed into a, while 7 is passed into b.
Next, let’s call our function by passing in some keyword arguments.
^ here, b=5 and a=8 are keyword arguments. Keyword arguments do not need to be in order, but we must pass them in using a key=value format.
5) Arbitrary Positional Arguments (*args)
Arbitrary positional arguments in a function, also known as *args, allow the function to accept any number of positional arguments.
^ here, the test function takes in *args — which allows test to take in any number of positional arguments, which will all be caught in a tuple named args.
We can combine this with normal parameters too (the *args must be behind)
Additional note — we don’t have the name it *args. We can name it whatever as long as we add the * in front of it.
6) Arbitrary keyword arguments (**kwargs)
Arbitrary keyword arguments, also known as **kwargs, allow our functions to take in any number of keyword arguments.
^ here, the test function takes in **kwargs — which allows test to take in any number of keyword arguments, will be caught in a dictionary named kwargs
We can also combine this with normal parameters (**kwargs must be behind too)
Additional note — we don’t have to name it kwargs if we don’t want to. We can name it whatever we want as long as it has ** in front of it.
Quick Pause
I recently wrote a book — 101 Things I Never Knew About Python
Check it out here if you wish to support me as a writer!
Link: https://payhip.com/b/vywcf
7) Using * and ** to pass list/dict into function
Here’s a trivial function that simply prints out its arguments.
Instead of calling this function the normal way ie hi(1, 2) , we could:
1) use * to pass a list containing positional arguments
^ here, the * in front of nums unpacks its contents into the function call as positional arguments. This is the same as hi(100, 200)
2) use ** to pass a dict containing keyword arguments
^ here, the ** in front of d unpacks its key-value pairs into the function call as keyword arguments. This is the same as hi(a=100, b=100)
8) Function vs method
When I was still starting out in Python, I used these 2 terms interchangeably. But there are slight differences in the terms.
A method is simply a function that belongs inside a class.
9) Magic methods in classes
In classes, magic methods are special methods that define special behaviour.
Magic methods usually start and end with double underscores eg. __init__, __str__ etc. Hence, magic methods are also known as dunder methods.
Each magic method has a its own unique purpose and special behaviour. For instance, the __init__ method defines how attributes of an object are assigned to it.
The __str__ method defines what string is returned when we do str(obj) to our custom object obj:
There are many more magic methods that each have their unique use cases and behaviour, but I won’t go through all of them here.
Some useful ones I use — __add__, __eq__, __lt__, __gt__, __invert__ etc
10) Higher-order functions
A higher-order function is a function that either:
takes in another function as an argument
returns another function
both 1 and 2
Example of 1) function that takes in another function as an argument
^ here, the higher-order function apply takes in another function square as an argument, and applies square to every single element in the list ls.
Example of 2) function that returns another function
^ here, the higher-order function add_n returns another function. add_n(100) returns a function that takes in x, and adds 100 to x.
11) Lambda functions
We usually define functions using the def keyword. But did you know that we can also define functions using the lambda keyword?
Here’s a trivial, simple function that simply adds 2 numbers together.
Here’s how we can define the same exact function using the lambda keyword.
function parameters go before the colon
the returned value goes after the colon
Lambda functions are also called anonymous functions. This means that it is optional to give a lambda function a name.
In the above example, we choose to give it a name add. But we can decide not to give it a name if we really don’t want to.
Lambda functions are useful when pairing them with higher-order functions.
^ here, we pair a lambda function with the higher-order function apply so that we don’t have to define another function using the def keyword.
Keep reading with a 7-day free trial
Subscribe to The Python Rabbithole to keep reading this post and get 7 days of free access to the full post archives.