Function
Function arguments refer to data passed to the function. In python, there four main types of arguments: positional arguments, keyword arguments, default arguments, and variable length arguments.
- Positional arguments are passed to a function in a specific order, and the values are assigned to parameters based on their position.
- Keyword arguments are passed to a function by explicitly specifying the parameter name. Any keyword arguments must be put after the last positional argument.
- A default argument allows a function to accept values for parameters that are not provided by the caller. If no argument is passed for a parameter with a default value, the default will be used. Any default arguments must be put after the last positional argument.
- Variable length arguments allow a function to accept any number of positional arguments.
*args
accepts all arguments into a tuple, while**kwargs
accepts all arguments into a dictionary.
SHOW CODE
def function_arguments(a, b=2, *args, c=3, **kwargs):
print(f"a: {a}, b: {b}, args: {args}, c: {c}, kwargs: {kwargs}")
function_arguments(1, 1997, 9, 99, 999, name="Signal", age=27)
SHOW OUTPUT
a: 1, b: 1997, args: (9, 99, 999), c: 3, kwargs: {'name': 'Signal', 'age': 27}
In Python, functions always return a value, if no
return
is specified, they returnNone
.
SHOW CODE
def check_even(num):
if num % 2 == 0:
return True
# No else clause, so returns None if odd
print(check_even(3)) # None
In Python, a variable defined outside a function is accessible within the function’s body, but only for reading its value. If a value is assigned to the variable inside the function, a new local variable with the same name is created, and the external variable remains unchanged.
SHOW CODE
x = 1
def fun():
print(x)
fun() # 1
x = 1
def fun():
x = 2
print(x)
fun() # 2
To modify a variable defined outside a function, the
global
keyword can be used, extending the variable’s scope into the function and allowing both reading and modification.
SHOW CODE
x = 1
def fun():
global x
x = 2
print(x)
print(x) # 1
fun() # 2
print(x) # 2
For function arguments, if the argument is a list, modifying the parameter itself doesn’t affect the original list, but modifying the list’s contents will affect the original list.
SHOW CODE
def fun(list_1):
print("Before modification...")
print(f"list_1: {list_1}")
print(f"list_2: {list_2}")
list_1 = [0, 0] # Modify the parameter itself
print("After modification...")
print(f"list_1: {list_1}")
print(f"list_2: {list_2}")
list_2 = [1, 2]
fun(list_2)
print(f"Outside the funtion: list_2 = {list_2}")
######################### Output #########################
Before modification...
list_1: [1, 2]
list_2: [1, 2]
After modification...
list_1: [0, 0]
list_2: [1, 2]
Outside the function: list_2 = [1, 2]
##########################################################
##################### Memory Diagram #####################
+-----------+ +--------+ +-----------+
| list_2 | ----> | [1, 2] | <---- | list_1 |
+-----------+ +--------+ +-----------+
############### Executing list_1 = [0, 0] ################
+-----------+ +--------+
| list_2 | ----> | [1, 2] |
+-----------+ +--------+
+-----------+ +--------+
| list_1 | ----> | [0, 0] |
+-----------+ +--------+
##########################################################
def fun(list_1):
print("Before modification...")
print(f"list_1: {list_1}")
print(f"list_2: {list_2}")
list_1[0] = 999 # Modify the list's content
print("After modification...")
print(f"list_1: {list_1}")
print(f"list_2: {list_2}")
list_2 = [1, 2]
fun(list_2)
print(f"Outside the function: list_2 = {list_2}")
######################### Output #########################
Before modification...
list_1: [1, 2]
list_2: [1, 2]
After modification...
list_1: [999, 2]
list_2: [999, 2]
Outside the funtion: list_2 = [999, 2]
##########################################################
##################### Memory Diagram #####################
+-----------+ +--------+ +-----------+
| list_2 | ----> | [1, 2] | <---- | list_1 |
+-----------+ +--------+ +-----------+
############### Executing list_1[0] = 999 ################
+-----------+ +----------+ +-----------+
| list_2 | ----> | [999, 2] | <---- | list_1 |
+-----------+ +----------+ +-----------+
##########################################################
Operators
- Floor division
//
rounds down the result of the division, truncating any fractional part. For example,-6 // 4
outputs-2
. - Left-sided binding refers to the way operators or expressions are evaluated from left to right. Most operators evaluate left-to-right. For example,
9 % 6 % 2
returns1
. - Right-sided binding refers to expressions where the evaluation happens from right to left. The exponentiation operator (
**
) and the chained assignment evaluate right-to-left. - Compound assignment operators allow performing an operation and then assign the result of it to a variable in a single step. For example, the expression
a /= 2 * 3
evaluates2 * 3
to6
, and then performsa = a / 6
that returns1.0
.
List
When assinging a list to a new variable, both variables reference the same list object in memory, meaning modifying one variable affects the other because they point to the same data.
SHOW CODE
list_1 = ["A", "B", "C"]
list_2 = list_1
list_3 = list_2
###################### Memory Diagram #####################
+-----------+ +-----------------+ +-----------+
| list_1 | ----> | ["A", "B", "C"] | <---- | list_2 |
+-----------+ +-----------------+ +-----------+
^
|
+-----------+
| list_3 |
+-----------+
###########################################################
del list_1[0]
################### Memory Diagram ###################
+-----------+ +------------+ +-----------+
| list_1 | ----> | ["B", "C"] | <---- | list_2 |
+-----------+ +------------+ +-----------+
^
|
+-----------+
| list_3 |
+-----------+
######################################################
del list_2
####### Memory Diagram ###########
+-----------+ +------------+
| list_1 | ----> | ["B", "C"] |
+-----------+ +------------+
^
|
+-----------+
| list_3 |
+-----------+
##################################
print(list_3) # ["B", "C"]
To copy the contents of the original list, slicing is commonly used.
SHOW CODE
list_1 = ["A", "B", "C"]
list_2 = list_1[:]
list_3 = list_2[:]
############ Memory Diagram ###########
+-----------+ +-----------------+
| list_1 | ----> | ["A", "B", "C"] |
+-----------+ +-----------------+
+-----------+ +-----------------+
| list_2 | ----> | ["A", "B", "C"] |
+-----------+ +-----------------+
+-----------+ +-----------------+
| list_3 | ----> | ["A", "B", "C"] |
+-----------+ +-----------------+
#######################################
del list_1[0]
############ Memory Diagram ###########
+-----------+ +-----------------+
| list_1 | ----> | ["B", "C"] |
+-----------+ +-----------------+
+-----------+ +-----------------+
| list_2 | ----> | ["A", "B", "C"] |
+-----------+ +-----------------+
+-----------+ +-----------------+
| list_3 | ----> | ["A", "B", "C"] |
+-----------+ +-----------------+
#######################################
del list_2[0]
############ Memory Diagram ###########
+-----------+ +-----------------+
| list_1 | ----> | ["B", "C"] |
+-----------+ +-----------------+
+-----------+ +-----------------+
| list_2 | ----> | ["B", "C"] |
+-----------+ +-----------------+
+-----------+ +-----------------+
| list_3 | ----> | ["A", "B", "C"] |
+-----------+ +-----------------+
#######################################
print(list_3) # ["A", "B", "C"]
List comprehension in Python provides a concise way to create lists by applying an expression to each item in an iterable and optionally filtering items based on a condition. It is typically faster than using loops for constructing lists.
SHOW CODE
# [expression for item in iterable if condition]
squares = [x**2 for x in range(10) if x % 2 == 0]
print(squares) # [0, 4, 16, 36, 64]
Tuple & Dictionary
Tuples are immutable sequences. A tuple with a single item must have a trailing comma (
tup = (5, )
) to differentiate it from a regular parentheses-enclosed expression.
Tuple unpacking allows extracting elements of a tuple into variables. The number of variables must match the number of elements in the tuple.
SHOW CODE
sides = (1, 2, 2)
a, b, c = sides
print(a, b, c) # 1 2 2
Dictionaries are mutable and unordered collections of key-value pairs. In Python 3.6x, dictionaries have become ordered by default, meaning the order of item is preserved based on the order of insertion.
Keys in a dictionary must be of a type that is immutable (e.g., strings, numbers, or tuples). Mutable types like lists or dictionaries themselves cannot be used as dictionary keys.
SHOW CODE
valid = {('a', 'b'): 'tuple_key'} # OK
invalid = {['a', 'b']: 'list_key'} # TypeError