• Home
  • LLMs
  • Python
  • Docker
  • Kubernetes
  • Java
  • Maven
  • All
  • About
Python | Defining and Using Functions
Basic function definition:
Use def keyword to define a function.
Function names should be lowercase (get_message).
The code inside the function must be indented.
The colon character (:) is required after the function signature.

Function parameters and arguments:
Parameters are variables in the function definition.
Arguments are actual values passed when calling the function.

def hello():
  """A simple function that print a hello message."""
  print('Hello!')

# calling hello function
hello()
Output:
Hello!
Return values:
  • Single return value.
    def add(i, j):
      return i+j
    
    print(add(3, 5)) # Output: 8
  • Multiple return values.
    def div(i, j):
      return i//j, i%j
    
    quotient, remainder = div(7, 2)
    print(f'quotient:{quotient}, remainder:{remainder}') # Output: quotient:3, remainder:1
Positional arguments:
def info(firstname, lastname):
  print(f'firstname: {firstname} | lastname: {lastname}')

# call info function with argument 'A' for the parameter firstname and argument 'B' for the parameter lastname
info('fn_A', 'ln_B')
Output:
firstname: fn_A | lastname: ln_B
Keywords arguments:
def info(firstname, lastname):
  print(f'firstname: {firstname} | lastname: {lastname}')

# explicitly naming the parameters of the function
info(firstname='fn_C', lastname='ln_D')

# the order of the arguments doesn't matter when explicitly naming the parameters
info(lastname='ln_F', firstname='fn_E')
Output:
firstname: fn_C | lastname: ln_D
firstname: fn_E | lastname: ln_F
Mixing positional and keywords arguments:
Positional arguments must be listed first.
def info(firstname, lastname):
  print(f'firstname: {firstname} | lastname: {lastname}')

# mixed positional and keywords arguments
info('fn_G', lastname='ln_H')
Output:
firstname: fn_G | lastname: ln_H
Arbitrary positional arguments (*args):
Passing an arbitrary number of arguments.
# python creates a tuple named values that will contain all the arguments
def print_values(*values):
  print(values)

print_values() # Output: ()
print_values(1) # Output: (1,)
print_values(1, 2) # Output: (1, 2)

# unpacking lists
list1 = [1, 2, 3]
print_values(*list1) # Output: (1, 2, 3)

# unpacking tuples
tuple1 = (1, 2, 3)
print_values(*tuple1) # Output: (1, 2, 3)
Mixing regular arguments and *args:
def print_values(key, *values):
  print(f'{key}={values}')

# the key argument is required
#print_values() # Raises TypeError: print_values() missing 1 required positional argument: 'key'

print_values('none') # Output: none=()
print_values('one', 'a') # Output: one=('a',)
print_values('two', 'a', 'b') # Output: two=('a', 'b')
Arbitrary keyword arguments (**kwargs)
Passing an arbitrary number of key-value pair as arguments.
# python creates a dictionary named values that will contain all the arguments
def print_values(**values):
  print(values)

print_values() # Output: {}
print_values(a=1) # Output: {'a': 1}
print_values(a=1, b=2) # Output: {'a': 1, 'b': 2}
print_values(a=1, b=2, c=3) # Output: {'a': 1, 'b': 2, 'c': 3}
Mixing regular arguments and **kwargs:
Passing regular and arbitrary number of key-value pair as arguments.
def print_values(key, **values):
  print(values[key])

# the key argument is required
#print_values('a') # Raises KeyError: 'a'

print_values('a', a=1) # Output: 1
print_values('b', a=1, b=2) # Output: 2
print_values('c', a=1, b=2, c=3) # Output: 3
Combining all parameter types:
def print_values(msg, *args, **kwargs):
  print(f'msg:{msg}, args:{args}, kwargs:{kwargs}')

print_values('hello', 1, a=1) # Output: msg:hello, args:(1,), kwargs:{'a': 1}
Default parameters:
def info(firstname, lastname='unknown'):
  print(f'firstname: {firstname} | lastname: {lastname}')

# using default with positional argument for the first parameter
info('fn_A') # the second argument is missing, defaults to 'unknown'

# using default with keyword argument for the first parameter
info(firstname='fn_B') # the second argument is missing, defaults to 'unknown'

# overriding the default value
info(firstname='fn_C', lastname='ln_D')
Output:
firstname: fn_A | lastname: unknown
firstname: fn_B | lastname: unknown
firstname: fn_C | lastname: ln_D
Mutable defaults:
You need to avoid mutable defaults like lists or dictionaries.
# using mutable default
def add_message(msg, messages=[]):
  messages.append(msg)
  return messages

print(add_message("hello")) # Output: ['hello']
print(add_message("python")) # Output: ['hello', 'python']
To fix the issue, use None:
def add_message(msg, messages=None):
  if messages is None:
    messages = []
  messages.append(msg)
  return messages

print(add_message("hello")) # Output: ['hello']
print(add_message("python")) # Output: ['python']
Passing lists as arguments:
def pop(x):
  return x.pop()

y = [1, 2, 3]
print(pop(y)) # Output: 3
print(y) # Output: [1, 2]
Passing a copy of a list as an argument:
def pop(x):
  return x.pop()

y = [1, 2, 3]
print(pop(y[:])) # Output: 3 (passing a list slice as argument)
print(y) # Output: [1, 2, 3]
Working with lists copies:
def append(i, list1, list2, list3):
  # modify the original list
  list1.append(i)

  # create new copy
  list_copy = list2.copy()
  list_copy.append(i)

  # create new copy
  list_another_copy = list3[:]
  list_another_copy.append(i)

  return list1, list_copy, list_another_copy

y1 = [1]
y2 = [2]
y3 = [3]
z1, z2, z3 = append(4, y1, y2, y3)
print(f'y1:{y1}, y2:{y2}, y3:{y3}') # Output: y1:[1, 4], y2:[2], y3:[3]
print(f'z1:{z1}, z2:{z2}, z3:{z3}') # Output: z1:[1, 4], z2:[2, 4], z3:[3, 4]
Local and global variables
global_var = "hello"
def use_global_local():
  local_var = "python!"
  print(f'{global_var} {local_var}') # Output: hello python!

def update_global():
  global global_var
  global_var = "hello python!" # the global variable will be changed
  print(global_var) # Output: hello python!

def shadow_global():
  # shadowing the global variable
  global_var = "hello!" # the global variable won't be changed
  print(global_var) # Output: hello!

use_global_local()
print(global_var) # Output: hello

update_global()
print(global_var) # Output: hello python!

shadow_global()
print(global_var) # Output: hello python!
Lambda functions
  • Basic lambda:
    square = lambda x: x ** 2
    print(square(3)) # Output: 9
  • Lambda with multiple arguments:
    add = lambda x, y: x + y
    print(add(3, 6)) # Output: 9
  • Lambda with map function:
    print(list(map(lambda x: x ** 2, [1, 2, 3]))) # Output: [1, 4, 9]
  • Lambda with filter function:
    print(list(filter(lambda x: x % 2 == 0, [1, 2, 3]))) # Output: [2]
  • Sorting with lambda:
    x = ['abcd', 'abc', 'ab', 'a']
    x.sort(key=lambda i: len(i))
    print(x) # Output: ['a', 'ab', 'abc', 'abcd']
Using functions as arguments
def apply(operation, numbers):
  return [operation(i) for i in numbers]

def square(x):
  return x ** 2

print(apply(square, [1, 2, 3])) # Output: [1, 4, 9]
print(apply(lambda x: x ** 2, [1, 2, 3])) # Output: [1, 4, 9]
Return functions
def apply_lambda(multiplier):
  return lambda x: x * multiplier

def apply_function(multiplier):
  def apply(x):
    return x * multiplier
  return apply

print(apply_lambda(3)(2)) # Output: 6
print(apply_function(3)(2)) # Output: 6
Modules and imports
  • Creating a module:
    Create a file function_module_1.py that contains the definition of two functions:
    $ vi function_module_1.py
    def add(i, j):
      return i+j
    
    def multiply(i, j):
      return i*j
  • Import entire module:
    Create a file function_import_1.py that imports the module function_module_1 (function_module_1.py):
    $ vi function_import_1.py
    # all functions defined in the module function_module_1 will be accessible using the prefix function_module_1
    import function_module_1
    
    # calling the functions in the module function_module_1 using the name of the module name as a prefix
    print(function_module_1.add(2, 3)) # Output: 5
    print(function_module_1.multiply(2, 3)) # Output: 6
  • Import specific functions:
    Create a file function_import_2.py that imports specific functions defined in the module function_module_1 (function_module_1.py):
    $ vi function_import_2.py
    # importing the functions add and multiply from the module function_module_1
    from function_module_1 import add, multiply
    
    # calling directly the functions in the module function_module_1 without specifying the module name
    print(add(2, 3)) # Output: 5
    print(multiply(2, 3)) # Output: 6
  • Import all:
    Create a file function_import_3.py that imports all functions defined in the module function_module_1 (function_module_1.py):
    $ vi function_import_3.py
    # importing all functions from the module function_module_1
    from function_module_1 import *
    
    # calling directly the functions in the module function_module_1 without specifying the module name
    print(add(2, 3)) # Output: 5
    print(multiply(2, 3)) # Output: 6
  • Import with alias (as):
    Create a file function_import_4.py that imports the module function_module_1 (function_module_1.py) and give it an alias f1:
    $ vi function_import_4.py
    # defining the alias f1 for the module function_module_1
    import function_module_1 as f1
    
    # calling the functions in the module function_module_1 using the alias of the module as a prefix
    print(f1.add(2, 3)) # Output: 5
    print(f1.multiply(2, 3)) # Output: 6
  • Import specific functions with aliases (as):
    Create a file function_import_5.py that imports specific functions defined in the module function_module_1 (function_module_1.py) and give them aliases:
    $ vi function_import_5.py
    # defining the alias a for the method add and the alias m for the method multiply
    from function_module_1 import add as a, multiply as m
    
    # calling directly the functions in the module function_module_1 using the specified alias for each function
    print(a(2, 3)) # Output: 5
    print(m(2, 3)) # Output: 6
© 2025  mtitek