Các khái niệm về Python OOP
Category: Python
Lập trình hướng đối tượng là một khái niệm cơ bản trong Python, trao quyền cho các nhà phát triển xây dựng các ứng dụng theo mô-đun, có thể bảo trì và có thể mở rộng. Bằng cách hiểu các nguyên tắc cốt lõi của OOP (lớp, đối tượng, kế thừa, đóng gói, đa hình và trừu tượng), các lập trình viên có thể tận dụng toàn bộ tiềm năng của các khả năng OOP của Python để thiết kế các giải pháp thanh lịch và hiệu quả cho các vấn đề phức tạp.
OOP là một cách tổ chức mã sử dụng các đối tượng và lớp để biểu diễn các thực thể trong thế giới thực và hành vi của chúng. Trong OOP, đối tượng có các thuộc tính có dữ liệu cụ thể và có thể thực hiện các hành động nhất định bằng các phương thức.
Các khái niệm OOP trong Python
Lớp trong Python
Đối tượng trong Python
Đa hình trong Python
Đóng gói trong Python
Kế thừa trong Python
Trừu tượng hóa dữ liệu trong Python
Lớp Python
Một lớp là một tập hợp các đối tượng. Các lớp là bản thiết kế để tạo ra các đối tượng. Một lớp định nghĩa một tập hợp các thuộc tính và phương thức mà các đối tượng được tạo ra (thể hiện) có thể có.
Một số điểm về lớp Python:
Các lớp được tạo bằng từ khóa class.
Thuộc tính là các biến thuộc về một lớp.
Thuộc tính luôn công khai và có thể được truy cập bằng toán tử dấu chấm (.). Ví dụ: Myclass.Myattribute
Tạo một lớp học
Ở đây, từ khóa class cho biết chúng ta đang tạo một lớp theo sau là tên lớp (trong trường hợp này là Dog).
class Dog:
species = "Canine" # Thuộc tính lớp
def __init__(self, name, age):
self.name = name # Thuộc tính thể hiện
self.age = age # Thuộc tính thể hiện
Giải thích:
lớp Dog: Định nghĩa một lớp có tên là Dog.
loài: Thuộc tính lớp được chia sẻ bởi tất cả các thể hiện của lớp.
Phương thức init: Khởi tạo các thuộc tính name và age khi một đối tượng mới được tạo.
Đối tượng Python
Đối tượng là một thể hiện của Lớp. Nó đại diện cho một triển khai cụ thể của lớp và chứa dữ liệu riêng của nó.
Một đối tượng bao gồm:
Trạng thái: Được biểu thị bằng các thuộc tính và phản ánh các đặc tính của một đối tượng.
Hành vi: Được biểu diễn bằng các phương thức của một đối tượng và phản ánh phản ứng của một đối tượng đối với các đối tượng khác.
Nhận dạng: Cung cấp tên duy nhất cho một đối tượng và cho phép một đối tượng tương tác với các đối tượng khác.
Tạo đối tượng
Việc tạo một đối tượng trong Python liên quan đến việc khởi tạo một lớp để tạo một thể hiện mới của lớp đó. Quá trình này cũng được gọi là khởi tạo đối tượng.
class Dog:
species = "Canine" # thuộc tính lớp
def __init__(self, name, age):
self.name = name # Thuộc tính thể hiện
self.age = age # Thuộc tính thể hiện
# Tạo một đối tượng của lớp Dog
dog1 = Dog("Buddy", 3)
print(dog1.name)
print(dog1.species)
Đầu ra:
Buddy
Canine
Giải thích:
dog1 = Dog("Buddy", 3): Tạo một đối tượng của lớp Dog với tên là "Buddy" và tuổi là 3.
dog1.name: Truy cập tên thuộc tính thể hiện của đối tượng dog1.
dog1.species: Truy cập thuộc tính lớp species của đối tượng dog1.
Tham số Self
tham số self là tham chiếu đến thể hiện hiện tại của lớp. Nó cho phép chúng ta truy cập các thuộc tính và phương thức của đối tượng.
class Dog:
species = "Canine" # Thuộc tính lớp
def __init__(self, name, age):
self.name = name # Thuộc tính thể hiện (instance)
self.age = age # Thuộc tính thể hiện (instance)
dog1 = Dog("Buddy", 3) # Tạo một đối tượng Dog
dog2 = Dog("Charlie", 5) # Tạo một đối tượng Dog khác
print(dog1.name, dog1.age, dog1.species) # Truy cập thuộc tính thể hiện và lớp
print(dog2.name, dog2.age, dog2.species) # Truy cập thuộc tính thể hiện và lớp
print(Dog.species) # Truy cập trực tiếp thuộc tính lớp
Đầu ra:
Buddy 3 Canine
Charlie 5 Canine
Canine
Giải thích:
self.name: Chỉ đến thuộc tính name của đối tượng (dog1) gọi phương thức.
dog1.bark(): Gọi phương thức bark trên dog1.
Phương pháp init
Phương thức init là hàm tạo trong Python, được gọi tự động khi một đối tượng mới được tạo. Nó khởi tạo các thuộc tính của lớp.
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
dog1 = Dog("Buddy", 3)
print(dog1.name)
Đầu ra:
Buddy
Giải thích:
init: Phương thức đặc biệt dùng để khởi tạo.
self.name và self.age: Thuộc tính thể hiện được khởi tạo trong hàm tạo.
Biến lớp và biến thể hiện
Trong Python, các biến được định nghĩa trong một lớp có thể là biến lớp hoặc biến thể hiện và việc hiểu được sự khác biệt giữa chúng rất quan trọng đối với lập trình hướng đối tượng.
Biến lớp
Đây là các biến được chia sẻ trên tất cả các thể hiện của một lớp. Nó được định nghĩa ở cấp độ lớp, bên ngoài bất kỳ phương thức nào. Tất cả các đối tượng của lớp chia sẻ cùng một giá trị cho một biến lớp trừ khi được ghi đè rõ ràng trong một đối tượng.
Biến thể hiện
Các biến duy nhất cho mỗi thể hiện (đối tượng) của một lớp. Các biến này được định nghĩa trong phương thức init hoặc các phương thức thể hiện khác. Mỗi đối tượng duy trì bản sao riêng của các biến thể hiện, độc lập với các đối tượng khác.
class Dog:
# Biến lớp (class variable)
species = "Canine"
def __init__(self, name, age):
# Biến đối tượng (instance variables)
self.name = name
self.age = age
# Tạo các đối tượng
dog1 = Dog("Buddy", 3)
dog2 = Dog("Charlie", 5)
# Truy cập biến lớp và biến đối tượng
print(dog1.species) # => Canine
print(dog1.name) # => Buddy
print(dog2.name) # => Charlie
# Thay đổi biến đối tượng
dog1.name = "Max"
print(dog1.name) # => Max
# Thay đổi biến lớp
Dog.species = "Feline"
print(dog1.species) # => Feline
print(dog2.species) # => Feline
Đầu ra:
Canine
Buddy
Charlie
Max
Feline
Feline
Giải thích:
Biến lớp (species): Được chia sẻ bởi tất cả các thể hiện của lớp. Thay đổi Dog.species ảnh hưởng đến tất cả các đối tượng vì đây là thuộc tính của chính lớp đó.
Biến thể hiện (tên, tuổi): Được định nghĩa trong phương thức init. Duy nhất cho mỗi thể hiện (ví dụ: dog1.name và dog2.name khác nhau).
Truy cập Biến: Biến lớp có thể được truy cập thông qua tên lớp (Dog.species) hoặc đối tượng (dog1.species). Biến thể hiện được truy cập thông qua đối tượng (dog1.name).
Cập nhật biến: Thay đổi Dog.species ảnh hưởng đến tất cả các trường hợp. Thay đổi dog1.name chỉ ảnh hưởng đến dog1 và không ảnh hưởng đến dog2.
Kế thừa Python
Kế thừa cho phép một lớp (lớp con) có được các thuộc tính và phương thức của một lớp khác (lớp cha). Nó hỗ trợ phân loại theo thứ bậc và thúc đẩy việc tái sử dụng mã.
Các loại thừa kế:
Kế thừa đơn: Một lớp con kế thừa từ một lớp cha duy nhất.
Kế thừa đa lớp: Một lớp con kế thừa từ nhiều lớp cha.
Kế thừa đa cấp: Lớp con kế thừa từ lớp cha, rồi lớp cha lại kế thừa từ lớp khác.
Kế thừa theo thứ bậc: Nhiều lớp con kế thừa từ một lớp cha duy nhất.
Kế thừa lai: Sự kết hợp của hai hoặc nhiều loại kế thừa.
# Kế thừa đơn (Single Inheritance)
class Dog:
def __init__(self, name):
self.name = name
def display_name(self):
print(f"Dog's Name: {self.name}")
class Labrador(Dog): # Kế thừa đơn
def sound(self):
print("Labrador woofs")
# Kế thừa đa cấp (Multilevel Inheritance)
class GuideDog(Labrador): # Kế thừa đa cấp
def guide(self):
print(f"{self.name}Guides the way!")
# Kế thừa đa hình / nhiều lớp (Multiple Inheritance)
class Friendly:
def greet(self):
print("Friendly!")
class GoldenRetriever(Dog, Friendly): # Kế thừa nhiều lớp
def sound(self):
print("Golden Retriever Barks")
# Ví dụ sử dụng
lab = Labrador("Buddy")
lab.display_name()
lab.sound()
guide_dog = GuideDog("Max")
guide_dog.display_name()
guide_dog.guide()
retriever = GoldenRetriever("Charlie")
retriever.display_name()
retriever.greet()
retriever.sound()
Giải thích:
Kế thừa đơn: Labrador kế thừa các thuộc tính và phương thức của Dog.
Kế thừa đa cấp: GuideDog mở rộng Labrador, kế thừa cả chức năng của Dog và Labrador.
Kế thừa đa dạng: GoldenRetriever kế thừa từ cả Dog và Friendly.
Đa hình Python
Đa hình cho phép các phương thức có cùng tên nhưng hoạt động khác nhau tùy theo ngữ cảnh của đối tượng. Có thể đạt được điều này thông qua ghi đè hoặc nạp chồng phương thức.
Các loại đa hình
Đa hình thời gian biên dịch : Loại đa hình này được xác định trong quá trình biên dịch chương trình. Nó cho phép các phương thức hoặc toán tử có cùng tên hoạt động khác nhau dựa trên các tham số đầu vào hoặc cách sử dụng của chúng. Nó thường được gọi là phương thức hoặc toán tử quá tải.
Đa hình thời gian chạy : Loại đa hình này được xác định trong quá trình thực thi chương trình. Nó xảy ra khi một lớp con cung cấp một triển khai cụ thể cho một phương thức đã được định nghĩa trong lớp cha của nó, thường được gọi là ghi đè phương thức.
Ví dụ mã:
# Lớp cha (Parent Class)
class Dog:
def sound(self):
print("dog sound") # Cài đặt mặc định
# Đa hình lúc chạy (Run-Time Polymorphism): Ghi đè phương thức
class Labrador(Dog):
def sound(self):
print("Labrador woofs") # Ghi đè phương thức của lớp cha
class Beagle(Dog):
def sound(self):
print("Beagle Barks") # Ghi đè phương thức của lớp cha
# Đa hình lúc biên dịch (Compile-Time Polymorphism): Bắt chước nạp chồng phương thức
class Calculator:
def add(self, a, b=0, c=0):
return a + b + c # Hỗ trợ nhiều cách gọi hàm add()
# Đa hình lúc chạy (Run-Time Polymorphism)
dogs = [Dog(), Labrador(), Beagle()]
for dog in dogs:
dog.sound() # Gọi phương thức phù hợp dựa trên loại đối tượng
# Đa hình lúc biên dịch (Mô phỏng bằng đối số mặc định)
calc = Calculator()
print(calc.add(5, 10)) # Hai đối số
print(calc.add(5, 10, 15)) # Ba đối số
Giải thích:
1. Đa hình thời gian chạy:
Được chứng minh bằng cách ghi đè phương thức trong lớp Dog và các lớp con của nó (Labrador và Beagle).
Phương thức âm thanh chính xác được gọi khi chạy dựa trên loại đối tượng thực tế trong danh sách.
2. Đa hình thời gian biên dịch:
Python không hỗ trợ phương thức nạp chồng. Thay vào đó, chúng tôi sử dụng một phương thức duy nhất (add) với các đối số mặc định để xử lý số lượng tham số khác nhau.
Các hành vi khác nhau (cộng hai hoặc ba số) đạt được tùy thuộc vào cách gọi phương thức.
Đóng gói Python
Đóng gói là việc đóng gói dữ liệu (thuộc tính) và phương thức (hàm) trong một lớp, hạn chế quyền truy cập vào một số thành phần để kiểm soát tương tác.
Lớp là một ví dụ về đóng gói vì nó đóng gói tất cả dữ liệu là các hàm thành viên, biến, v.v.
Các loại đóng gói:
Thành viên công khai : Có thể truy cập từ mọi nơi.
Thành viên được bảo vệ : Có thể truy cập trong lớp và các lớp con của nó.
Thành viên riêng tư : Chỉ có thể truy cập trong lớp.
Ví dụ mã:
class Dog:
def __init__(self, name, breed, age):
self.name = name # Thuộc tính công khai (Public)
self._breed = breed # Thuộc tính được bảo vệ (Protected)
self.__age = age # Thuộc tính riêng tư (Private)
# Phương thức công khai
def get_info(self):
return f"Name: {self.name}, Breed: {self._breed}, Age: {self.__age}"
# Getter và Setter cho thuộc tính riêng tư
def get_age(self):
return self.__age
def set_age(self, age):
if age > 0:
self.__age = age
else:
print("Invalid age!")
# Ví dụ sử dụng
dog = Dog("Buddy", "Labrador", 3)
# Truy cập thành viên công khai
print(dog.name) # Có thể truy cập
# Truy cập thành viên được bảo vệ
print(dog._breed) # Có thể truy cập nhưng không khuyến khích từ bên ngoài lớp
# Truy cập thành viên riêng tư thông qua getter
print(dog.get_age())
# Thay đổi thành viên riêng tư thông qua setter
dog.set_age(5)
print(dog.get_info())
Giải thích:
Thành viên công khai: Dễ dàng truy cập, chẳng hạn như tên.
Thành viên được bảo vệ : Được sử dụng với một duy nhất, chẳng hạn như breed. Không khuyến khích truy cập nhưng được phép trong các lớp con.
Thành viên riêng tư: Được sử dụng với , chẳng hạn như age. Access yêu cầu phương thức getter và setter .
Trừu tượng dữ liệu
Abstraction ẩn các chi tiết triển khai bên trong trong khi chỉ hiển thị chức năng cần thiết. Nó giúp tập trung vào "cần làm gì" thay vì "làm như thế nào".
Các loại trừu tượng:
Trừu tượng một phần: Lớp trừu tượng chứa cả phương thức trừu tượng và cụ thể.
Trừu tượng hoàn toàn: Lớp trừu tượng chỉ chứa các phương thức trừu tượng (như giao diện).
Ví dụ mã:
from abc import ABC, abstractmethod
class Dog(ABC): # Lớp trừu tượng
def __init__(self, name):
self.name = name
@abstractmethod
def sound(self): # Phương thức trừu tượng
pass
def display_name(self): # Phương thức cụ thể
print(f"Dog's Name: {self.name}")
class Labrador(Dog): # Trừu tượng một phần
def sound(self):
print("Labrador Woof!")
class Beagle(Dog): # Trừu tượng một phần
def sound(self):
print("Beagle Bark!")
# Ví dụ sử dụng
dogs = [Labrador("Buddy"), Beagle("Charlie")]
for dog in dogs:
dog.display_name() # Gọi phương thức cụ thể
dog.sound() # Gọi phương thức trừu tượng đã được cài đặt
Giải thích:
Trừu tượng một phần : Dog Lớp này có cả phương thức trừu tượng ( sound) và cụ thể ( display_name).
Tại sao sử dụng : Tính trừu tượng đảm bảo tính nhất quán trong các lớp dẫn xuất bằng cách áp dụng các phương thức trừu tượng.
Published on Jun 19, 2025