Functions, Classes, and Objects
Writing Pythonic code¶
What is “Pythonic”?¶
Code is read much more often than it is written.
“Pythonic” means code that follows the conventions of the Python community. It is clean, readable, and concise.
PEP 8 is the official “Style Guide” for Python code. It’s like the grammar rules for the language.
import thisOutput
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
What is a Function?¶
A function is a block of organized, reusable code that performs a specific task.
DRY Principle: “Don’t Repeat Yourself.” If you find yourself copy-pasting code, you should probably make it a function.
Modularity: It breaks a complex problem (like “Process the Census”) into small, manageable pieces (e.g., “Clean Name”, “Calculate Age”, “Validate Address”).
Anatomy of a Function¶
defkeyword: Tells Python you are defining a function.function name: Follows
snake_caserules (e.g.,calculate_yield). Used to identify and call a function.parameters: The inputs the function needs (inside parentheses).
docstring: A comment describing what the function does.
return value: The output sent back to the main program.
Syntax¶
def function_name(parameter1, parameter2):
"""docstring: Explains what this does."""
# Code block
result = parameter1 + parameter2
return resultdef greet_farmer():
"""Prints a simple welcome message."""
print("Magandang araw! Welcome to the Digital Census.")
# Calling the function
greet_farmer()Output
Magandang araw! Welcome to the Digital Census.
Parameters and Arguments¶
Parameter: The variable name in the function definition (e.g.,
area).Argument: The actual value you pass when running it (e.g.,
5.5).
We can also set Default Arguments. These are used if the user doesn’t provide a value.
# greet_farmer function with 2 named parameters: first_name and last_name with default valuse Juan and dela Cruz, respectively
def greet_farmer(first_name="Juan", last_name="dela Cruz"):
print(f"Magandang araw {first_name} {last_name}! Welcome to the Digital Census.")Output
greet_farmer()Output
Magandang araw Juan dela Cruz! Welcome to the Digital Census.
# running greet_farmer with a different first parameter
greet_farmer(first_name="Maria")Output
Magandang araw Maria dela Cruz! Welcome to the Digital Census.
return vs. print¶
This is a common point of confusion.
print(): Displays text on the screen. The computer “forgets” it immediately.return: Gives the value back to the program so you can store it in a variable.
def get_area_print(length, width):
area = length * width
print(area) # Just shows it
def get_area_return(length, width):
area = length * width
return area # Gives it back
result_1 = get_area_print(10, 10) # Prints 100, but result_1 is None
result_2 = get_area_return(10, 10) # result_2 becomes 100
print(f"Stored from Print: {result_1}")
print(f"Stored from Return: {result_2}")Output
100
Stored from Print: None
Stored from Return: 100
Classes and Objects¶
Definitions¶
When used in the Object-Oriented paradigm:
Class: The blueprint or template; It defines what attributes and methods the objects created from the class will have (e.g., The definition of a “Farm”).
Object: A specific instance of a class that encapsulates/inherits the class’ attributes (data) and methods (behavior) (e.g., “Mang Juan’s Farm”).
Methods: Functions that the object can perform (e.g., Calculate Yield).
Attributes: Variables stored inside the object (e.g., Hectares, Crop Type).
Methods and attributes can both either be defined for the class or specific instance/object.
Class methods are bound to the class and not to a specific instance of a class making them useful as factory methods or for accessing class-level attributes.
Class attributes are shared by all instances of a class compared to instance attributes that are specific to one instance.
The __init__ Method¶
This is a special function that runs automatically when you create a new Object. We use it to set up the initial data.
class Farm:
def __init__(self, name, crop, hectares):
# Attributes: Data specific to this farm
self.name = name
self.crop = crop
self.hectares = hectares
# Method: An action the farm can perform
def describe_farm(self):
return f"{self.name} plants {self.crop} on {self.hectares} hectares."
# Creating an Object (Instance)
my_farm = Farm("Maligaya Estate", "Palay", 10)
# Calling a Method
print(my_farm.describe_farm())Output
Maligaya Estate plants Palay on 10 hectares.
Overriding Methods (Polymorphism)¶
In Python, we can change how standard commands work for our custom objects.
For example, if you try to print(my_farm) right now, Python will give you a messy code like <__main__.Farm object at 0x00...>.
We can fix this by overriding the special __str__ method.
print(my_farm)Output
<__main__.Farm object at 0x77d564306270>
class Farm:
def __init__(self, name, crop, hectares):
self.name = name
self.crop = crop
self.hectares = hectares
def estimate_production(self):
"""Assume standard yield of 4.5 tons/ha"""
return self.hectares * 4.5
# OVERRIDING the standard print function
def __str__(self):
return f"FARM: {self.name} | CROP: {self.crop} | AREA: {self.hectares} ha"
farm_1 = Farm("Maligaya Fields", "Corn", 5)
print(farm_1)
print(f"Estimated Harvest: {farm_1.estimate_production()} tons")Output
FARM: Maligaya Fields | CROP: Corn | AREA: 5 ha
Estimated Harvest: 22.5 tons
Practice Exercises¶
Creating a class¶
Create a class
Livestock.In the
__init__method, acceptspecies(e.g., “Carabao”) andcount(e.g., 4).Create an object called
my_animalsand print itsspeciesattribute.
Source
class Livestock:
"""
A class to represent livestock.
Attributes:
species (str): The species of the livestock.
count (int): The number of animals.
"""
def __init__(self, species: str, count: int):
"""
Initialize a Livestock object.
Args:
species (str): The species of the livestock.
count (int): The number of animals.
"""
self.species = species
self.count = count
# Example usage:
my_animals = Livestock("Carabao", 4)
print(my_animals.species) # Output: CarabaoCarabao
Adding a class method¶
Add a standard method called
check_status().If
count< 20, return “Small Herd”.Else, return “Commercial Herd”.
Create several instances of Livestock and check their status.
Source
class Livestock:
"""
A class to represent livestock.
Attributes:
species (str): The species of the livestock.
count (int): The number of animals.
"""
def __init__(self, species: str, count: int):
"""
Initialize a Livestock object.
Args:
species (str): The species of the livestock.
count (int): The number of animals.
"""
self.species = species
self.count = count
def check_status(self) -> str:
"""
Determine the status of the herd based on its size.
Returns:
str: "Small Herd" if count < 5, otherwise "Commercial Herd".
"""
if self.count < 20:
return "Small Herd"
else:
return "Commercial Herd"# Example usage:
my_animals = Livestock("Carabao", 50)
print(my_animals.check_status())
my_animals = Livestock("Cow", 8)
print(my_animals.check_status())Commercial Herd
Small Herd
Overriding the print method¶
Override the
__str__method to yourLivestockclass.It should return a string like: “Registered Herd: {count} heads of {species}”.
Create an instance and pass it directly to the
print()function to test it.
Source
class Livestock:
"""
A class to represent livestock.
Attributes:
species (str): The species of the livestock.
count (int): The number of animals.
"""
def __init__(self, species: str, count: int):
"""
Initialize a Livestock object.
Args:
species (str): The species of the livestock.
count (int): The number of animals.
"""
self.species = species
self.count = count
def check_status(self) -> str:
"""
Determine the status of the herd based on its size.
Returns:
str: "Small Herd" if count < 5, otherwise "Commercial Herd".
"""
if self.count < 5:
return "Small Herd"
else:
return "Commercial Herd"
def __str__(self) -> str:
"""
Return a string representation of the Livestock object.
Returns:
str: A formatted string containing species and count.
"""
return f"Registered Herd: {self.count} heads of {self.species}"
# Example usage:
my_animals = Livestock("Carabao", 10)
print(my_animals) # Output: Registered Herd: 10 heads of CarabaoRegistered Herd: 10 heads of Carabao