Programming and IT

Python: functions

A function is a named piece of code that takes values and returns a result. In Python a definition takes one line, but arguments have subtleties: defaults are evaluated once, positional and keyword arguments mix by rules, and a function without return still returns something.

Updated
In this article

Definition and return#

A function starts with the word def, a name, parentheses with the parameter list and a colon. The body is indented by four spaces.

def greet(name):
    """Return a greeting for the given name."""
    return f"Hello, {name}!"

print(greet("Anna"))     # Hello, Anna!

The triple-quoted string right under def is the function's docstring; it is available through help(greet) and greet.__doc__. Writing one pays off even for yourself: a month later it is the only way to remember what the function promises.

If no return runs, the function returns None — nothing crashes, the result is simply empty:

def add(a, b):
    print(a + b)        # prints, but does not return

result = add(2, 3)      # 5
print(result)           # None

Mixing up print and return is beginner mistake number one. print shows a value to a person; return hands it to the code.

Arguments: positional, keyword, with defaults#

def power(base, exp=2):
    return base ** exp

print(power(3))              # 9
print(power(3, 3))           # 27
print(power(exp=3, base=2))  # 8

Positional arguments are matched by order, keyword arguments by name, and the latter can come in any order. Parameters with default values are declared only after the ordinary ones: def f(a=1, b) is a syntax error.

An asterisk in the parameter list makes everything after it keyword-only — that saves you from unreadable calls like save(data, True, False):

def save(data, *, overwrite=False):
    return f"{data} / overwrite: {overwrite}"

print(save("report", overwrite=True))   # report / overwrite: True

A variable number of arguments#

*args collects extra positional arguments into a tuple, and **kwargs collects keyword arguments into a dictionary.

def total(*args, **kwargs):
    print(args, kwargs)
    return sum(args)

print(total(1, 2, 3, discount=5))
  # (1, 2, 3) {'discount': 5}
  # 6

The same asterisk works in a call too — it unpacks a ready sequence or dictionary into arguments:

nums = [2, 3]
print(power(*nums))                      # 8
print(power(**{"base": 5, "exp": 3}))    # 125

The mutable default value#

A default expression is evaluated once — when the function is defined, not on every call. So a list or dictionary used as a default lives on between calls:

def collect(item, box=[]):
    box.append(item)
    return box

print(collect("a"))   # ['a']
print(collect("b"))   # ['a', 'b']  — not what you expected

The fix is always the same: use None as the default and create the real value inside.

def collect(item, box=None):
    if box is None:
        box = []
    box.append(item)
    return box

print(collect("a"))   # ['a']
print(collect("b"))   # ['b']

Scope#

A name assigned inside a function is treated as local for the whole function — even if the assignment is on the last line.

counter = 0

def bump():
    global counter
    counter += 1

bump()
print(counter)      # 1

Without the global counter line, the same code would fail with UnboundLocalError. But global is a bad habit: more often you should take the value as an argument and return the new one. Reading global values inside a function works without any declaration.

A little practice: write a function stats(*numbers) that returns a tuple of the minimum, maximum and mean, and check that it works both as stats(1, 2, 3) and as stats(*[1, 2, 3]). Next you will want Python decorators — they are add-ons built on top of functions — and Python exceptions, to report bad arguments cleanly.

Step-by-step plan

  1. A simple function with returnWrite a function that takes two numbers and returns their sum; print the result.
  2. Defaults and keyword argumentsAdd a parameter with a default value and call the function three different ways.
  3. Collect *argsA function with a variable number of arguments that computes the mean; call it by unpacking a list.
  4. Reproduce the trapRun the box=[] example twice in a row and see the list accumulate values.
  5. Rewrite it safelyChange the default to None and check that calls no longer affect each other.

Start learning this in your own space

The plan goes into your repository: tick off stages, keep notes — the change history shows how far you have come.

Start the plan

Check yourself

1.What does this print: def f(a, b=2): return a * b; print(f(3))?

2.What does this print: def f(x): print(x); r = f(1); print(r)?

3.What does the second call print: def c(i, box=[]): box.append(i); return box; c('a'); print(c('b'))?

4.What does this return: def t(*args): return len(args); t(1, 2, 3, 4)?

Sources

Was this helpful?

More articles

Programming and IT Python: decorators A decorator is a function that takes another function and returns a new one with extra behaviour. The `@` sign above a definition is just a shorthand for an assignment. Keep that in mind and the whole topic takes one evening. Programming and IT How to learn Python from scratch Python is a good first programming language: code reads almost like text, and the standard library covers most everyday tasks. This plan takes you from installing the interpreter to your own scripts covered by tests in about four months, at roughly an hour a day. Programming and IT Python: lists A list is a mutable, ordered collection of values of any type. It is also the main source of surprises for beginners: assignment does not copy a list, sort returns nothing, and removing items inside a loop skips half of them. Let us go through it in order. Programming and IT Python: classes A class describes what data an object is made of and what it can do. The `__init__` constructor fills in a new object, and `self` is a reference to the object itself. Below: a minimal working class, the difference between class and instance attributes, and ways to make the code shorter. Programming and IT Python: strings A string in Python is an immutable sequence of characters. Almost all of its quirks follow from that: methods do not change a string but return a new one, and fast text building goes through join, not through adding strings in a loop. Below is the working minimum with examples and output. Programming and IT Python: reading a file Working with a file takes three steps: open it, read or write, close it. You are better off not closing it by hand — that is what the `with` statement is for. And the parameter people forget most is the encoding: without it, the same code reads a file differently on different machines.

More solutions