Basic Object-Oriented Programming Concepts
Python is a programming language that adopts the object-oriented programming or OOP paradigm. One of Python's fundamental principles is that everything is an object. This concept might sound abstract at first, but it's actually very natural and similar to how we view the real world.
Imagine the world around us. All objects have characteristics and can do something. A car has color, brand, and speed, and can move, stop, and honk its horn. Similarly in Python, every data and function is an object that has attributes and can perform certain actions.
Programming Paradigm Comparison
Procedural Languages
In procedural programming languages, state and actions are separated. Data and functions that operate on that data are separate from each other.
// Example of procedural approach in C languagestruct ParkSystem { int max; int occ;};int occupy(struct ParkSystem* ps) { if (ps->max <= ps->occ) { return -1; } ps->occ++; return 0;}void leave(struct ParkSystem* ps) { if (ps->occ > 0) { ps->occ--; }}int main() { struct ParkSystem ps = {100, 0}; occupy(&ps); printf("%d %d", ps.max, ps.occ); return 0;}
In the procedural approach, you can see that data (struct) and functions are separate. Functions accept data as parameters and modify them from outside.
Object-Oriented Languages
In object-oriented programming languages, state and actions are combined into one unit called a class. Attributes describe state, while methods describe actions that can be performed on that state.
# Example of object-oriented approach in Pythonclass ParkSystem: def __init__(self, max_capacity): self.max = max_capacity self.occ = 0 def occupy(self): if self.max <= self.occ: return -1 self.occ += 1 return 0 def leave(self): if self.occ > 0: self.occ -= 1# Usageps = ParkSystem(100)ps.occupy()print(f"Max: {ps.max}, Occupied: {ps.occ}")
In the object-oriented approach, data and functions that operate on that data are packaged in one unit. Objects have the responsibility to manage their own state.
Parking System as an Analogy
Let's use a parking system as an example to understand the concept of objects. In the real world, a parking system has characteristics like maximum capacity and number of occupied spaces. This system can also perform actions like accepting cars entering or leaving.
class ParkingSystem: def __init__(self, capacity): """Initialize parking system with certain capacity""" self.capacity = capacity self.occupied = 0 self.vehicles = [] # List of parked vehicles def park_vehicle(self, vehicle_plate): """Method to park a vehicle""" if self.occupied >= self.capacity: return f"Parking full! Cannot park {vehicle_plate}" self.vehicles.append(vehicle_plate) self.occupied += 1 return f"Vehicle {vehicle_plate} successfully parked" def exit_vehicle(self, vehicle_plate): """Method to exit parking""" if vehicle_plate in self.vehicles: self.vehicles.remove(vehicle_plate) self.occupied -= 1 return f"Vehicle {vehicle_plate} exited parking" else: return f"Vehicle {vehicle_plate} not found" def get_status(self): """Method to view parking status""" available = self.capacity - self.occupied return { 'capacity': self.capacity, 'occupied': self.occupied, 'available': available, 'vehicles': self.vehicles } def is_full(self): """Method to check if parking is full""" return self.occupied >= self.capacity# Example usageparking = ParkingSystem(5)print(parking.park_vehicle("B 1234 CD"))print(parking.park_vehicle("B 5678 EF"))print(parking.get_status())print(parking.is_full())
Object Concepts in Data Types
In Python, the concept of "everything is an object" means every data you create has attributes and methods. Let's explore this concept deeper.
Numbers are Objects
# Numbers in Python are objectsnumber = 42# Numbers have methodsprint(number.bit_length()) # Method to calculate bit lengthprint(number.__add__(8)) # Method for addition (same as number + 8)# Float numbers are also objectsprice = 15.75print(price.is_integer()) # Method to check if it's a whole numberprint(price.as_integer_ratio()) # Method to convert to ratio# Even mathematical operation results are objectsresult = 10 + 5print(type(result)) # <class 'int'>print(dir(result)) # View all available methods
Strings are Objects
# Strings in Python are very powerful objectsmessage = "Learning Python is Fun"# Strings have many useful methodsprint(message.upper()) # LEARNING PYTHON IS FUNprint(message.lower()) # learning python is funprint(message.title()) # Learning Python Is Funprint(message.count('n')) # Count letter 'n'print(message.replace('Python', 'Programming')) # Replace word# Methods for checkingemail = "user@example.com"print(email.endswith('.com')) # Trueprint(email.startswith('user')) # Trueprint(email.find('@')) # Position of '@' character# Methods for formattingname = "alice"age = 25formatted = "Name: {}, Age: {}".format(name.title(), age)print(formatted)# String split and joinwords = message.split() # Split into word listprint(words)rejoined = " ".join(words) # Join back togetherprint(rejoined)
Lists are Objects
# Lists in Python are dynamic objectsfruits = ["apple", "orange", "mango"]# Lists have methods for data manipulationfruits.append("banana") # Add at the endprint(fruits)fruits.insert(1, "strawberry") # Add at specific positionprint(fruits)fruits.remove("orange") # Remove specific itemprint(fruits)# Methods for searching and sortingnumbers = [3, 1, 4, 1, 5, 9, 2, 6]print(numbers.count(1)) # Count occurrencesprint(numbers.index(4)) # Find positionnumbers.sort() # Sortprint(numbers)numbers.reverse() # Reverse orderprint(numbers)# List comprehension - pythonic waysquares = [x**2 for x in range(1, 6)]print(squares) # [1, 4, 9, 16, 25]# Methods for advanced operationsoriginal = [1, 2, 3]copy_list = original.copy() # Create copyoriginal.extend([4, 5]) # Add multiple itemsprint(f"Original: {original}")print(f"Copy: {copy_list}")
Dictionaries are Objects
# Dictionaries in Python are flexible objectsstudent = { "name": "Alice", "age": 22, "major": "Computer Science", "gpa": 3.8}# Dictionaries have methods for manipulationprint(student.get("name")) # Get value safelyprint(student.get("height", "Unknown")) # Default value if key doesn't exist# Methods to view dictionary contentsprint(student.keys()) # All keysprint(student.values()) # All valuesprint(student.items()) # Key-value pairs# Methods for update and manipulationstudent.update({"semester": 6, "age": 23}) # Update multiple valuesprint(student)# Pop method to get and removegpa = student.pop("gpa")print(f"Removed GPA: {gpa}")print(student)# Dictionary comprehensiongrades = {"Math": 85, "Physics": 92, "Chemistry": 78}passed = {subject: grade for subject, grade in grades.items() if grade >= 80}print(passed)# Nested dictionaryuniversity = { "students": { "CS": ["Alice", "Bob"], "Math": ["Charlie", "Diana"] }, "location": "Jakarta"}print(university["students"]["CS"])
Functions are Also Objects
One interesting thing about Python is that functions are also objects. This allows you to treat functions like regular data.
# Functions in Python are first-class objectsdef greet(name): return f"Hello, {name}!"def farewell(name): return f"Goodbye, {name}!"# Functions have attributesprint(greet.__name__) # Function nameprint(type(greet)) # <class 'function'># Functions can be stored in variablesmy_function = greetprint(my_function("Alice")) # Hello, Alice!# Functions can be stored in listsfunctions = [greet, farewell]for func in functions: print(func("Bob"))# Functions can be used as parametersdef call_function(func, name): return func(name)result = call_function(greet, "Charlie")print(result)# Functions can be returned from other functionsdef get_greeting_function(language): def english_greet(name): return f"Hello, {name}!" def indonesian_greet(name): return f"Halo, {name}!" if language == "english": return english_greet else: return indonesian_greet# Using returned functiongreet_func = get_greeting_function("indonesian")print(greet_func("Diana")) # Halo, Diana!# Lambda functions are also objectssquare = lambda x: x ** 2print(type(square)) # <class 'function'>print(square(5)) # 25
Classes and Instances as Objects
A class is a blueprint for creating objects, while an instance is an object created from that class.
# Creating class as blueprintclass Student: # Class attribute (shared by all instances) university = "University of Indonesia" def __init__(self, name, major, semester): # Instance attributes (unique for each instance) self.name = name self.major = major self.semester = semester self.courses = [] def add_course(self, course): """Method to add a course""" self.courses.append(course) return f"{self.name} is taking course {course}" def get_info(self): """Method to get student information""" return { 'name': self.name, 'major': self.major, 'semester': self.semester, 'courses': self.courses, 'university': self.university } def __str__(self): """Special method for string representation""" return f"Student({self.name}, {self.major})" def __len__(self): """Special method to get number of courses""" return len(self.courses)# Creating instances (objects) from classstudent1 = Student("Alice", "Computer Science", 4)student2 = Student("Bob", "Mathematics", 6)# Each instance is an object with attributes and methodsprint(student1.add_course("Python Programming"))print(student1.add_course("Data Structures"))print(student2.add_course("Calculus"))print(student2.add_course("Linear Algebra"))# Using methodsprint(student1.get_info())print(student2.get_info())# Special methods (__str__ and __len__)print(student1) # Student(Alice, Computer Science)print(len(student1)) # 2 (number of courses)# Instances have accessible attributesprint(f"Name: {student1.name}")print(f"Major: {student1.major}")print(f"University: {student1.university}")# Class is also an objectprint(type(Student)) # <class 'type'>print(Student.__name__) # Studentprint(Student.university) # University of Indonesia
Special Methods
Python has special methods that start and end with double underscores. These methods allow your objects to behave like built-in types.
class BankAccount: def __init__(self, owner, balance=0): self.owner = owner self.balance = balance def __str__(self): """Readable string representation""" return f"BankAccount({self.owner}, USD{self.balance:,})" def __repr__(self): """String representation for debugging""" return f"BankAccount('{self.owner}', {self.balance})" def __len__(self): """Return length of owner name""" return len(self.owner) def __eq__(self, other): """Compare two bank accounts""" if isinstance(other, BankAccount): return self.balance == other.balance return False def __lt__(self, other): """Less than comparison""" if isinstance(other, BankAccount): return self.balance < other.balance return False def __add__(self, amount): """Add balance (deposit)""" if isinstance(amount, (int, float)) and amount > 0: self.balance += amount return self def __sub__(self, amount): """Subtract balance (withdraw)""" if isinstance(amount, (int, float)) and amount > 0: if amount <= self.balance: self.balance -= amount else: print("Insufficient balance!") return self def __bool__(self): """True if has balance, False if balance is 0""" return self.balance > 0# Creating objectsaccount1 = BankAccount("Alice", 1000000)account2 = BankAccount("Bob", 500000)# Magic methods in actionprint(account1) # __str__print(repr(account1)) # __repr__print(len(account1)) # __len__ (name length)# Comparisonprint(account1 == account2) # __eq__print(account1 > account2) # __lt__ (reversed)# Arithmetic operationsaccount1 + 500000 # __add__ (deposit)print(account1)account1 - 200000 # __sub__ (withdraw)print(account1)# Boolean conversionempty_account = BankAccount("Charlie", 0)print(bool(account1)) # Trueprint(bool(empty_account)) # False# Using in conditionalsif account1: print(f"{account1.owner} has balance")else: print(f"{account1.owner} has no balance")
Object-Oriented Programming Practice
Let's create a more complex example to understand how OOP is applied in real scenarios.
class Book: def __init__(self, title, author, isbn): self.title = title self.author = author self.isbn = isbn self.is_borrowed = False self.borrower = None def __str__(self): status = "Borrowed" if self.is_borrowed else "Available" return f"{self.title} by {self.author} - {status}"class Member: def __init__(self, name, member_id): self.name = name self.member_id = member_id self.borrowed_books = [] def __str__(self): return f"Member: {self.name} (ID: {self.member_id})"class Library: def __init__(self, name): self.name = name self.books = [] self.members = [] def add_book(self, book): """Add book to library""" self.books.append(book) return f"Book '{book.title}' successfully added" def register_member(self, member): """Register new member""" self.members.append(member) return f"Member {member.name} successfully registered" def borrow_book(self, member_id, isbn): """Borrow book""" # Find member member = None for m in self.members: if m.member_id == member_id: member = m break if not member: return "Member not found" # Find book book = None for b in self.books: if b.isbn == isbn and not b.is_borrowed: book = b break if not book: return "Book not available" # Process borrowing book.is_borrowed = True book.borrower = member member.borrowed_books.append(book) return f"{member.name} successfully borrowed '{book.title}'" def return_book(self, member_id, isbn): """Return book""" member = None for m in self.members: if m.member_id == member_id: member = m break if not member: return "Member not found" book = None for b in member.borrowed_books: if b.isbn == isbn: book = b break if not book: return "Book not found in borrowed list" # Process return book.is_borrowed = False book.borrower = None member.borrowed_books.remove(book) return f"{member.name} successfully returned '{book.title}'" def get_available_books(self): """Get list of available books""" available = [book for book in self.books if not book.is_borrowed] return available def get_member_books(self, member_id): """Get list of books borrowed by member""" for member in self.members: if member.member_id == member_id: return member.borrowed_books return []# Example usage of library systemlibrary = Library("Central Library")# Adding booksbook1 = Book("Python Programming", "John Smith", "978-1234567890")book2 = Book("Data Science Basics", "Jane Doe", "978-0987654321")book3 = Book("Machine Learning", "Bob Johnson", "978-1122334455")print(library.add_book(book1))print(library.add_book(book2))print(library.add_book(book3))# Registering membersmember1 = Member("Alice Cooper", "M001")member2 = Member("Bob Wilson", "M002")print(library.register_member(member1))print(library.register_member(member2))# Borrowing booksprint(library.borrow_book("M001", "978-1234567890"))print(library.borrow_book("M002", "978-0987654321"))# Viewing book statusprint("List of all books:")for book in library.books: print(book)print("Available books:")for book in library.get_available_books(): print(book)print(f"Books borrowed by Alice: {len(library.get_member_books('M001'))} books")# Returning booksprint(library.return_book("M001", "978-1234567890"))
By understanding the concept that everything is an object in Python, you can write code that is more structured, easier to understand, and easier to maintain. Object-oriented programming allows you to model real-world problems into code in a natural and intuitive way.