Bài 9.1. Python - Tạo và sử dụng một lớp

Bài 9.1. Python - Tạo và sử dụng một lớp
Bạn có thể mô hình hóa hầu hết mọi thứ bằng cách sử dụng các lớp. Hãy bắt đầu bằng cách viết một lớp đơn giản, Dog
, đại diện cho một con chó - không phải một con chó cụ thể, mà là bất kỳ con chó nào. Chúng ta biết gì về hầu hết các con chó cưng? Chúng đều có tên và tuổi. Chúng ta cũng biết rằng hầu hết các con chó ngồi và lăn tròn. Hai mẩu thông tin đó (tên và tuổi) và hai hành vi đó (ngồi và lăn tròn) sẽ được đưa vào lớp Dog
của chúng ta vì chúng là chung cho hầu hết các con chó. Lớp này sẽ cho Python biết cách tạo một đối tượng đại diện cho một con chó. Sau khi lớp của chúng ta được viết, chúng ta sẽ sử dụng nó để tạo các thể hiện riêng lẻ, mỗi thể hiện đại diện cho một con chó cụ thể.
Tạo lớp Dog
Mỗi thể hiện được tạo từ lớp Dog
sẽ lưu trữ một tên và một tuổi, và chúng ta sẽ cung cấp cho mỗi con chó khả năng sit()
và roll_over()
:
class Dog:
"""Một nỗ lực đơn giản để mô hình hóa một con chó."""
def __init__(self, name, age):
"""Khởi tạo các thuộc tính name và age."""
self.name = name
self.age = age
def sit(self):
"""Mô phỏng một con chó ngồi theo lệnh."""
print(f"{self.name} is now sitting.")
def roll_over(self):
"""Mô phỏng lăn tròn theo lệnh."""
print(f"{self.name} rolled over!")
Có nhiều điều cần chú ý ở đây, nhưng đừng lo lắng. Bạn sẽ thấy cấu trúc này xuyên suốt chương này và có nhiều thời gian để làm quen với nó. Đầu tiên, chúng ta định nghĩa một lớp gọi là Dog
. Theo quy ước, các tên viết hoa đề cập đến các lớp trong Python. Không có dấu ngoặc đơn trong định nghĩa lớp vì chúng ta đang tạo lớp này từ đầu. Sau đó, chúng ta viết một docstring mô tả những gì lớp này làm.
Phương thức __init__()
Một hàm là một phần của một lớp được gọi là phương thức. Mọi thứ bạn đã học về hàm cũng áp dụng cho phương thức; sự khác biệt thực tế duy nhất hiện tại là cách chúng ta sẽ gọi các phương thức. Phương thức __init__()
là một phương thức đặc biệt mà Python tự động chạy bất cứ khi nào chúng ta tạo một thể hiện mới dựa trên lớp Dog
. Phương thức này có hai dấu gạch dưới dẫn đầu và hai dấu gạch dưới kết thúc, một quy ước giúp ngăn các tên phương thức mặc định của Python xung đột với các tên phương thức của bạn. Hãy chắc chắn sử dụng hai dấu gạch dưới ở mỗi bên của __init__()
. Nếu bạn chỉ sử dụng một dấu gạch dưới ở mỗi bên, phương thức sẽ không được gọi tự động khi bạn sử dụng lớp của mình, điều này có thể dẫn đến các lỗi khó xác định.
Chúng ta định nghĩa phương thức __init__()
để có ba tham số: self
, name
, và age
. Tham số self
là bắt buộc trong định nghĩa phương thức, và nó phải đứng đầu tiên, trước các tham số khác. Nó phải được bao gồm trong định nghĩa vì khi Python gọi phương thức này sau này (để tạo một thể hiện của Dog
), lệnh gọi phương thức sẽ tự động truyền đối số self
. Mọi lệnh gọi phương thức liên quan đến một thể hiện tự động truyền self
, là một tham chiếu đến chính thể hiện đó; nó cung cấp cho thể hiện cá nhân quyền truy cập vào các thuộc tính và phương thức trong lớp. Khi chúng ta tạo một thể hiện của Dog
, Python sẽ gọi phương thức __init__()
từ lớp Dog
. Chúng ta sẽ truyền cho Dog()
một tên và một tuổi làm đối số; self
được truyền tự động, vì vậy chúng ta không cần truyền nó. Bất cứ khi nào chúng ta muốn tạo một thể hiện từ lớp Dog
, chúng ta sẽ cung cấp các giá trị cho chỉ hai tham số cuối cùng, name
và age
.
Hai biến được định nghĩa trong thân của phương thức __init__()
đều có tiền tố self
. Bất kỳ biến nào có tiền tố self
đều có sẵn cho mọi phương thức trong lớp, và chúng ta cũng sẽ có thể truy cập các biến này thông qua bất kỳ thể hiện nào được tạo từ lớp. Dòng self.name = name
lấy giá trị liên kết với tham số name
và gán nó cho biến name
, sau đó được gắn vào thể hiện đang được tạo. Quá trình tương tự xảy ra với self.age = age
. Các biến có thể truy cập thông qua các thể hiện như thế này được gọi là thuộc tính.
Lớp Dog
có hai phương thức khác được định nghĩa: sit()
và roll_over()
. Vì các phương thức này không cần thông tin bổ sung để chạy, chúng ta chỉ định nghĩa chúng để có một tham số, self
. Các thể hiện mà chúng ta tạo sau này sẽ có quyền truy cập vào các phương thức này. Nói cách khác, chúng sẽ có thể ngồi và lăn tròn. Hiện tại, sit()
và roll_over()
không làm nhiều. Chúng chỉ đơn giản in ra một thông báo nói rằng con chó đang ngồi hoặc lăn tròn. Nhưng khái niệm này có thể được mở rộng đến các tình huống thực tế: nếu lớp này là một phần của một trò chơi máy tính, các phương thức này sẽ chứa mã để làm cho một con chó hoạt hình ngồi và lăn tròn. Nếu lớp này được viết để điều khiển một robot, các phương thức này sẽ điều khiển các chuyển động khiến một con chó robot ngồi và lăn tròn.
Tạo một thể hiện từ một lớp
Hãy nghĩ về một lớp như một tập hợp các hướng dẫn về cách tạo một thể hiện. Lớp Dog
là một tập hợp các hướng dẫn cho Python về cách tạo các thể hiện riêng lẻ đại diện cho các con chó cụ thể.
Hãy tạo một thể hiện đại diện cho một con chó cụ thể:
class Dog:
"""Một nỗ lực đơn giản để mô hình hóa một con chó."""
def __init__(self, name, age):
"""Khởi tạo các thuộc tính name và age."""
self.name = name
self.age = age
def sit(self):
"""Mô phỏng một con chó ngồi theo lệnh."""
print(f"{self.name} is now sitting.")
def roll_over(self):
"""Mô phỏng lăn tròn theo lệnh."""
print(f"{self.name} rolled over!")
my_dog = Dog('Willie', 6)
print(f"My dog's name is {my_dog.name}.")
print(f"My dog is {my_dog.age} years old.")
Lớp Dog
mà chúng ta đang sử dụng ở đây là lớp mà chúng ta vừa viết trong ví dụ trước. Ở đây, chúng ta yêu cầu Python tạo một con chó có tên là 'Willie' và tuổi là 6. Khi Python đọc dòng này, nó gọi phương thức __init__()
trong Dog
với các đối số 'Willie' và 6. Phương thức __init__()
tạo một thể hiện đại diện cho con chó cụ thể này và đặt các thuộc tính name
và age
bằng các giá trị mà chúng ta đã cung cấp. Python sau đó trả về một thể hiện đại diện cho con chó này. Chúng ta gán thể hiện đó cho biến my_dog
. Quy ước đặt tên rất hữu ích ở đây; chúng ta thường có thể giả định rằng một tên viết hoa như Dog
đề cập đến một lớp, và một tên viết thường như my_dog
đề cập đến một thể hiện đơn lẻ được tạo từ một lớp.
Truy cập các thuộc tính
Để truy cập các thuộc tính của một thể hiện, bạn sử dụng ký hiệu dấu chấm. Chúng ta truy cập giá trị của thuộc tính name
của my_dog
bằng cách viết:
my_dog.name
Ký hiệu dấu chấm được sử dụng thường xuyên trong Python. Cú pháp này cho thấy cách Python tìm giá trị của một thuộc tính. Ở đây, Python nhìn vào thể hiện my_dog
và sau đó tìm thuộc tính name
liên kết với my_dog
. Đây là cùng một thuộc tính được gọi là self.name
trong lớp Dog
. Chúng ta sử dụng cùng một cách tiếp cận để làm việc với thuộc tính age
.
Đầu ra là một tóm tắt về những gì chúng ta biết về my_dog
:
My dog's name is Willie.
My dog is 6 years old.
Gọi các phương thức
Sau khi chúng ta tạo một thể hiện từ lớp Dog
, chúng ta có thể sử dụng ký hiệu dấu chấm để gọi bất kỳ phương thức nào được định nghĩa trong Dog
. Hãy làm cho con chó của chúng ta ngồi và lăn tròn:
class Dog:
"""Một nỗ lực đơn giản để mô hình hóa một con chó."""
def __init__(self, name, age):
"""Khởi tạo các thuộc tính name và age."""
self.name = name
self.age = age
def sit(self):
"""Mô phỏng một con chó ngồi theo lệnh."""
print(f"{self.name} is now sitting.")
def roll_over(self):
"""Mô phỏng lăn tròn theo lệnh."""
print(f"{self.name} rolled over!")
my_dog = Dog('Willie', 6)
my_dog.sit()
my_dog.roll_over()
Để gọi một phương thức, hãy đưa tên của thể hiện (trong trường hợp này là my_dog
) và phương thức bạn muốn gọi, ngăn cách bằng một dấu chấm. Khi Python đọc my_dog.sit()
, nó tìm phương thức sit()
trong lớp Dog
và chạy mã đó. Python diễn giải dòng my_dog.roll_over()
theo cùng một cách.
Bây giờ Willie làm những gì chúng ta yêu cầu anh ta:
Willie is now sitting.
Willie rolled over!
Cú pháp này khá hữu ích. Khi các thuộc tính và phương thức đã được đặt tên mô tả phù hợp như name
, age
, sit()
, và roll_over()
, chúng ta có thể dễ dàng suy ra một khối mã, ngay cả khi chúng ta chưa từng thấy trước đó, dự định làm gì.
Tạo nhiều thể hiện
Bạn có thể tạo bao nhiêu thể hiện từ một lớp tùy thích. Hãy tạo một con chó thứ hai gọi là your_dog
:
class Dog:
"""Một nỗ lực đơn giản để mô hình hóa một con chó."""
def __init__(self, name, age):
"""Khởi tạo các thuộc tính name và age."""
self.name = name
self.age = age
def sit(self):
"""Mô phỏng một con chó ngồi theo lệnh."""
print(f"{self.name} is now sitting.")
def roll_over(self):
"""Mô phỏng lăn tròn theo lệnh."""
print(f"{self.name} rolled over!")
my_dog = Dog('Willie', 6)
your_dog = Dog('Lucy', 3)
print(f"My dog's name is {my_dog.name}.")
print(f"My dog is {my_dog.age} years old.")
my_dog.sit()
print(f"\nYour dog's name is {your_dog.name}.")
print(f"Your dog is {your_dog.age} years old.")
your_dog.sit()
Trong ví dụ này, chúng ta tạo một con chó tên là Willie và một con chó tên là Lucy. Mỗi con chó là một thể hiện riêng biệt với bộ thuộc tính riêng của nó, có khả năng thực hiện cùng một tập hợp các hành động:
My dog's name is Willie.
My dog is 6 years old.
Willie is now sitting.
Your dog's name is Lucy.
Your dog is 3 years old.
Lucy is now sitting.
Ngay cả khi chúng ta sử dụng cùng một tên và tuổi cho con chó thứ hai, Python vẫn sẽ tạo một thể hiện riêng biệt từ lớp Dog
. Bạn có thể tạo bao nhiêu thể hiện từ một lớp tùy thích, miễn là bạn đặt cho mỗi thể hiện một tên biến duy nhất hoặc nó chiếm một vị trí duy nhất trong một danh sách hoặc từ điển.
Comments