Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Python

Kế thừa trong Python: Hướng dẫn từng bước

Kế thừa trong Python là khi một lớp con sử dụng mã từ một lớp khác. Kế thừa là một tính năng thiết yếu trong các ngôn ngữ hướng đối tượng như Python, giúp viết mã dễ dàng và hiệu quả hơn.


Python là một ngôn ngữ hướng đối tượng, nghĩa là nó hỗ trợ tạo các khối mã có thể tái sử dụng để giúp mã hiệu quả hơn. Một trong những cách thực hiện điều này là thông qua kế thừa, nơi một lớp con có thể sử dụng mã từ một lớp cha.

Ví dụ, bạn có thể có một lớp lưu trữ "tài khoản ngân hàng", và muốn tạo một lớp con lưu trữ "tài khoản ngân hàng vàng" có thể tham chiếu các thuộc tính trong lớp "tài khoản ngân hàng" hiện có.

Trong hướng dẫn này, chúng ta sẽ phân tích các kiến thức cơ bản về kế thừa trong Python. Chúng ta cũng sẽ thảo luận về cách các lớp cha và lớp con trong Python hoạt động, cũng như cách ghi đè thuộc tính và phương thức khi làm việc với các đối tượng lớp.

Kế thừa trong Python

Kế thừa là thuật ngữ dùng để mô tả một lớp Python bên trong một lớp khác. Các lớp gọi là lớp con hoặc lớp dẫn xuất có thể kế thừa giá trị từ lớp cha, tương tự như cách con cái kế thừa đặc điểm từ cha mẹ trong đời thực.

Kế thừa rất hữu ích vì nó cho phép chúng ta tạo các lớp con có cùng kiểu giá trị với lớp cha, mà không cần khai báo những kiểu đó nhiều lần.

Lớp cha (Base Classes)

Lớp cha (còn gọi là lớp cơ sở) tạo ra cấu trúc chính mà các lớp con có thể truy cập. Chúng ta có thể tạo nhiều lớp con mà không cần khai báo lại cùng một tập hợp các giá trị chung mà các phương thức lớp dẫn xuất kế thừa từ lớp cha.

Hãy sử dụng một ví dụ để minh họa cách thức hoạt động. Giả sử chúng ta có một chương trình làm việc với hai loại tài khoản ngân hàng khác nhau: tài khoản cha và tài khoản con.

81% người tham gia cho biết họ cảm thấy tự tin hơn về cơ hội việc làm công nghệ sau khi tham gia bootcamp. Được ghép nối với bootcamp ngay hôm nay.

Sinh viên trung bình tốt nghiệp bootcamp mất chưa đến sáu tháng để chuyển đổi nghề nghiệp, từ khi bắt đầu bootcamp đến khi tìm được việc đầu tiên.

Cả hai tài khoản này đều là tài khoản ngân hàng, do đó chúng sẽ có các giá trị tương tự. Nhưng mỗi loại tài khoản có thể yêu cầu thông tin riêng. Ví dụ, tài khoản của cha mẹ có thể hỗ trợ thấu chi, trong khi tài khoản của trẻ em chỉ hoạt động với số dư của họ.

Vì vậy, nếu chúng ta muốn tạo một chương trình với các giá trị này, trước tiên chúng ta sẽ định nghĩa một lớp cho tài khoản ngân hàng (lớp cha), sau đó tạo các lớp con cho hai loại tài khoản ngân hàng—cha và con—mà chúng ta muốn hỗ trợ.

Dưới đây là ví dụ về khai báo lớp cha cho tài khoản ngân hàng:

class BankAccount: def __init__(self, forename, surname, balance): self.forename = forename self.surname = surname self.balance = balance

Chúng ta đã tạo lớp BankAccount lưu trữ ba giá trị: tên, họ và số dư. Chúng ta cũng có thể thêm phương thức vào lớp, như sau:

class BankAccount: def __init__(self, forename, surname, balance): self.forename = forename self.surname = surname self.balance = balance def getDetails(self): print("Forename: ", self.forename) print("Surname: ", self.surname) def getBalance(self): print("Balance: $ ", self.balance)

Lớp của chúng ta giờ lưu trữ ba giá trị, cũng như hai phương thức mới: details và balance. Phương thức details có thể dùng để tìm tên và họ của chủ tài khoản, và phương thức balance sẽ trả về số dư của chủ tài khoản.

Mọi phương thức và biến mà chúng ta khai báo trong lớp BankAccount đều sẽ có thể truy cập trong lớp con của chúng ta.

Để minh họa lớp hoạt động, hãy tạo một tài khoản ngân hàng ví dụ. Chúng ta có thể làm như sau:

account = BankAccount("John", "Appleseed", 100)

Điều này sẽ tạo một tài khoản cho John Appleseed chứa $100. Bây giờ chúng ta đã sẵn sàng tài khoản, có thể bắt đầu tham chiếu nó như bất kỳ lớp nào khác. Dưới đây là ví dụ chạy phương thức getBalance() trong tài khoản ngân hàng để biết số tiền:

print(account.getBalance())

Chương trình trả về kết quả sau:

Balance: $ 100

Lớp con (Child Classes)

Trong ví dụ trên, chúng ta đã khai báo một lớp cha lưu trữ tài khoản ngân hàng. Nhưng nếu chúng ta muốn lưu trữ thông tin về một loại tài khoản cụ thể như tài khoản dưới 18 tuổi của trẻ em? Đó là lúc lớp con xuất hiện.

Lớp con, hoặc lớp dẫn xuất, kế thừa giá trị từ lớp cha. Điều này có nghĩa là mỗi lớp con sẽ có thể tham chiếu các phương thức và biến mà chúng ta khai báo trong lớp cha.

Vì vậy, giả sử chúng ta muốn tạo một lớp con cho ChildBankAccount. Tài khoản này nên có thể trả về thông tin tài khoản ngân hàng của người dùng—tên và số dư—và cũng nên có một giá trị mới gọi là restricted. Giá trị này sẽ được lưu trên tài khoản của trẻ em vì họ dưới 18 tuổi, và không đủ điều kiện cho tài khoản ngân hàng đầy đủ.

Để tạo một lớp con, chúng ta có thể dùng mã sau:

class ChildBankAccount(BankAccount):

Lớp ChildBankAccount trở thành lớp con của BankAccount vì BankAccount được đặt trong dấu ngoặc đơn. Nếu chúng ta muốn lớp con có chính xác các giá trị giống lớp cha—BankAccount—chúng ta có thể dùng từ khóa pass như sau:

class ChildBankAccount(BankAccount): pass

Nhưng như đã thảo luận, tài khoản con sẽ cần lưu một giá trị đặc biệt: một biến cho biết tài khoản của người dùng bị hạn chế.

Để đạt được mục tiêu này, chúng ta sẽ thêm một giá trị mới gọi là restricted vào lớp con. Chúng ta có thể làm như sau:

class ChildBankAccount(BankAccount): def __init__(self, forename, surname, balance, restricted=True): self.forename = forename self.surname = surname self.balance = balance self.restricted = restricted def isRestricted(self): print("This account is restricted as the user is under 18.")

Hãy phân tích mã của chúng ta.

Trong mã trên, chúng ta nói rằng ChildBankAccounts sẽ giữ bốn giá trị: forename, surname, balance và restricted.

Ba giá trị đầu tiên—forename, surname và balance—giống với giá trị lớp cha nhưng restricted là mới, và nó độc quyền cho lớp con. Mặc định, restricted được đặt là True.

Vì vậy, nếu chúng ta tạo một BankAccount tiêu chuẩn (không phải ChildBankAccount), chúng ta sẽ không thể truy cập giá trị restricted. Tương tự, chúng ta không thể truy cập phương thức isRestricted trừ khi tạo một ChildBankAccount.

Dưới đây là ví dụ tạo ChildBankAccount và sử dụng phương thức getBalance() và isRestricted() để tìm hiểu thêm về lớp:

child_account = ChildBankAccount("Bill", "Appleseed", 100) print(child_account.getBalance()) print(child_account.isRestricted())

Mã trả về kết quả sau:

Balance: $ 100 This account is restricted as the user is under 18.

Như bạn thấy, chương trình đầu tiên định nghĩa một ChildBankAccount mới cho Bill Appleseed, tài khoản có $100. Sau đó, chương trình thực thi phương thức getBalance() trong lớp, trả về số dư của người dùng. getBalance() được khai báo trong lớp cha, BankAccount, nhưng có thể truy cập được bởi ChildBankAccount nhờ kế thừa.

Chương trình cũng thực thi phương thức isRestricted(), cho biết tài khoản của trẻ em bị hạn chế vì dưới 18 tuổi. Lớp này được khai báo trong ChildBankAccount, nghĩa là nó không thể truy cập từ lớp cha BankAccount. Nếu muốn tạo BankAccount bị hạn chế, chúng ta cần thay đổi lớp cha.

Ghi đè phương thức lớp cha

Trong ví dụ trên, chúng ta khai báo lớp cha BankAccount lưu trữ thông tin tài khoản ngân hàng. Chúng ta cũng tạo lớp con ChildBankAccount lưu trữ thông tin chủ tài khoản dưới 18 tuổi. Lớp này kế thừa phương thức từ BankAccount và tạo thêm phương thức isRestricted().

Nhưng nếu chúng ta muốn sửa đổi phương thức lớp cha hiện có? Giả sử chúng ta muốn số dư BankAccount trả về thông báo kèm thông điệp You are eligible for an overdraft, nhưng không muốn thông báo này xuất hiện cho chủ ChildBankAccount.

Để làm điều này, chúng ta cần ghi đè phương thức lớp cha.

Dưới đây là mã cho phương thức lớp cha đã sửa đổi, BankAccount, giờ in thông báo cho chủ tài khoản biết họ đủ điều kiện thấu chi khi kiểm tra số dư:

class BankAccount: def __init__(self, forename, surname, balance): self.forename = forename self.surname = surname self.balance = balance def getDetails(self): print("Forename: ", self.forename) print("Surname: ", self.surname) def getBalance(self): print("Balance: $ ", self.balance) print("You are eligible for an overdraft.")

Bây giờ, nếu tạo BankAccount mới cho John Appleseed và in số dư, chúng ta sẽ thấy thông báo You are eligible for an overdraft. Ví dụ khai báo tài khoản mới và kiểm tra số dư:

account = BankAccount("John", "Appleseed", 100) print(account.getBalance())

Mã trả về:

Balance: $ 100 You are eligible for an overdraft.

Nhưng thay đổi này cũng có nghĩa là ChildBankAccount, kế thừa giá trị từ BankAccount, cũng sẽ thấy thông báo. Ví dụ tạo ChildBankAccount và kiểm tra số dư sau khi lớp cha thay đổi:

child_account = ChildBankAccount("Bill", "Appleseed", 100) print(child_account.getBalance())

Mã trả về:

Balance: $ 100 You are eligible for an overdraft.

Vì trẻ em thường không được phép thấu chi, chúng ta cần sửa đổi mã. Để làm vậy, chúng ta phải sửa lớp ChildBankAccount và khai báo hàm getBalance() mới.

Dưới đây là mã ChildBankAccount từ trên:

class ChildBankAccount(BankAccount): def __init__(self, forename, surname, balance, restricted=True): self.forename = forename self.surname = surname self.balance = balance self.restricted = restricted def isRestricted(self): print("This account is restricted as the user is under 18.")

Chúng ta cần thay đổi mã để thêm hàm mới: getBalance(). Hàm này sẽ hoạt động giống như hàm trong lớp cha, nhưng không bao gồm thông báo về thấu chi. Đây là mã thêm vào để khai báo hàm mới:

... def getBalance(self): print("Balance: $ ", self.balance)

Hãy thử lấy số dư của trẻ em:

child_account = ChildBankAccount("Bill", "Appleseed", 100) print(child_account.getBalance())

Mã trả về:

Balance: $ 100

Trong ví dụ trên, chúng ta đã ghi đè phương thức getBalance() trong lớp con ChildBankAccount. Phương thức getBalance() mới cho ChildBankAccount chỉ hiển thị số dư. Nhưng trong lớp BankAccount, phương thức getBalance() hiển thị cả số dư và thông báo You are eligible for an overdraft.

Ghi đè phương thức lớp cha rất hữu ích khi bạn có nhiều phương thức lớp con có thể dùng phương thức tương tự lớp cha, nhưng yêu cầu thay đổi cụ thể riêng. Như trường hợp trên, chúng ta muốn tài khoản cha thấy thông báo thấu chi, nhưng không phải tài khoản con, nên ghi đè phương thức cha trong ChildBankAccount.

Kết luận

Kế thừa được dùng trong lập trình hướng đối tượng để giúp bạn tạo các lớp con có thể lưu trữ giá trị đã khai báo trong lớp cha. Điều này hữu ích khi bạn tạo các lớp tương tự sẽ lưu trữ các giá trị giống nhau, vì bạn có thể dùng kế thừa để tạo những lớp đó mà không cần lặp lại mã nhiều lần.

Trong hướng dẫn này, chúng ta đã khám phá vai trò của kế thừa trong Python. Chúng ta cũng thảo luận về cách kế thừa và lớp cha, lớp con hoạt động, sau đó khám phá cách ghi đè phương thức lớp cha. Bây giờ bạn đã sẵn sàng làm việc với lớp và kế thừa như một chuyên gia Python!