[Ch 4] Everything About Python Functions from the Official Documentation

July 10, 2025

[Ch 4] Everything About Python Functions from the Official Documentation

Use Original Cover Image
Type
Post
Children
Language
en
Tags
Python
function
Argument
Symbol Table
Method
Keyword Argument
Arbitrary Argument
Positional Argument
Lambda Expression
Docstring
Authors
Published
July 10, 2025

Overview

This article provides a more understandable summary of all the content in 4. More Control Flow Tools ~ 4.10. Intermezzo: Coding Style from the official Python v3.13 Tutorial.

1. Defining Functions

def fib(n): # write Fibonacci series less than n """Print a Fibonacci series less than n.""" a, b = 0, 1 while a < n: print(a, end=' ') a, b = b, a+b print()
  1. def: A keyword that indicates the definition of a function.
  1. fib: Sets the name of the function.
  1. (): Contains the list of the function's parameters.
  1. :: The body of the function follows this colon. Indentation is required when writing the function.

2. Symbol Table

A symbol table is a dictionary that stores the name and data address for an object.
  1. When a function is executed, a new symbol table for that function is created.
  1. When referencing a variable, it is searched in the order of local symbol tableenclosing function's symbol tableglobal symbol tabletable of built-in names.
    1. Therefore, the values of global variables or variables of an enclosing function may not be assigned.
  1. Each time another function is called, or the function itself is called recursively, a new local symbol table is created for that call.
  1. Since functions are also objects in the symbol table, different names can point to the same function object.
fib
page icon
<function fib at 10042ed0>
f = fib f(100)
page icon
0 1 1 2 3 5 8 13 21 34 55 89

3. Return

The return statement allows a function to output a value.

3.1. Functions without a return statement

The fib function shown earlier does not have a return statement. However, in Python, even without a return statement, a function always returns a value, which is None. None is not displayed by the interpreter, so if you want to force the display of the returned None, you can use print.
print(fib(0))
page icon
None

3.2. Method

def fib2(n): # return Fibonacci series up to n """Return a list containing the Fibonacci series up to n.""" result = [] a, b = 0, 1 while a < n: result.append(a) # see below a, b = b, a+b return result f100 = fib2(100) # call it f100 # write the result
page icon
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
A method is a function whose name is obj.methodname. Here, obj is some object, which can be an expression like a str or int. In the example above, the statement result.append(a) calls a method of the list object result.
  • Different object types have different methods.
    • For example, list objects have append, but other objects may not.
  • Different object types can have methods with the same name without causing ambiguity.
  • You can define your own object types and methods using class.
    • For example, if you create an object of type temp and add a method named append, it will not conflict with the append method of lists.

4. Arguments

4.1. Default Argument Values

When defining a function, you can set default values for arguments. A default value is set like retries=4 in the def statement.
def ask_ok(prompt, retries=4, reminder='Please try again!'): while True: reply = input(prompt) if reply in {'y', 'ye', 'yes'}: return True if reply in {'n', 'no', 'nop', 'nope'}: return False retries = retries - 1 if retries < 0: raise ValueError('invalid user response') print(reminder)
If you have set a default value, you can call the function without specifying the value for that argument. For example, you can specify only one or two arguments instead of all three.
  • Pass only the required argument: ask_ok('Do you really want to quit?')
  • Pass one optional argument: ask_ok('OK to overwrite the file?', 2)
  • Pass all arguments: ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')

4.1.1. Important Note

The default value of an argument is evaluated only once, when the function is defined. For example, in the code below, i=5 when the function is defined, so arg is fixed to 5. Therefore, even after i becomes 6, calling f will print 5.
i = 5 def f(arg=i): print(arg) i = 6 f()
If the default value is a mutable object like a list, dictionary, or instance of a class, all calls to the function share the same object. For example, if you set the default value to L=[], each call will add a value to the same list, resulting in the output shown on the right.
def f(a, L=[]): L.append(a) return L print(f(1)) print(f(2)) print(f(3))
page icon
[1] [1, 2] [1, 2, 3]
If you do not want to share the default value, you can modify the code as follows.
def f(a, L=None): if L is None: L = [] L.append(a) return L

4.2. Keyword Arguments

You can pass arguments to a function in the form of kwarg=value.
def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'): print("-- This parrot wouldn't", action, end=' ') print("if you put", voltage, "volts through it.") print("-- Lovely plumage, the", type) print("-- It's", state, "!")
For example, you can call the above function as follows:
parrot(1000) # 1 positional argument parrot(voltage=1000) # 1 keyword argument parrot(voltage=1000000, action='VOOOOOM') # 2 keyword arguments parrot(action='VOOOOOM', voltage=1000000) # 2 keyword arguments parrot('a million', 'bereft of life', 'jump') # 3 positional arguments parrot('a thousand', state='pushing up the daisies') # 1 positional, 1 keyword
The following features apply:
  • All keyword arguments must match one of the function's arguments. (In the example below, you cannot pass an actor argument that is not in parrot.)
  • The order of keyword arguments does not matter.
  • Arguments cannot be duplicated.
  • A non-keyword argument cannot come after a keyword argument.
parrot() # required argument missing parrot(voltage=5.0, 'dead') # non-keyword argument after a keyword argument parrot(110, voltage=220) # duplicate value for the same argument parrot(actor='John Cleese') # unknown keyword argument

4.3. Arbitrary Arguments: *args, **kwargs

4.3.1. Arbitrary Positional Arguments: *args

You can use the *name form to specify that the function can be called with an arbitrary number of arguments. The following features apply:
  • The arguments are passed as a tuple.
  • Parameters after *arg are keyword-only arguments.
def concat(*args, sep="/"): return sep.join(args) concat("earth", "mars", "venus", sep=".")
page icon
'earth.mars.venus'

4.3.2. Arbitrary Keyword Arguments: **kwargs

While *name receives a tuple, **name receives a dictionary. Similarly, you can pass an arbitrary number of arguments as keywords. **name must come after *name. The order of arguments in the dictionary is the same as the order in which they were provided in the call.
def cheeseshop(kind, *arguments, **keywords): print("-- Do you have any", kind, "?") print("-- I'm sorry, we're all out of", kind) for arg in arguments: print(arg) print("-" * 40) for kw in keywords: print(kw, ":", keywords[kw]) cheeseshop("Limburger", "It's very runny, sir.", "It's really very, VERY runny, sir.", shopkeeper="Michael Palin", client="John Cleese", sketch="Cheese Shop Sketch")
-- Do you have any Limburger ? -- I'm sorry, we're all out of Limburger It's very runny, sir. It's really very, VERY runny, sir. ---------------------------------------- shopkeeper : Michael Palin client : John Cleese sketch : Cheese Shop Sketch

4.4. Special parameters

For readability and performance, you can optionally use / and * to restrict how arguments can be passed to a function.
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2): ----------- ---------- ---------- | | | | Positional or keyword | | - Keyword only -- Positional only

4.4.1. Positional-or-Keyword Arguments

If / and * are not present in the function definition, arguments can be passed by position or by keyword. This is the same as what we have seen so far.

4.4.2. Positional-Only Parameters

Parameters placed before / can only be passed by position and cannot be passed by keyword.

4.4.3. Keyword-Only Arguments

Parameters placed after * can only be passed by keyword and cannot be passed by position.

4.4.4. Usage Examples

def standard_arg(arg): print(arg) def pos_only_arg(arg, /): print(arg) def kwd_only_arg(*, arg): print(arg) def combined_example(pos_only, /, standard, *, kwd_only): print(pos_only, standard, kwd_only)
Without / and *, there are no restrictions.
standard_arg(2)
page icon
2
standard_arg(arg=2)
page icon
2
Passing a keyword argument to a positional-only argument slot results in an error.
pos_only_arg(1)
page icon
1
pos_only_arg(arg=1)
page icon
Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: pos_only_arg() got some positional-only arguments passed as keyword arguments: 'arg'
Passing a positional argument to a keyword-only argument slot results in an error.
kwd_only_arg(3)
page icon
Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: kwd_only_arg() takes 0 positional arguments but 1 was given
kwd_only_arg(arg=3)
page icon
3

4.4.5. Conflict between Positional arguments and **kwds

As shown in the left example below, trying to pass a value in **kwds that already exists as a positional argument will cause an error. This is because the positional argument, being defined and passed first, is stored first.
This problem can be avoided by using / to make name a positional-only argument, as shown in the right example.
def foo(name, **kwds): return 'name' in kwds foo(1, **{'name': 2})
page icon
Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: foo() got multiple values for argument 'name'
def foo(name, /, **kwds): return 'name' in kwds foo(1, **{'name': 2})
page icon
True

4.4.6. Summary

def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
  1. Situations where positional-only is useful:
    1. The parameter name has no intrinsic meaning.
    2. You don't want to expose the parameter name to the user.
    3. You want to enforce the order of arguments more clearly.
    4. You are using both positional parameters and arbitrary keywords.
    5. The function is for an API. It can prevent the API from breaking if the parameter name changes later.
  1. Situations where keyword-only is useful:
    1. The parameter name has an intrinsic meaning.
    2. You don't want the user to pass arguments by position.
    3. You want to make the function definition clearer by using names.

4.5. Unpacking Arguments: *args, **kwargs

This can be confused with Arbitrary Arguments: *args, **kwargs because they use the same * and ** symbols. To be clear, the previous section was about using * when defining a function, while this section is about using * when calling a function.
If the arguments are already in a list, tuple, or dictionary, you can unpack them to call the function. Use * for lists or tuples, and ** for dictionaries. (If you use * with a dictionary, only the keys are passed, and they act as positional arguments, not keyword arguments.)
def f(arg1, arg2, arg3): print(arg1, arg2, arg3) args = (1, 2, 3) f(*args)
page icon
1 2 3
def f(arg1, arg2, arg3): print(arg1, arg2, arg3) args = {'arg1': 1, 'arg2': 2, 'arg3': 3} f(**args)
page icon
1 2 3

5. Lambda Expressions

You can create small, anonymous functions with the lambda keyword. The format is lambda {argument list}: {return value}. The following features apply:
  • Lambda functions can be completely replaced by regular def functions. Their only reason for existence is to be more concise.
  • The body is restricted to a single expression. If you need multiple lines, use a regular def function.
  • Like regular def functions, lambda functions can reference variables from the enclosing scope.
For example, let's look at a function that creates a function to add two values. The lambda function can reference n from the enclosing make_incrementor function. Lambda is useful when returning a function like this.
def make_incrementor(n): return lambda x: x + n f = make_incrementor(42) f(10)
page icon
52
Another example is passing a function as an argument. list.sort() requires a sorting key function, which can be passed as a lambda function.
pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')] pairs.sort(key=lambda pair: pair[1]) pairs
page icon
[(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]
Another common use case is shown below. When loading a table from a pandas dataframe, you can define converters for multiple columns or easily apply transformations to each row after the dataframe has been loaded.
converters = { 'distance': lambda x: float(x) / 1_000, 'time' : lambda x: float(x) / 3_600, } df = pd.read_csv(path, converters=converters)
df['lat_lng'] = df.apply(lambda row: (df['lat'], df['lng']), axis=1)
Note that in the code above, axis=1 applies the function to rows, and axis=0 applies it to columns.

6. Documentation Strings

6.1. Definition

When the first statement of a function body is a string literal, that string literal is called a documentation string or docstring. Docstrings are conventionally used by IDEs and other programs to read the description of the function.
A string literal is text enclosed in single quotes, double quotes, or triple quotes. Triple quotes are usually used because they can record line breaks.

6.2. Convention

  1. The first line is a short, concise summary of the function's purpose, starting with a capital letter. The type is not specified in the first line.
  1. If more explanation is needed, the second line is left blank to visually separate the summary from the detailed description.
  1. The following lines can contain various information such as the calling convention, the type of each argument, etc.
When writing a multi-line docstring, its indentation is determined by the indentation of the first non-blank line that comes after the first line. That is, if "Do nothing,..." is the first line and the next non-blank line is "No, ...", the indentation of this line is set as the indentation for the entire docstring.
def my_function(): """Do nothing, but document it. No, really, it doesn't do anything. """ pass print(my_function.__doc__)
page icon
Do nothing, but document it. No, really, it doesn't do anything.

6.3. Annotations

Annotations are optional metadata about types and do not change the function itself. They are used to specify the types of arguments and return values more concretely. When specified, they are stored in the function's __annotations__ attribute as a dictionary.
  1. A parameter annotation is an expression like str, int, or float following the parameter name and a colon. In the example below, = 'eggs' is a default argument value and is separate from the annotation.
  1. A return annotation is defined by writing -> and an expression between the parameter list and the colon of the def statement.
def f(ham: str, eggs: str = 'eggs') -> str: print("Annotations:", f.__annotations__) print("Arguments:", ham, eggs) return ham + ' and ' + eggs f('spam')
page icon
Annotations: {'ham': <class 'str'>, 'return': <class 'str'>, 'eggs': <class 'str'>} Arguments: spam eggs 'spam and eggs'

7. Coding Style

When writing long and complex code, writing it concisely and with a consistent format helps others and your future self understand the code better. **PEP 8** contains a style guide that every Python developer should read at some point. Some of the most important points are listed below.
  • Use 4-space indentation. Do not use tabs.
    • Fewer spaces allow for deeper nesting but are harder to read, and more spaces also make the code harder to read. Tab characters cause confusion.
      (Modern IDEs automatically convert tabs to 4-space indentation.)
  • Wrap lines so that they don't exceed 79 characters.
    • This makes the code more visible on side-by-side screens.
  • Use blank lines to separate functions, classes, and large blocks of code within functions.
  • If possible, write comments on their own lines, not next to the code.
  • Use docstrings.
  • Use a space after operators and commas.
    • Space on both sides of operators like +, -, *, /, =.
    • Space after a comma.
    • However, do not put a space immediately inside parentheses like (), {}, []. ✅(1, 2)( 1, 2 )
    • Example: a = f(1, 2) + g(3, 4)
  • Name classes and functions consistently.
    • It is conventional to use UpperCamelCase for classes.
    • It is conventional to use lowercase_with_underscores for functions and methods.
  • Always name the first method of a class self.
  • If the code is used in a multi-language environment, do not use complex encodings. Python's default encoding is UTF-8. You can even write well in any situation with just ASCII. It is best to write code using only ASCII characters. A developer from another language may need to read or maintain it.

Reference

[1] Python Software Foundation. "4.8. Special Parameters." The Python Tutorial, version 3.13, Python Software Foundation, 2024, docs.python.org/3.13/tutorial/controlflow.html#special-parameters. Accessed 10 July 2025.