Understanding Function, Module & Class In Python
This is the 6th post in a series of learning the Python programming language.
Function
A function is a block of code that performs a specific task. Functions are defined using the “def” keyword, followed by the function name and a set of parentheses that may contain parameters. The code block within the function is indented and starts with a colon. Functions can take input parameters and return output.
Here’s an example of a simple function called “greet”:
def greet(name):
print("Hello, " + name)
greet("John")
This function takes one parameter called “name” and prints “Hello, name” to the console. When the function is called with the argument “John”, the output will be “Hello, John”.
Functions can also return values using the “return” statement. For example, the following function takes two numbers as input and returns their sum:
def add(a, b):
return a + b
result = add(3, 4)
print(result)
This function takes two parameters, “a” and “b”, adds them together, and returns the result. When the function is called with the arguments 3 and 4, the output will be 7.
Functions can also have default values for their parameters, which are used when a value is not provided when the function is called. For example:
def greet(name, greeting="Hello"):
print(greeting + ", " + name)
greet("John") # prints "Hello, John"
greet("John", "Hi") # prints "Hi, John"
In this example, the function “greet” takes two parameters, “name” and “greeting”, with “greeting” having a default value of “Hello”. When the function is called with only one argument, the default value is used for the second argument.
Functions are first-class citizens
In Python, Functions are first-class citizens, meaning they can be treated like any other data type, such as an integer or string. They can be passed as arguments to other functions, stored in data structures, and so on.
Lambda functions
Additionally, Python has a feature called “lambda functions” which allows you to define a small anonymous function in a single line. They are also known as “anonymous functions” or “lambda expressions”.
add = lambda a, b : a + b
result = add(3,4)
print(result)
In Python, function arguments can also be passed using special syntax *args
and **kwargs
which allows a function to accept a variable number of arguments. *args
allows a function to accept any number of non-keyword arguments and **kwargs
allows a function to accept any number of keyword arguments.
def test_function(arg1, *args, **kwargs):
print(arg1) # 1
print(args) # (2, 3, 4, 5)
print(kwargs) # {'name': 'John', 'age': 25}
test_function(1, 2, 3, 4, 5, name='John', age=25)
Function decorators
In Python, a function decorator is a feature that allows you to modify the behavior of a function, without modifying its code. A function decorator is a function that takes another function as input and returns a new function. The new function, also known as the “decorated” function, typically includes additional functionality before or after the original function is called.
Function decorators are defined using the “@” symbol followed by the decorator function name. Here is an example of a simple decorator function that adds logging functionality to a function:
def my_logger(original_function):
import logging
logging.basicConfig(filename='{}.log'.format(original_function.__name__), level=logging.INFO)
def wrapper(*args, **kwargs):
logging.info(
'Ran with args: {}, and kwargs: {}'.format(args, kwargs))
return original_function(*args, **kwargs)
return wrapper
@my_logger
def display():
print('display function ran')
display()
In this example, the my_logger
function is a decorator that takes the display
function as input and returns a new function called wrapper
. The @my_logger
syntax is a shortcut for saying display = my_logger(display)
. When display
is called, it runs the code within the wrapper
function, which includes logging the input arguments and the return value of the original `display
Module
A module in Python is a single file that contains Python code. It can define functions, classes, and variables, and can be imported into other Python files or scripts to be used.
To create a module, simply create a new .py file and write your Python code inside it. You can then import the module into other files using the import statement. For example, if you have a module named “mymodule.py”, you can import it into another file using the following code:
import mymodule
Once the module is imported, you can access its functions, classes, and variables using the dot notation. For example, if the module “mymodule.py” defines a function named “myfunction()”, you can call that function using the following code:
mymodule.myfunction()
You can also use the “from” keyword to import specific elements from a module. For example, you can use the following code to import only the “myfunction()” function from “mymodule.py”:
from mymodule import myfunction
After that, you can use the function directly without prefixing the module name.
myfunction()
You can also use the “as” keyword to give a module or a specific element from a module a different name when importing it. For example, you can use the following code to import “mymodule.py” and give it the name “m”:
import mymodule as m
Once you have imported the module, you can access its elements using the new name.
m.myfunction()
It’s important to note that when you import a module, Python runs all the code in the module. If you have any code in your module that you only want to run when the module is run directly, you can use the following code at the bottom of your module:
if __name__ == "__main__":
# code to run when the module is run directly
This way when you import the module the code inside this block won’t be executed but when you run the module directly, the code inside the block will be executed.
Class
A class is a blueprint for creating objects (a particular data structure), providing initial values for state (member variables or attributes), and implementations of behavior (member functions or methods).
The class is defined using the “class” keyword, followed by the name of the class. The class definition usually contains a number of class variables and class methods.
A class variable is a variable that is shared by all instances of a class. Class variables are defined within the class but outside of any of the class’s methods.
A class method is a method that is bound to the class and not the instance of the object.
An object is an instance of a class and has its own state and behavior. An object can be created using the class name followed by parentheses.
class Person:
species = "Homo sapiens"
def __init__(self, name, age):
self.name = name
self.age = age
def info(self):
return f"{self.name} is {self.age} years old"
p1 = Person("John", 36)
p2 = Person("Amy", 25)
print(p1.info())
print(p2.info())
In the above example, species
is a class variable that is shared by all instances of the class Person
. name
and age
are instance variables, which are unique to each object. info()
is a method that is common to all instances of the class Person
.
There are different types of methods that can be defined within a class:
- Instance method: These are the most common type of method and are bound to a specific instance of the class. They can access and modify the state of the instance, and typically use the “self” parameter to refer to the instance.
- Class method: These methods are bound to the class itself, rather than a specific instance. They are defined using the “@classmethod” decorator and use the “cls” parameter to refer to the class. Class methods are often used for factory methods, which create and return new instances of the class.
- Static method: These methods are also bound to the class, rather than a specific instance. They are defined using the “@staticmethod” decorator and do not have access to the class or instance state. Static methods are often used for utility functions that don’t need to access any class or instance data.
class MyClass:
x = [1, 2, 3]
def __init__(self, value):
self.value = value
def instance_method(self):
print(f"This is an instance method. Value = {self.value}")
@classmethod
def class_method(cls):
print(f"This is a class method. x = {cls.x}")
@staticmethod
def static_method():
print("This is a static method.")
def normal_method():
print("This is a normal method.")
instance_method()
is an instance method because it takes theself
parameter, which refers to the instance of the class. When called on an instance of the class, it can access and modify the instance’svalue
attribute.class_method()
is a class method because it takes thecls
parameter, which refers to the class itself. When called on the class, it can access and modify class-level attributes, such as thex
attribute.static_method()
is a static method because it doesn’t take any special parameters, such asself
orcls
. It can’t access or modify any instance or class-level attributes, but it can be called on the class or an instance of the class.
You can call these methods on an instance of the class like this:
obj = MyClass(10)
obj.instance_method() # This is an instance method. Value = 10
obj.class_method() # This is a class method. x = [1, 2, 3]
obj.static_method() # This is a static method
You can also call these methods on the class itself:
MyClass.class_method() # This is a class method. x = [1, 2, 3]
MyClass.static_method() # This is a static method
OOPs Concepts
(Object-oriented programming) is a programming paradigm that uses objects and their interactions to design applications and computer programs. The main concepts of OOP are encapsulation, inheritance, and polymorphism.
Encapsulation
Encapsulation refers to the practice of hiding internal data and methods from external access and providing a public interface for interacting with the object. This ensures that the internal state of the object is protected from accidental or intentional changes and that the object’s behavior is consistent.
An example of encapsulation in Python is the use of the private
and protected
access modifiers, which are denoted by a single or double underscore prefix, respectively, on the name of a class member (attributes and methods). These members can only be accessed within the class or its subclasses.
class MyClass:
def __init__(self):
self.__private_var = 0
self._protected_var = 0
def set_private_var(self, value):
self.__private_var = value
def get_private_var(self):
return self.__private_var
def set_protected_var(self, value):
self._protected_var = value
def get_protected_var(self):
return self._protected_var
In the above example, __private_var
and _protected_var
can only be accessed within the class ‘MyClass’, and it’s not possible to access it directly from the object.
Inheritance
Inheritance is the ability to create new classes that inherit the properties and methods of existing classes. This allows for code reuse and a clear hierarchy of class relationships.
An example of inheritance in Python is the use of the class DerivedClass(BaseClass):
syntax to create a derived class that inherits from a base class.
class Shape:
def __init__(self, x, y):
self.x = x
self.y = y
def area(self):
return self.x * self.y
class Rectangle(Shape):
def __init__(self, x, y):
super().__init__(x, y)
class Square(Rectangle):
def __init__(self, x):
super().__init__(x, x)
sq = Square(4)
print(sq.area()) # 16
In the above example, the class Square
is derived from class Rectangle
, which itself is derived from class Shape
. So, the class Square
has access to the methods of both Rectangle
and Shape
classes.
Polymorphism
Polymorphism refers to the ability of a single function or method to work with multiple types of data. This means that the same function or method can be used to work with different types of objects, even if they are instances of different classes.
There are two main types of polymorphism in Python:
Duck Typing: Duck typing is a form of polymorphism in which the type of an object is determined by the methods and properties it has, rather than by its class. This means that if an object “walks like a duck and quacks like a duck”, it is considered to be a duck.
def quack(duck):
duck.quack()
class Duck:
def quack(self):
print("Quack")
class Goose:
def quack(self):
print("Honk")
duck = Duck()
goose = Goose()
quack(duck) # Quack
quack(goose) # Honk
In this example, quack
function is able to work with both Duck
and Goose
objects, even though they are instances of different classes because they both have a quack
method.
Method Overriding: Method overriding is a form of polymorphism in which a subclass can provide a different implementation of a method that is already defined in its superclass. This allows the subclass to inherit the behavior of the superclass, while also providing its own implementation.
class Animal:
def speak(self):
print("Animal make noise")
class Dog(Animal):
def speak(self):
print("Bark")
class Cat(Animal):
def speak(self):
print("Meow")
dog = Dog()
cat = Cat()
dog.speak() # Bark
cat.speak() # Meow
In this example, the speak
method is defined in the Animal
class, but Dog
and Cat
classes both provide their own implementation of the method. This allows the speak
method to behave differently depending on the type of object it is called on.
Summary
- Functions are one of the most important concepts in Python and are used to organize and reuse code. They can take input parameters, return output, have default values for parameters, and can be assigned to variables or used as arguments for other functions. Python also provides advanced features such as lambda functions, function decorators, and a variable number of arguments, which can be used to further enhance the functionality and readability of your code.
- Modules are a great way to organize and reuse your Python code and can help make your code more readable, maintainable, and efficient.
- Classes are important because they provide a way to create new data types. With classes, you can define the characteristics and behavior of a type of object, and then create instances of that object.
If you like the post, don’t forget to clap. If you’d like to connect, you can find me on LinkedIn.