Chapter 4.functions
Chapter 4.functions
and Packages
Introduction
• Functions, modules and packages are constructs that promote code
modularization.
• Modular programming – process of breaking a large programming task into
separate, smaller, more manageable subtasks or modules.
• A function is a block of organized, reusable code that is used to perform a
single, related operation. Python has excellent support for functions.
• A module is used to logically organize the code. A python module can be
defined as a python program file which contains a python program code
including the python functions, class or variables. I.e. our python code file
saved with .py extension is the module.
• A python package is a collection of modules which have a common
purpose. In short modules are grouped together to forms packages.
Packages allows us to create a hierarchical file directory structure of
modules.
Functions
• Python Functions is a block of statements that return the specific
task. The idea is to put some commonly or repeatedly done tasks
together and make a function so that instead of writing the same
code again and again for different inputs, we can do the function calls
to reuse code contained in it over and over again.
• Some Benefits of Using Functions:
✓Increase Code Readability
✓Increase Code Reusability
Python Function Declaration
# Driver code
num1, num2 = 5, 15
ans = add(num1, num2)
print(f"The addition of {num1} and {num2} results {ans}.")idl
Functions with default arguments
• A default argument is a parameter that assumes a default value if a
value is not provided in the function call for that argument.
# Python program to demonstrate
# default arguments
def myFun(x, y = 50):
print("x: ", x)
print("y: ", y)
# Driver code
myFun(10)
Output:
x: 10
y: 50
Functions with Keyword arguments
• The idea is to allow the caller to specify the argument name with values so
that the caller does not need to remember the order of parameters.
# Keyword arguments
student(firstname ='Geeks', lastname ='Practice')
student(lastname ='Practice', firstname ='Geeks')
Output:
Geeks Practice
Geeks Practice
Functions with Variable Length Arguments
Result of *args:
def myFun2(**kwargs):
Hello
for key, value in kwargs.items(): Welcome
print ("% s == % s" %(key, value)) to
GeeksforGeeks
print("\nResult of **kwargs")
myFun2(first ='Geeks', mid ='for', last ='Geeks')
Functions: Positional Arguments
• We used the Position argument during the function call so that the first argument (or value) is assigned to
name and the second argument (or value) is assigned to age. By changing the position, or if you forget the
order of the positions, the values can be used in the wrong places, as shown in the Case-2 example below,
where 27 is assigned to the name and Suraj is assigned to the age.
def nameAge(name, age):
print("Hi, I am", name) Output:
print("My age is ", age) Case-1:
Hi, I am Suraj
# You will get correct output because My age is 27
# argument is given in order Case-2:
print("Case-1:") Hi, I am 27
nameAge("Suraj", 27) My age is Suraj
# You will get incorrect output because
# argument is not in order
print("\nCase-2:")
nameAge(27, "Suraj")
Positional-Only Arguments
• You can specify that a function can have ONLY positional arguments, or ONLY keyword arguments.
• To specify that a function can have only positional arguments, add , / after the arguments:
def my_function(x, /):
print(x)
my_function(3)
• Without the , / you are actually allowed to use keyword arguments even if the function expects
positional arguments:
def my_function(x):
print(x)
my_function(x = 3)
• But when adding the , / you will get an error if you try to send a keyword argument:
def my_function(x, /):
print(x)
my_function(x = 3)
Keyword-Only Arguments
• To specify that a function can have only keyword arguments, add *, before the arguments:
def my_function(*, x):
print(x)
my_function(x = 3)
• Without the *, you are allowed to use positionale arguments even if the function expects
keyword arguments:
def my_function(x):
print(x)
my_function(3)
• But when adding the *, / you will get an error if you try to send a positional argument:
def my_function(*, x):
print(x)
my_function(3)
Combine Positional-Only and Keyword-Only
• You can combine the two argument types in the same function.
• Any argument before the / , are positional-only, and any argument
after the *, are keyword-only.
my_function(5, 6, c = 7, d = 8)
Pass by Reference or pass by value in Python
• One important thing to note is, in Python every variable name is a
reference. When we pass a variable to a function, a new reference to the
object is created. Parameter passing in Python is the same as reference
passing in Java. To confirm this Python’s built-in id() function is used in the
below example.
def myFun(x): Output:
print("Value received:", x, "id:", id(x)) Value passed: 12 id: 11094656
Value received: 12 id: 11094656
# Driver's code
x = 12
print("Value passed:", x, "id:", id(x))
myFun(x)
• If the value of the above variable is changed inside a function, then it will
create a different variable as a number that is immutable. However, if a
mutable list object is modified inside the function, the changes are
reflected outside the function also.
• Program: (function-with-mutable-list) # function with docstring also
# Recursive function
def recursive_fibonacci(n):
if n <= 1:
return n
else:
return(recursive_fibonacci(n-1) + recursive_fibonacci(n-2))
n_terms = 10
# check if the number of terms is valid
if n_terms <= 0:
print("Invalid input ! Please input a positive value")
else:
print("Fibonacci series:")
for i in range(n_terms):
print(recursive_fibonacci(i))
Output
Fibonacci series:
0
1
1
2
3
5
8
13
21
34
The lambda(Anomynous) function
• In Python, a lambda function is a special type of function without the
function name. A lambda function can take any number of arguments, but
can only have one expression, which is evaluated and returned.
• Syntax:
lambda argument(s): expression
Example:
lambda : print('Hello World')
# lambda call
greet_user(‘Oceanite')
x = lambda a : a + 10 # Output: 15
print(x(5))
Or, use the same function definition to make both functions, in the same program:
def myfunc(n):
return lambda a : a * n
mydoubler = myfunc(2)
mytripler = myfunc(3)
print(mydoubler(11)) #Output: 22
print(mytripler(11)) 33
Namespace
• A namespace is a collection of currently defined symbolic names along with
information about the object that each name references. You can think of a
namespace as a dictionary in which the keys are the object names and the values
are the objects themselves.
• In Python, a way to give each object a unique name is through a namespace.
Variables and methods are examples of objects in Python. To put it another way,
it is a collection of the known symbolic names and the details about the thing
that each name refers to. A name can be thought of as a key in a dictionary, and
objects are the values in a namespace. We should figure out it with a genuine
model - A namespace resembles a last name. If there are multiple “Siddhi" names
in the class, it may be difficult to locate a “Siddhi" name; however, when we
specifically request “Siddhi Patil" or “Siddhi Chorge," In a class, it might not be
common for multiple students to have the same first and last name.
• The Python interpreter can get a better understanding of the exact method or
variable in the code thanks to the namespace. As a result, its name contains
additional information, including Space (related to scope) and Name, which
denotes a unique identifier.
Namespace and Scope
(Module)
(Function)
• Namespaces are collections of different objects that are associated
with unique names whose lifespan depends on the scope of a
variable. The scope is a region from where we can access a particular
object.
• Namespaces define the context in which identifiers exist, while scope
delineates the regions where these identifiers are accessible.
• In Python, there are four types of namespaces which are given below:
o Built-in
o Global
o Enclosing
o Local
• As these namespace various have lifetimes, Python interpreter creates
namespaces as necessary and deletes them when they are no longer needed.
• The Built-in Namespace:
The Built-in Namespace in Python is a fundamental repository of predefined names and objects
that are available globally in any Python script or module. It encompasses core functions and
objects that form the backbone of the language, including functions like print(), len(), and
constants like True and False. This Python Namespace class is automatically loaded when
Python starts and persists throughout the entire runtime. It provides a foundation for basic
operations, allowing programmers to utilize these essential functionalities without the need for
explicit import statements. Understanding the Built-in Namespace is crucial for any Python
developer, as it forms the basis for constructing complex applications and scripts.
• Let's list these names with the following command. Open the Python terminal
and type the following command.
• Command –
>>> dir(__builtins__)
Output
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError',
'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError',
'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FileExistsError',
'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning',
'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError',
'MemoryError', 'ModuleNotFoundError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError',
'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'RecursionError',
'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError',
'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError',
'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning',
'ValueError', 'Warning', 'WindowsError', 'ZeroDivisionError', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__',
'__name__', '__package__', '__spec__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'breakpoint', 'bytearray', 'bytes', 'callable', 'chr',
'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float',
'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license',
'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr',
'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
Python interpreter create the built-in namespace when it starts up. These are
terminated when Python interpreter terminates.
• The Global Namespace:
• The global namespace consists of any names in Python at any level of the
main program. It is created when the main body executes and remains in
existence until the interpreter terminates.
• The Python interpreter creates a global namespace for any module that our
Python loads with the import statement.
• The Global Namespace in Python refers to the scope where names or
identifiers are defined at the top level of a module or script. Variables,
functions, and classes declared here are accessible throughout the entire
module or script. They can be used in any part of the code, including within
functions and classes. This namespace is created when a module is
imported or a script is executed, and it persists until the program
terminates or the module is explicitly unloaded. Understanding the Global
Namespace is crucial for managing variables that need to be accessed by
multiple parts of a program, ensuring their availability and coherence in a
Python script.
• The Local and Enclosing Namespaces:
• The local namespaces are used by the function; When the function is run, the
Python interpreter creates a new namespace. The local namespaces continue to
exist after the function has finished running. The capability can likewise comprise
of another capability. As shown below, we can define one function within
another.
• The Local Namespace in Python pertains to the scope within a function or
method. Variables defined here are only accessible within that specific function
or method. Once the function completes its execution, the local namespace and
its variables are removed from memory.
• The Enclosing Namespace, also known as non-local scope, applies to nested
functions. If a variable isn't found in the local scope, Python searches for it in the
enclosing scope. This allows inner functions to access variables from outer
functions.
• Understanding local and enclosing namespaces is crucial for managing variable
scope and preventing naming conflicts in Python programs. It ensures that
variables are appropriately isolated and accessible in the right parts of the code.
• Example -
Scope of the Objects/Variable
• The scope of an object or variable in Python defines the region in a
program where that object can be accessed. There are three primary
scopes:
• Local Scope: Variables defined within a function are local and can
only be accessed within that function.
• Enclosing (or Non-Local) Scope: Pertains to variables in a nested
function. If a variable isn't found in the local scope, Python looks for it
in the enclosing scope.
• Global Scope: Variables defined at the top-level of a module or script
are global and can be accessed throughout the entire module or
script.
Changing Variables Out of Scope
• Changing variables out of their scope in Python involves using the global
and nonlocal keywords.
• Global Variables:
• By default, if you modify a variable within a function, Python creates a new
local variable with the same name, leaving the global variable unchanged.
To modify a global variable from within a function, you must use the global
keyword.
• Example:
x = 10
def change_global():
global x
x = 20
change_global()
print(x) # Output: 20
• Non-Local Variables:
• In nested functions, if you want to modify a variable from an outer function, you
use the nonlocal keyword.
• Example:
def outer_function():
y = 10
def inner_function():
nonlocal y
y = 20
inner_function()
print(y) # Output: 20
outer_function()
• These keywords allow you to explicitly indicate that a variable is intended to be
modified from an outer scope, ensuring clarity and avoiding unexpected behavior.
Modules
• Python Module is a file that contains built-in functions, classes, its and variables.
There are many Python modules, each with its specific work.
• We will cover all about Python modules, such as how to create our own simple
module, Import Python modules, From statements in Python, we can use the
alias to rename the module, etc.
• Grouping related code into a module makes the code easier to understand and
use. It also makes the code logically organized.
• Create a Python Module
• To create a Python module, write the desired code and save that in a
file with .py extension. Let’s understand it better with an example:
• Example:
• Let’s create a simple calc.py in which we define two functions,
one add and another subtract.
• # A simple module, calc.py
def add(x, y):
return (x+y)
print(sqrt(16)) Output:
print(factorial(6)) 4.0
720
• Import all Names
• The * symbol used with the import statement is used to import all the names
from a module to a current namespace.
• Syntax:
from module_name import *
• What does import * do in Python?
• The use of * has its advantages and disadvantages. If you know exactly what you
will be needing from the module, it is not recommended to use *, else do so.
# importing sqrt() and factorial from the
# module math
from math import *
# importing sys.path
print(sys.path)
Output:
['C:\\Users\\sabalesm\\AppData\\Local\\Programs\\Python\\Python312\\Lib\\idlelib',
'C:\\Users\\sabalesm\\AppData\\Local\\Programs\\Python\\Python312\\python312.zip',
'C:\\Users\\sabalesm\\AppData\\Local\\Programs\\Python\\Python312\\DLLs',
'C:\\Users\\sabalesm\\AppData\\Local\\Programs\\Python\\Python312\\Lib',
'C:\\Users\\sabalesm\\AppData\\Local\\Programs\\Python\\Python312',
'C:\\Users\\sabalesm\\AppData\\Local\\Programs\\Python\\Python312\\Lib\\site-
packages']
• Renaming the Python Module
• We can rename the module while importing it using the keyword.