3. Scripts & Functions#
3.1. Python as a script#
While Python’s interactive mode is useful for quick experiments and testing small snippets of code, it becomes cumbersome for developing complex programs. To manage more intricate projects, Python is typically used in script mode. In this mode, the program’s instructions are written and saved in a file called a script file (see glossary Script). The script file is a simple plain text file that contains the sequence of Python commands and statements necessary to perform the desired tasks.
The script file is typically named with a .py
extension, which identifies it as a Python script. For example, a file might be named my_program.py
. Once the script is written and saved, it can be executed by the Python interpreter. To run the script, you open a terminal or command prompt and enter the following command: python my_program.py
. When you execute this command, the Python interpreter reads the file and executes the lines of code sequentially, from top to bottom, just as if you were typing them one by one in interactive mode. However, because the code is stored in a file, it is much easier to organize, edit, and debug, making script mode ideal for developing more complex and reusable programs.
Let’s imagine we want to create a small program to simply calculate the average of two numbers. We will first do it in the interpreter, then transform it into a script and gradually make it more complex. Here is a series of instructions that can be typed into the interpreter.
>>> a = float(input())
12.5
>>> b = float(input())
16
>>> (a+b)/2
14.25
The value 12.5
and 16
are typed bu the used. The expected result 14.25
is displayed by the interpreter as the result of the expression (a+b)/2
is not None
. Everything seems okay.
To avoid retyping these instructions every time we want to perform this average calculation, we create a file named mean.py
and place the above instructions in it. We then execute the program by typing python mean.py. Here are some commands typed into a terminal. Lines starting with the %
character indicate that the terminal is waiting for a command, which is typed afterward. Lines without the %
character are the terminal’s responses to the commands. The cat mean.py
command displays the contents of the mean.py
file. The python mean.py
command tells the Python interpreter to execute the instructions in the mean.py
file. The values 12.5
and 16
seen in the terminal were entered by the user via the keyboard. Before their entry, the program was paused, waiting for these values and for the Enter key
to be pressed.
% cat mean.py
a = float(input())
b = float(input())
(a+b)/2
% python mean.py
12.5
16
%
Unlike the interpreter, the intermediate values of calculations are not displayed, and specifically, the expected result is not shown during program execution. In the case of a script, anything we want to display in the terminal must be explicitly indicated using the print
function. This function takes as a parameter the string to be displayed. A script may be
% cat mean.py
print("Enter two values.")
a = float(input())
b = float(input())
print("The mean is :")
print((a+b)/2)
% python mean.py
Enter two values.
12.5
16
The mean is :
14.25
%
3.2. Functions#
Functions (see glossary Function) are a core component of programming that allow us to encapsulate reusable blocks of code (see glossary Block). They improve code organization, readability, and maintainability. In Python, you’ve already used several built-in functions like print
, input
, int
, float
, and str
. In this section, we’ll explore how to define and use your own functions.
3.2.1. Function Declaration#
A function in Python is defined using the def
keyword (see glossary Keyword), followed by the function’s name, parameters in parentheses, and a colon (:
). The code block within the function, known as the function body, is indented. Let’s start with a simple example: a function that calculates the square of a number.
def square(x):
r = x*x
return r
Breaking down the function.
def
, this keyword tells Python that you are defining a function.square
, this is the name of the function. You will use this name to use the function later.(x)
, these are the parameters of the function. Here,x
is a parameter, meaning that the function expects one argument when it is called.:
, the colon indicates the start of the function’s code block.line 2 and 3 are indedted. They are the function body, the instructions that will be executed when the function is called. The
return
statement specifies the value that the function will take.
3.2.2. Function Call#
To use the function, you call (see glossary Call) it by its name, followed by parentheses containing the arguments.
s = square(10)
print(s)
When you call square(10)
, Python performs the following steps:
The function
square
is invoked withx
set to10
.The expression
r = x * x
is evaluated, r is set to100
.Then, the
return
statement sends the value100
back to where the function was called.The value
100
is assigned to the variables
.Finally,
print(s)
displays100
.
3.2.3. Indentation in Python#
Python uses indentation (spaces or tabs) to define the structure of code blocks, such as the body of a function. The indentation level indicates that the lines belong to the same block. Improper indentation is a common source of errors for beginners. For example:
def square(x):
return x*x
File "<stdin>", line 2
return x*x
^
IndentationError: expected an indented block after function definition on line 1
In Python, each line of code inside a function must be indented to the same level. Omitting the colon after the function definition is another common mistake:
def square(x)
return x*x
File "<stdin>", line 1
def square(x)
^
SyntaxError: expected ':'
3.2.4. Variable Scope#
In Python, scope (see glossary Scope) refers to the region of a program where a variable is accessible. Understanding variable scope is essential because it helps avoid unintended errors, such as using variables where they are not meant to be used or accidentally modifying variables from another part of the program. Variables can be classified into different scopes depending on where they are declared and used.
3.2.4.1. Local scope#
Variables that are defined within a function have a local scope. This means they are only accessible within that function and cannot be accessed outside of it. The parameters of a function, as well as any variables declared inside the function, fall into this category. Once the function finishes executing, these local variables are destroyed, and their memory is freed.
Example of Local Scope:
def cube(x):
y = x * x * x
return y
cube(10)
print(y)
Traceback (most recent call last):
File "<stdin>", line 5, in <module>
NameError: name 'y' is not defined
In this example, the variable y
is created within the cube
function and is therefore only accessible inside that function. When the function is called with cube(10)
, y
is created and the value refered to is returned. But y
cannot be accessed outside of the function, this variable is freed at the end of the function execution. Attempting to print y
outside of the function results in a NameError
.
The NameError
occurs because Python cannot find the variable y
outside the cube
function. Since y
is defined within the function, it only exists while the function is executing. After the function returns, the variable y
ceases to exist. As a result, trying to print y
outside the function leads to an error.
3.2.4.2. Global Scope#
In contrast to local variables, variables defined outside of any function have a global scope. They can be accessed from any part of the code, including inside functions (unless overridden by a local variable with the same name). However, it’s generally good practice to limit the use of global variables to avoid unintended side effects and make the code easier to understand and debug. Example of Global and Local Scope:
z = 5 # Global variable
def multiply(a):
b = a * z # z is accessible here
return b
result = multiply(3)
print(result) # Outputs: 15
In this example, z
is a global variable and is accessible both inside and outside the multiply
function. However, the variable b
is local to the multiply
function and cannot be accessed outside of it.
3.2.4.3. Minimizing the Use of Global Variables#
In programming, the use of global variables should be minimized due to potential issues related to code maintainability, readability, and debugging. Global variables are accessible from anywhere in the code, which can lead to unintended side effects if they are modified in different parts of a program. Consequently, the use of global variables is generally reserved for specific scenarios where their benefits outweigh the drawbacks.
Global variables are often used for defining constants or configuration values that are set once and should remain unchanged throughout the execution of the program. For instance, in a physics simulation software, fundamental constants such as Planck’s constant or the speed of light can be defined as global variables. These constants are used across various modules of the program but are not modified after their initial definition.
#Global constants
PLANCK_CONSTANT = 6.626e-34
SPEED_OF_LIGHT = 3.0e8
def calculate_energy(frequency):
return PLANCK_CONSTANT * frequency
def calculate_time(distance):
return distance / SPEED_OF_LIGHT
In this example, PLANCK_CONSTANT
and SPEED_OF_LIGHT
are global constants that are used in multiple functions but are not intended to be changed. By keeping these values global, we ensure that they are consistently available throughout the program without duplication. By convention, the names of global variables are written in uppercase.
By default, Python does not allow the modification of global variables within a function unless explicitly stated. This is to prevent inadvertent changes to important global values.
PLANCK_CONSTANT = 6.626e-34
def change():
PLANCK_CONSTANT = 2 # create a local variable which hide the global variable
change()
print(PLANCK_CONSTANT) # will print 6.626e-34
3.2.5. Function Parameters and Calls#
Functions in Python can take any number of parameters or none at all. When calling a function, you must specify the exact number of parameters in the parentheses. Proper use of parentheses is crucial for executing a function correctly.
Consider the function discriminant
, which computes the discriminant of a quadratic equation given coefficients a
, b
, and c
.
def discriminant(a, b, c):
return b * b - 4 * a * c
print(discriminant(1, 2, 1)) # Outputs: 0
In this example, the function discriminant
requires three parameters (a
, b
, and c
). When calling the function, you provide the arguments 1
, 2
, and 1
within the parentheses.
Even if a function does not take any parameters, parentheses are still required to call it. For example, the input
function prompts the user to enter a string.
user_input = input() # Requires parentheses to execute
print(user_input)
Without parentheses, input
is not executed; it is simply referenced as a function object. If you omit the parentheses when referencing a function, Python treats it as an object rather than executing it.
>>> x = input
>>> print(x)
<built-in function input>
In this case, x
is assigned to the input
function object, not its execution. Printing x
shows that it is a built-in function object rather than the result of a function call. To execute the function stored in x
, you need to include parentheses:
>>> x = input
>>> print(x()) # This will prompt for input
A value
A value
Here, x
correctly invokes the input function, allowing you to enter the string A value
. The function call works as intended, prompting the user for input and then printing the result.
Understanding the distinction between function references and function calls helps in writing clearer and more predictable code. For now, focus on correctly using parentheses to execute functions and avoid common pitfalls related to function objects.
3.2.6. Functions with and without Return Values#
In Python, functions can be defined to return values or to perform actions without returning a value. The return
keyword is used in a function to specify what value should be returned to the caller. The value provided after the return
statement replaces the function call in expressions or assignments. Once the return
statement is executed, the function exits, and any code following the return
statement is not executed.
def square(x):
return x * x
print("This message will never be displayed")
c = square(10) * 5
In this example:
The function
square
computes the square ofx
and returns the result.The
print("This message will never be displayed")
line is never executed because the function exits when it encounters thereturn
statement.The value
100
is returned bysquare(10)
, and then it is multiplied by5
resulting in500
.Thus,
c
is assigned the value500
.
A function does not have to include a return
statement. If a function does not use return
, it implicitly returns None
. This is the default return value for functions that do not explicitly return a value.
>>> a = print("X")
>>> print(a)
None
In this example:
The
print("X")
function outputsX
to the screen.Since
print
does not have an explicit return value, it returnsNone
by default.The variable
a
is assigned the valueNone
.Therefore, when
print(a)
is executed, it printsNone
.