Function Definition with Default Parameters

by Christoph Schiessl on Python

A couple of weeks ago or so, I introduced you to Function Definitions with Simple Parameters. Today, we will build on that and explore functions with default parameters. We will again use the official grammar, taken from the official Language Reference, as a guide:

funcdef                   ::=  [decorators] "def" funcname [type_params] "(" [parameter_list] ")"
                               ["->" expression] ":" suite
decorators                ::=  decorator+
decorator                 ::=  "@" assignment_expression NEWLINE
parameter_list            ::=  defparameter ("," defparameter)* "," "/" ["," [parameter_list_no_posonly]]
                                 | parameter_list_no_posonly
parameter_list_no_posonly ::=  defparameter ("," defparameter)* ["," [parameter_list_starargs]]
                               | parameter_list_starargs
parameter_list_starargs   ::=  "*" [parameter] ("," defparameter)* ["," ["**" parameter [","]]]
                               | "**" parameter [","]
parameter                 ::=  identifier [":" expression]
defparameter              ::=  parameter ["=" expression]
funcname                  ::=  identifier

If you look at the definition of defparamter, you can see how default parameters work. You define the parameter as usual but append = expression to each parameter for which you want to establish a default value. For instance, the following function has two parameters, a and b, both of which have a default value:

def foo(a=2, b=3,):
    pass

Needless to say, parameters with default values don't have to be provided when the function is called, but you can provide them to overwrite the default. Observe:

Python 3.12.1 (main, Jan  1 2024, 16:22:47) [GCC 13.2.1 20230801] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> def exp(a=2, b=3):
...     return a ** b # a to the power of b
...
>>> exp()         # use only default values
8
>>> exp(a=3)      # overwrite only `a` with keyword param
27
>>> exp(3)        # overwrite only `a` with positional param
27
>>> exp(b=4)      # overwrite only `b` with keyword param
16
>>> exp(a=3, b=4) # overwrite both with keyword params
81
>>> exp(3, 4)     # overwrite both with positional params
81

Restrictions

Even though the grammar does not define it, there are some parameters for which default values are not allowed. The following restriction applies only to parameters the caller can provide as positional parameters ... Namely, parameters without default values must be listed before parameters with default values. If you violate this rule, you immediately get a SyntaxError:

Python 3.12.1 (main, Jan  1 2024, 16:22:47) [GCC 13.2.1 20230801] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> def foo(a=1, b):
  File "<stdin>", line 1
    def foo(a=1, b):
                 ^
SyntaxError: parameter without a default follows parameter with a default

Evaluation of Default Values

It is essential to understand that expressions defining the default values are evaluated only once when the function is defined — they are not evaluated when the function is called!

Python 3.12.1 (main, Jan  1 2024, 16:22:47) [GCC 13.2.1 20230801] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> default_value = 123
>>> def foo(a = default_value, b = default_value * 2):
...     return (a, b)
...
>>> foo()
(123, 246)
>>> foo(234)
(234, 246)
>>> default_value = 345 # does not affect foo's default values!
>>> foo()
(123, 246)
>>> foo(234)
(234, 246)

You have to be careful, though if the default value is a mutable object:

Python 3.12.1 (main, Jan  1 2024, 16:22:47) [GCC 13.2.1 20230801] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> default_value = [123]
>>> def foo(a = default_value): # `a` defaults to a reference to `default_value`
...     return a
...
>>> foo()
[123]
>>> foo([234])
[234]
>>> default_value.append(456) # modifies the list object
>>> foo()
[123, 456]
>>> foo([234])
[234]
>>> default_value = [] # now it's a new list object => doesn't affect any default values
>>> foo()
[123, 456]

The official Language Reference explains it as follows:

Default parameter values are evaluated from left to right when the function definition is executed.

That's everything for today. Thank you for reading, and see you soon!

Web App Reverse Checklist

Ready to Build Your Next Web App?

Get my Web App Reverse Checklist first ...


Software Engineering is often driven by fashion, but swimming with the current is rarely the best choice. In addition to knowing what to do, it's equally important to know what not to do. And this is precisely what my free Web App Reverse Checklist will help you with.

Subscribe below to get your free copy of my Reverse Checklist delivered to your inbox. Afterward, you can expect one weekly email on building resilient Web Applications using Python, JavaScript, and PostgreSQL.

By the way, it goes without saying that I'm not sharing your email address with anyone, and you're free to unsubscribe at any time. No spam. No commitments. No questions asked.

Continue Reading?

Here are a few more Articles for you ...


Function Definition with Position-Only Parameters

Learn about positional parameters in Python and a special syntax that allows functions to declare certain parameters as position-only.

By Christoph Schiessl on Python

Function Definition with Catch-All Parameters

Learn how to use catch-all parameters in Python functions with this guide. Capture excess positional and keyword arguments to make your functions more flexible.

By Christoph Schiessl on Python

The Built-In sorted() Function

Python's sorted() function makes sorting easy and performant, guaranteeing stability and allowing descending order and custom mapping.

By Christoph Schiessl on Python

Christoph Schiessl

Hi, I'm Christoph Schiessl.

I help you build robust and fast Web Applications.


I'm available for hire as a freelance web developer, so you can take advantage of my more than a decade of experience working on many projects across several industries. Most of my clients are building web-based SaaS applications in a B2B context and depend on my expertise in various capacities.

More often than not, my involvement includes hands-on development work using technologies like Python, JavaScript, and PostgreSQL. Furthermore, if you already have an established team, I can support you as a technical product manager with a passion for simplifying complex processes. Lastly, I'm an avid writer and educator who takes pride in breaking technical concepts down into the simplest possible terms.