Trong bài viết này, bạn sẽ khám phá tính kế thừa và thành phần trong Python. Kế thừa và thành phần là hai khái niệm quan trọng trong lập trình hướng đối tượng, mô hình hóa mối quan hệ giữa hai lớp. Chúng là các khối xây dựng của thiết kế hướng đối tượng và chúng giúp các lập trình viên viết mã có thể tái sử dụng
Mô hình phân cấp lớp bằng cách sử dụng tính kế thừa
Sử dụng đa kế thừa trong Python và hiểu nhược điểm của nó
Sử dụng bố cục để tạo các đối tượng phức tạp
Sử dụng lại mã hiện có bằng cách áp dụng thành phần
Thay đổi hành vi của ứng dụng trong thời gian chạy thông qua thành phần
Tiền thưởng miễn phí. Nhấp vào đây để có quyền truy cập vào Bảng cheat Python OOP miễn phí chỉ cho bạn các hướng dẫn, video và sách hay nhất để tìm hiểu thêm về Lập trình hướng đối tượng với Python
What Are Inheritance and Composition?
Inheritance and composition are two major concepts in object oriented programming that model the relationship between two classes. They drive the design of an application and determine how the application should evolve as new features are added or requirements change
Both of them enable code reuse, but they do it in different ways
Remove ads
What’s Inheritance?
Inheritance models what is called an is a relationship. This means that when you have a
# In hr.pyclassHourlyEmployee(Employee):def__init__(self,id,name,hours_worked,hour_rate):super().__init__(id,name)self.hours_worked=hours_workedself.hour_rate=hour_ratedefcalculate_payroll(self):returnself.hours_worked*self.hour_rate
6 class that inherits from a
# In hr.pyclassHourlyEmployee(Employee):def__init__(self,id,name,hours_worked,hour_rate):super().__init__(id,name)self.hours_worked=hours_workedself.hour_rate=hour_ratedefcalculate_payroll(self):returnself.hours_worked*self.hour_rate
7 class, you created a relationship where
# In hr.pyclassHourlyEmployee(Employee):def__init__(self,id,name,hours_worked,hour_rate):super().__init__(id,name)self.hours_worked=hours_workedself.hour_rate=hour_ratedefcalculate_payroll(self):returnself.hours_worked*self.hour_rate
6 is a specialized version of
# In hr.pyclassHourlyEmployee(Employee):def__init__(self,id,name,hours_worked,hour_rate):super().__init__(id,name)self.hours_worked=hours_workedself.hour_rate=hour_ratedefcalculate_payroll(self):returnself.hours_worked*self.hour_rate
7
Inheritance is represented using the Unified Modeling Language or UML in the following way
Classes are represented as boxes with the class name on top. The inheritance relationship is represented by an arrow from the derived class pointing to the base class. The word extends is usually added to the arrow
Note. In an inheritance relationship
Classes that inherit from another are called derived classes, subclasses, or subtypes
Classes from which other classes are derived are called base classes or super classes
A derived class is said to derive, inherit, or extend a base class
Let’s say you have a base class
# In hr.pyclassCommissionEmployee(SalaryEmployee):def__init__(self,id,name,weekly_salary,commission):super().__init__(id,name,weekly_salary)self.commission=commissiondefcalculate_payroll(self):fixed=super().calculate_payroll()returnfixed+self.commission
0 and you derive from it to create a
# In hr.pyclassCommissionEmployee(SalaryEmployee):def__init__(self,id,name,weekly_salary,commission):super().__init__(id,name,weekly_salary)self.commission=commissiondefcalculate_payroll(self):fixed=super().calculate_payroll()returnfixed+self.commission
1 class. The inheritance relationship states that a
# In hr.pyclassCommissionEmployee(SalaryEmployee):def__init__(self,id,name,weekly_salary,commission):super().__init__(id,name,weekly_salary)self.commission=commissiondefcalculate_payroll(self):fixed=super().calculate_payroll()returnfixed+self.commission
1 is an
# In hr.pyclassCommissionEmployee(SalaryEmployee):def__init__(self,id,name,weekly_salary,commission):super().__init__(id,name,weekly_salary)self.commission=commissiondefcalculate_payroll(self):fixed=super().calculate_payroll()returnfixed+self.commission
0. This means that
# In hr.pyclassCommissionEmployee(SalaryEmployee):def__init__(self,id,name,weekly_salary,commission):super().__init__(id,name,weekly_salary)self.commission=commissiondefcalculate_payroll(self):fixed=super().calculate_payroll()returnfixed+self.commission
1 inherits the interface and implementation of
# In hr.pyclassCommissionEmployee(SalaryEmployee):def__init__(self,id,name,weekly_salary,commission):super().__init__(id,name,weekly_salary)self.commission=commissiondefcalculate_payroll(self):fixed=super().calculate_payroll()returnfixed+self.commission
0, and
# In hr.pyclassCommissionEmployee(SalaryEmployee):def__init__(self,id,name,weekly_salary,commission):super().__init__(id,name,weekly_salary)self.commission=commissiondefcalculate_payroll(self):fixed=super().calculate_payroll()returnfixed+self.commission
1 objects can be used to replace
# In hr.pyclassCommissionEmployee(SalaryEmployee):def__init__(self,id,name,weekly_salary,commission):super().__init__(id,name,weekly_salary)self.commission=commissiondefcalculate_payroll(self):fixed=super().calculate_payroll()returnfixed+self.commission
0 objects in the application
This is known as the Liskov substitution principle. Nguyên tắc nói rằng “trong một chương trình máy tính, nếu
# In hr.pyclassCommissionEmployee(SalaryEmployee):def__init__(self,id,name,weekly_salary,commission):super().__init__(id,name,weekly_salary)self.commission=commissiondefcalculate_payroll(self):fixed=super().calculate_payroll()returnfixed+self.commission
8 là một kiểu con của
# In hr.pyclassCommissionEmployee(SalaryEmployee):def__init__(self,id,name,weekly_salary,commission):super().__init__(id,name,weekly_salary)self.commission=commissiondefcalculate_payroll(self):fixed=super().calculate_payroll()returnfixed+self.commission
9, thì các đối tượng kiểu
# In hr.pyclassCommissionEmployee(SalaryEmployee):def__init__(self,id,name,weekly_salary,commission):super().__init__(id,name,weekly_salary)self.commission=commissiondefcalculate_payroll(self):fixed=super().calculate_payroll()returnfixed+self.commission
9 có thể được thay thế bằng các đối tượng kiểu
# In hr.pyclassCommissionEmployee(SalaryEmployee):def__init__(self,id,name,weekly_salary,commission):super().__init__(id,name,weekly_salary)self.commission=commissiondefcalculate_payroll(self):fixed=super().calculate_payroll()returnfixed+self.commission
8 mà không làm thay đổi bất kỳ thuộc tính mong muốn nào của chương trình”
Trong bài viết này, bạn sẽ thấy lý do tại sao bạn phải luôn tuân theo nguyên tắc thay thế Liskov khi tạo hệ thống phân cấp lớp của mình và những vấn đề bạn sẽ gặp phải nếu không tuân theo
Thành phần là gì?
Thành phần là một khái niệm mà các mô hình có một mối quan hệ. Nó cho phép tạo các kiểu phức tạp bằng cách kết hợp các đối tượng thuộc các kiểu khác. This means that a class
Composition is represented through a line with a diamond at the composite class pointing to the component class. The composite side can express the cardinality of the relationship. The cardinality indicates the number or valid range of
03 instances. The range is indicated with the minimum and maximum number of instances, or minimum and many instances like in 1. *
Ghi chú. Classes that contain objects of other classes are usually referred to as composites, where classes that are used to create more complex types are referred to as components
Ví dụ: lớp
# In hr.pyclassCommissionEmployee(SalaryEmployee):def__init__(self,id,name,weekly_salary,commission):super().__init__(id,name,weekly_salary)self.commission=commissiondefcalculate_payroll(self):fixed=super().calculate_payroll()returnfixed+self.commission
1 của bạn có thể được tạo bởi một đối tượng khác thuộc loại
18. Bố cục cho phép bạn thể hiện mối quan hệ đó bằng cách nói một
# In hr.pyclassCommissionEmployee(SalaryEmployee):def__init__(self,id,name,weekly_salary,commission):super().__init__(id,name,weekly_salary)self.commission=commissiondefcalculate_payroll(self):fixed=super().calculate_payroll()returnfixed+self.commission
Thành phần cho phép bạn sử dụng lại mã bằng cách thêm các đối tượng vào các đối tượng khác, thay vì kế thừa giao diện và triển khai của các lớp khác. Cả lớp
# In hr.pyclassCommissionEmployee(SalaryEmployee):def__init__(self,id,name,weekly_salary,commission):super().__init__(id,name,weekly_salary)self.commission=commissiondefcalculate_payroll(self):fixed=super().calculate_payroll()returnfixed+self.commission
18 thông qua thành phần mà không cần lấy lớp này từ lớp kia
Tổng quan về tính kế thừa trong Python
Mọi thứ trong Python đều là đối tượng. Mô-đun là đối tượng, định nghĩa lớp và hàm là đối tượng, và tất nhiên, đối tượng được tạo từ lớp cũng là đối tượng
Kế thừa là một tính năng bắt buộc của mọi ngôn ngữ lập trình hướng đối tượng. Điều này có nghĩa là Python hỗ trợ tính kế thừa và như bạn sẽ thấy ở phần sau, đây là một trong số ít ngôn ngữ hỗ trợ tính đa kế thừa
Khi bạn viết mã Python bằng các lớp, bạn đang sử dụng tính kế thừa ngay cả khi bạn không biết mình đang sử dụng nó. Hãy xem điều đó có nghĩa là gì
Remove ads
Siêu lớp đối tượng
The easiest way to see inheritance in Python is to jump into the and write a little bit of code. You’ll start by writing the simplest class possible
31. The exception to this rule are classes used to indicate errors by raising an exception
You can see the problem using the Python interactive interpreter
>>>
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
You created a new class to indicate a type of error. Then you tried to use it to raise an exception. An exception is raised but the output states that the exception is of type
38, the output correctly states the type of error raised
Creating Class Hierarchies
Inheritance is the mechanism you’ll use to create hierarchies of related classes. These related classes will share a common interface that will be defined in the base classes. Derived classes can specialize the interface by providing a particular implementation where applies
In this section, you’ll start modeling an HR system. The example will demonstrate the use of inheritance and how derived classes can provide a concrete implementation of the base class interface
The HR system needs to process payroll for the company’s employees, but there are different types of employees depending on how their payroll is calculated
Ví dụ, nhân viên hành chính có mức lương cố định, vì vậy hàng tuần họ được trả số tiền như nhau
# In hr.pyclassSalaryEmployee(Employee):def__init__(self,id,name,weekly_salary):super().__init__(id,name)self.weekly_salary=weekly_salarydefcalculate_payroll(self):returnself.weekly_salary
# In hr.pyclassHourlyEmployee(Employee):def__init__(self,id,name,hours_worked,hour_rate):super().__init__(id,name)self.hours_worked=hours_workedself.hour_rate=hour_ratedefcalculate_payroll(self):returnself.hours_worked*self.hour_rate
47 được thực hiện bằng cách trả lại số giờ đã làm việc nhân với tỷ lệ giờ
Cuối cùng, công ty tuyển dụng các cộng tác viên bán hàng được trả lương cố định cộng với hoa hồng dựa trên doanh số bán hàng của họ, vì vậy bạn tạo một lớp
# In hr.pyclassCommissionEmployee(SalaryEmployee):def__init__(self,id,name,weekly_salary,commission):super().__init__(id,name,weekly_salary)self.commission=commissiondefcalculate_payroll(self):fixed=super().calculate_payroll()returnfixed+self.commission
Chương trình tạo ba đối tượng nhân viên, một đối tượng cho mỗi lớp dẫn xuất. Sau đó, nó tạo hệ thống tính lương và chuyển danh sách nhân viên sang phương thức
51 trong ví dụ trên được gọi là lớp cơ sở trừu tượng. Các lớp cơ sở trừu tượng tồn tại để được kế thừa, nhưng không bao giờ được khởi tạo. Python cung cấp mô-đun
Bạn có thể sử dụng dấu gạch dưới hàng đầu trong tên lớp của mình để thông báo rằng các đối tượng của lớp đó không nên được tạo. Dấu gạch dưới cung cấp một cách thân thiện để ngăn việc sử dụng sai mã của bạn, nhưng chúng không ngăn người dùng háo hức tạo các phiên bản của lớp đó
Thư viện chuẩn trong Python cung cấp chức năng ngăn việc tạo các đối tượng từ các lớp cơ sở trừu tượng
97. Các lớp dẫn xuất phải ghi đè phương thức để cho phép tạo các đối tượng thuộc loại của chúng
Kế thừa triển khai so với Kế thừa giao diện
Khi bạn dẫn xuất một lớp này từ một lớp khác, lớp dẫn xuất sẽ kế thừa cả hai
Giao diện lớp cơ sở. Lớp dẫn xuất kế thừa tất cả các phương thức, thuộc tính và thuộc tính của lớp cơ sở
Việc thực hiện lớp cơ sở. Lớp dẫn xuất kế thừa mã cài đặt giao diện lớp
Hầu hết thời gian, bạn sẽ muốn kế thừa việc triển khai một lớp, nhưng bạn sẽ muốn triển khai nhiều giao diện, để các đối tượng của bạn có thể được sử dụng trong các tình huống khác nhau
Các ngôn ngữ lập trình hiện đại được thiết kế dựa trên khái niệm cơ bản này. Chúng cho phép bạn kế thừa từ một lớp duy nhất, nhưng bạn có thể triển khai nhiều giao diện
Trong Python, bạn không cần phải khai báo giao diện một cách rõ ràng. Bất kỳ đối tượng nào triển khai giao diện mong muốn đều có thể được sử dụng thay cho đối tượng khác. Điều này được gọi là. Gõ vịt thường được giải thích là “nếu nó hoạt động giống như một con vịt, thì đó là một con vịt. ”
45 vẫn có thể xử lý đối tượng mới vì nó đáp ứng giao diện mong muốn
Vì bạn không cần phải xuất phát từ một lớp cụ thể để chương trình có thể sử dụng lại các đối tượng của bạn, bạn có thể hỏi tại sao bạn nên sử dụng tính kế thừa thay vì chỉ triển khai giao diện mong muốn. Các quy tắc sau đây có thể giúp bạn
Sử dụng kế thừa để sử dụng lại một triển khai. Các lớp dẫn xuất của bạn nên tận dụng hầu hết việc triển khai lớp cơ sở của chúng. Họ cũng phải mô hình hóa một mối quan hệ. Một lớp
Thực hiện một giao diện được sử dụng lại. Khi bạn muốn lớp của mình được sử dụng lại bởi một phần cụ thể của ứng dụng, bạn triển khai giao diện bắt buộc trong lớp của mình, nhưng bạn không cần cung cấp lớp cơ sở hoặc kế thừa từ lớp khác
Bây giờ bạn có thể làm sạch ví dụ trên để chuyển sang chủ đề tiếp theo. Bạn có thể xóa tệp
62 để triển khai phiên bản của chính nó
Remove ads
Vấn đề bùng nổ lớp học
Nếu bạn không cẩn thận, tính kế thừa có thể dẫn bạn đến một cấu trúc phân cấp khổng lồ của các lớp khó hiểu và khó duy trì. This is known as the class explosion problem
65 theo dõi năng suất dựa trên vai trò của nhân viên. Có nhiều vai trò nhân viên khác nhau
quản lý. Họ đi xung quanh và la mắng mọi người bảo họ phải làm gì. Họ là những người làm công ăn lương và kiếm được nhiều tiền hơn
thư ký. Họ làm tất cả các công việc giấy tờ cho người quản lý và đảm bảo rằng mọi thứ được lập hóa đơn và thanh toán đúng hạn. Họ cũng là người làm công ăn lương nhưng kiếm được ít tiền hơn
nhân viên kinh doanh. Họ thực hiện rất nhiều cuộc điện thoại để bán sản phẩm. Họ có lương, nhưng họ cũng nhận được hoa hồng khi bán hàng
Công nhân nhà máy. Họ sản xuất các sản phẩm cho công ty. Họ được trả lương theo giờ
Chương trình tạo danh sách nhân viên các loại. Danh sách nhân viên được gửi đến hệ thống năng suất để theo dõi công việc của họ trong 40 giờ. Sau đó, cùng một danh sách nhân viên được gửi đến hệ thống bảng lương để tính lương cho họ
Chương trình hiển thị các nhân viên làm việc trong 40 giờ thông qua hệ thống năng suất. Sau đó, nó tính toán và hiển thị bảng lương cho từng nhân viên
Chương trình hoạt động như mong đợi, nhưng bạn phải thêm bốn lớp mới để hỗ trợ các thay đổi. Khi có các yêu cầu mới, hệ thống phân cấp lớp của bạn chắc chắn sẽ phát triển, dẫn đến vấn đề bùng nổ lớp trong đó hệ thống phân cấp của bạn sẽ trở nên lớn đến mức chúng sẽ khó hiểu và khó duy trì
Sơ đồ sau đây cho thấy hệ thống phân cấp lớp mới
Sơ đồ cho thấy hệ thống phân cấp lớp đang phát triển như thế nào. Các yêu cầu bổ sung có thể có tác động theo cấp số nhân về số lượng lớp học với thiết kế này
Remove ads
Kế thừa nhiều lớp
Python là một trong số ít ngôn ngữ lập trình hiện đại hỗ trợ đa kế thừa. Đa kế thừa là khả năng dẫn xuất một lớp từ nhiều lớp cơ sở cùng một lúc
Đa kế thừa có tiếng xấu đến mức hầu hết các ngôn ngữ lập trình hiện đại không hỗ trợ nó. Thay vào đó, các ngôn ngữ lập trình hiện đại hỗ trợ khái niệm giao diện. Trong các ngôn ngữ đó, bạn kế thừa từ một lớp cơ sở duy nhất và sau đó triển khai nhiều giao diện, vì vậy lớp của bạn có thể được sử dụng lại trong các tình huống khác nhau
Cách tiếp cận này đặt ra một số ràng buộc trong thiết kế của bạn. Bạn chỉ có thể kế thừa việc triển khai một lớp bằng cách xuất phát trực tiếp từ nó. Bạn có thể triển khai nhiều giao diện, nhưng bạn không thể kế thừa việc triển khai nhiều lớp
Ràng buộc này tốt cho thiết kế phần mềm vì nó buộc bạn phải thiết kế các lớp của mình với ít phụ thuộc lẫn nhau hơn. Ở phần sau của bài viết này, bạn sẽ thấy rằng bạn có thể tận dụng nhiều triển khai thông qua thành phần, giúp phần mềm trở nên linh hoạt hơn. Tuy nhiên, phần này nói về đa thừa kế, vì vậy chúng ta hãy xem nó hoạt động như thế nào
Hóa ra đôi khi thư ký tạm thời được thuê khi có quá nhiều giấy tờ phải làm. Lớp
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
Bây giờ, hãy chạy lại chương trình và xem điều gì sẽ xảy ra
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
09 sẽ giúp ích
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
1
Thử nó
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
2
Điều đó cũng không hiệu quả. Được rồi, đã đến lúc bạn đi sâu vào trình tự giải quyết phương pháp Python (MRO) để xem điều gì đang xảy ra
Khi một phương thức hoặc thuộc tính của một lớp được truy cập, Python sử dụng lớp MRO để tìm nó. MRO cũng được sử dụng bởi
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
3
MRO hiển thị thứ tự mà Python sẽ tìm kiếm một thuộc tính hoặc phương thức phù hợp. Trong ví dụ này, đây là điều xảy ra khi chúng ta tạo đối tượng
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
14 được gọi là
Cuộc gọi
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
15 phù hợp với
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
18, mà MRO sẽ khớp với
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
04, được kế thừa từ
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
Bạn có thể bỏ qua MRO bằng cách đảo ngược thứ tự thừa kế và gọi trực tiếp
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
22 như sau
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
4
Điều đó giải quyết vấn đề tạo đối tượng, nhưng bạn sẽ gặp phải vấn đề tương tự khi cố tính bảng lương. Bạn có thể chạy chương trình để xem vấn đề
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
5
Vấn đề bây giờ là do bạn đảo ngược thứ tự thừa kế, MRO đang tìm phương pháp
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
29 để đảm bảo rằng bạn nhận được kết quả chính xác. Bạn có thể chạy lại chương trình để thấy nó hoạt động
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
7
Chương trình hiện hoạt động như mong đợi vì bạn đang buộc thứ tự giải quyết phương thức bằng cách thông báo rõ ràng cho trình thông dịch biết phương pháp nào chúng tôi muốn sử dụng
Như bạn có thể thấy, đa thừa kế có thể gây nhầm lẫn, đặc biệt là khi bạn gặp phải
Sơ đồ sau đây cho thấy vấn đề kim cương trong hệ thống phân cấp lớp học của bạn
Sơ đồ cho thấy vấn đề kim cương với thiết kế lớp hiện tại.
51, đây là điều bạn muốn tránh trong thiết kế của mình
Vấn đề kim cương xuất hiện khi bạn đang sử dụng nhiều kế thừa và xuất phát từ hai lớp có lớp cơ sở chung. Điều này có thể gây ra phiên bản sai của một phương thức được gọi
Như bạn đã thấy, Python cung cấp một cách để buộc gọi đúng phương thức và việc phân tích MRO có thể giúp bạn hiểu vấn đề
Tuy nhiên, khi bạn gặp vấn đề về kim cương, tốt hơn hết là bạn nên suy nghĩ lại về thiết kế. Bây giờ bạn sẽ thực hiện một số thay đổi để tận dụng đa kế thừa, tránh vấn đề kim cương
Hệ thống năng suất theo dõi năng suất của nhân viên
Hệ thống bảng lương tính toán bảng lương của nhân viên
Điều này có nghĩa là mọi thứ liên quan đến năng suất phải được đặt cùng nhau trong một mô-đun và mọi thứ liên quan đến bảng lương phải được đặt cùng nhau trong một mô-đun khác. Bạn có thể bắt đầu thực hiện các thay đổi đối với mô-đun năng suất
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
8
Mô-đun
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
45, tính toán bảng lương cho nhân viên. Nó cũng thực hiện các lớp chính sách cho bảng lương. Như bạn có thể thấy, các lớp chính sách không bắt nguồn từ
51 khác nhau. Bạn vẫn đang sử dụng đa kế thừa để kế thừa việc triển khai các lớp chính sách tiền lương và vai trò năng suất, nhưng việc triển khai từng lớp chỉ cần xử lý việc khởi tạo
Lưu ý rằng bạn vẫn cần khởi tạo rõ ràng các chính sách tiền lương trong hàm tạo. Bạn có thể thấy rằng phần khởi tạo của
82 bằng cách sử dụng đa thừa kế, nhưng tránh vấn đề kim cương
You can run the program and see how it works
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
1
Bạn đã thấy cách hoạt động của thừa kế và đa thừa kế trong Python. Bây giờ bạn có thể khám phá chủ đề sáng tác
Remove ads
Thành phần trong Python
Thành phần là một khái niệm thiết kế hướng đối tượng mà mô hình có một mối quan hệ. Trong thành phần, một lớp được gọi là hỗn hợp chứa một đối tượng của một lớp khác được gọi là thành phần. Nói cách khác, một lớp tổng hợp có một thành phần của lớp khác
Thành phần cho phép các lớp tổng hợp sử dụng lại việc triển khai các thành phần mà nó chứa. Lớp tổng hợp không kế thừa giao diện lớp thành phần, nhưng nó có thể tận dụng việc triển khai của nó
Mối quan hệ thành phần giữa hai lớp được coi là liên kết lỏng lẻo. Điều đó có nghĩa là những thay đổi đối với lớp thành phần hiếm khi ảnh hưởng đến lớp tổng hợp và những thay đổi đối với lớp tổng hợp không bao giờ ảnh hưởng đến lớp thành phần
Điều này cung cấp khả năng thích ứng tốt hơn để thay đổi và cho phép các ứng dụng đưa ra các yêu cầu mới mà không ảnh hưởng đến mã hiện có
Khi xem xét hai thiết kế phần mềm cạnh tranh, một dựa trên tính kế thừa và một dựa trên thành phần, giải pháp thành phần thường là linh hoạt nhất. Bây giờ bạn có thể xem cách sáng tác hoạt động
Bạn đã sử dụng bố cục trong các ví dụ của chúng tôi. Nếu bạn nhìn vào lớp
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
58
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
2
Bạn đã triển khai một lớp địa chỉ cơ bản chứa các thành phần thông thường cho một địa chỉ. Bạn đã đặt thuộc tính
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
59 là tùy chọn vì không phải địa chỉ nào cũng có thành phần đó
Bạn đã triển khai
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
60 để cung cấp một biểu diễn đẹp mắt của một
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
58. Bạn có thể thấy cách triển khai này trong trình thông dịch tương tác
>>>
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
3
Khi bạn
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
62 biến
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
63, phương thức đặc biệt
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
60 được gọi. Vì bạn đã quá tải phương thức để trả về một chuỗi được định dạng dưới dạng địa chỉ, nên bạn sẽ có một biểu diễn đẹp, dễ đọc. Quá tải toán tử và chức năng trong các lớp Python tùy chỉnh cung cấp một cái nhìn tổng quan về các phương thức đặc biệt có sẵn trong các lớp có thể được triển khai để tùy chỉnh hành vi của các đối tượng của bạn
Bây giờ bạn có thể thêm
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
4
Bây giờ, bạn khởi tạo thuộc tính
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
63 thành
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
68 để làm cho nó trở thành tùy chọn, nhưng bằng cách đó, giờ đây bạn có thể gán một
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
72
Thành phần là một mối quan hệ kết hợp lỏng lẻo thường không yêu cầu lớp tổng hợp phải có kiến thức về thành phần
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
94 có địa chỉ không, nếu có thì in ra. Bây giờ bạn có thể sửa đổi chương trình để gán một số địa chỉ cho nhân viên
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
6
Bạn đã thêm một vài địa chỉ vào các đối tượng
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
81 và
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
82. Khi bạn chạy chương trình, bạn sẽ thấy các địa chỉ được in
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
7
Lưu ý cách đầu ra bảng lương cho các đối tượng
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
81 và
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
58 mà không có bất kỳ kiến thức nào về đối tượng
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
58 là gì hoặc nó được biểu diễn như thế nào. Kiểu thiết kế này linh hoạt đến mức bạn có thể thay đổi lớp
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
Thành phần linh hoạt hơn thừa kế vì nó mô hình hóa mối quan hệ kết hợp lỏng lẻo. Các thay đổi đối với một lớp thành phần có ảnh hưởng tối thiểu hoặc không ảnh hưởng đến lớp tổng hợp. Thiết kế dựa trên thành phần phù hợp hơn để thay đổi
Bạn thay đổi hành vi bằng cách cung cấp các thành phần mới triển khai các hành vi đó thay vì thêm các lớp mới vào hệ thống phân cấp của bạn
Hãy xem ví dụ đa thừa kế ở trên. Hãy tưởng tượng chính sách tiền lương mới sẽ ảnh hưởng đến thiết kế như thế nào. Cố gắng hình dung hệ thống phân cấp lớp sẽ như thế nào nếu cần có vai trò mới. Như bạn đã thấy trước đây, việc phụ thuộc quá nhiều vào tính kế thừa có thể dẫn đến bùng nổ giai cấp
Vấn đề lớn nhất không phải là số lượng các lớp trong thiết kế của bạn nhiều như thế nào, mà là mối quan hệ giữa các lớp đó chặt chẽ đến mức nào. Các lớp liên kết chặt chẽ ảnh hưởng lẫn nhau khi các thay đổi được đưa ra
Trong phần này, bạn sẽ sử dụng bố cục để thực hiện một thiết kế tốt hơn mà vẫn phù hợp với các yêu cầu của
65 xác định một số vai trò bằng cách sử dụng mã định danh chuỗi được ánh xạ tới lớp vai trò thực hiện vai trò đó. Nó hiển thị một phương thức
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
94, được cung cấp một định danh vai trò, trả về đối tượng loại vai trò. Nếu vai trò không được tìm thấy, thì một ngoại lệ
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
95 sẽ được đưa ra
Nó cũng hiển thị chức năng trước đó trong phương pháp
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
96, trong đó đưa ra một danh sách nhân viên, nó theo dõi năng suất của những nhân viên đó
Bây giờ bạn có thể triển khai các lớp vai trò khác nhau
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
9
Mỗi vai trò mà bạn đã triển khai đều cho thấy một
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
75 đã làm việc. Các phương thức trả về một chuỗi đại diện cho các nhiệm vụ
Các lớp vai trò độc lập với nhau, nhưng chúng hiển thị cùng một giao diện, vì vậy chúng có thể hoán đổi cho nhau. Sau này bạn sẽ thấy chúng được sử dụng như thế nào trong ứng dụng
48 doesn’t exist in the system, then the method raises a
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
24
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
24 được sử dụng để tính toán
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
26, được triển khai như một thuộc tính để nó được tính toán khi được yêu cầu. Trong ví dụ này, chúng tôi giả định rằng một lần bán hàng diễn ra sau mỗi 5 giờ làm việc và
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
26 là số lần bán hàng nhân với giá trị
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
24
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
32 giữ một cơ sở dữ liệu nội bộ gồm các đối tượng
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
58 cho mỗi nhân viên. Nó hiển thị một phương thức
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
95
Việc triển khai lớp
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
58 vẫn giống như trước đây
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
2
Lớp quản lý các thành phần địa chỉ và cung cấp một biểu diễn đẹp về địa chỉ
Cho đến nay, các lớp mới đã được mở rộng để hỗ trợ nhiều chức năng hơn, nhưng không có thay đổi đáng kể nào đối với thiết kế trước đó. Điều này sẽ thay đổi với thiết kế của mô-đun
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
63. Nó cũng đòi hỏi năng suất
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
45 của nhân viên và chính sách
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
51 duy nhất bao gồm các đối tượng dữ liệu khác như
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
58 và phụ thuộc vào giao diện
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
Thiết kế này được gọi là , trong đó các lớp bao gồm các chính sách và chúng ủy quyền cho các chính sách đó để thực hiện công việc
Thiết kế dựa trên chính sách đã được giới thiệu trong cuốn sách Modern C++ Design và nó sử dụng siêu lập trình mẫu trong C++ để đạt được kết quả
Python không hỗ trợ các mẫu, nhưng bạn có thể đạt được kết quả tương tự bằng cách sử dụng bố cục, như bạn đã thấy trong ví dụ trên
Kiểu thiết kế này mang đến cho bạn tất cả sự linh hoạt mà bạn cần khi các yêu cầu thay đổi. Hãy tưởng tượng bạn cần thay đổi cách tính lương cho một đối tượng trong thời gian chạy
Remove ads
Tùy chỉnh hành vi với thành phần
Nếu thiết kế của bạn dựa trên sự kế thừa, bạn cần tìm cách thay đổi loại đối tượng để thay đổi hành vi của nó. Với bố cục, bạn chỉ cần thay đổi chính sách mà đối tượng sử dụng
Hãy tưởng tượng rằng
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
81 của chúng ta đột nhiên trở thành nhân viên tạm thời được trả lương theo giờ. Bạn có thể sửa đổi đối tượng trong quá trình thực hiện chương trình theo cách sau
Tấm séc cho Mary Poppins, người quản lý của chúng tôi, hiện có giá 2200 đô la thay vì mức lương cố định 3000 đô la mà cô ấy có mỗi tuần
Lưu ý cách chúng tôi đã thêm quy tắc kinh doanh đó vào chương trình mà không thay đổi bất kỳ lớp hiện có nào. Xem xét loại thay đổi nào sẽ được yêu cầu với thiết kế kế thừa
Bạn sẽ phải tạo một lớp mới và thay đổi loại nhân viên quản lý. Không có khả năng bạn có thể thay đổi chính sách trong thời gian chạy
Lựa chọn giữa Kế thừa và Thành phần trong Python
Cho đến giờ, bạn đã thấy cách hoạt động của tính kế thừa và thành phần trong Python. Bạn đã thấy rằng các lớp dẫn xuất kế thừa giao diện và triển khai của các lớp cơ sở của chúng. Bạn cũng đã thấy rằng thành phần cho phép bạn sử dụng lại việc triển khai một lớp khác
Bạn đã triển khai hai giải pháp cho cùng một vấn đề. Giải pháp đầu tiên sử dụng đa kế thừa và giải pháp thứ hai sử dụng thành phần
Bạn cũng đã thấy rằng cách gõ vịt của Python cho phép bạn sử dụng lại các đối tượng với các phần hiện có của chương trình bằng cách triển khai giao diện mong muốn. Trong Python, không cần thiết phải xuất phát từ một lớp cơ sở để các lớp của bạn được sử dụng lại
Tại thời điểm này, bạn có thể hỏi khi nào nên sử dụng thừa kế so với thành phần trong Python. Cả hai đều cho phép sử dụng lại mã. Kế thừa và thành phần có thể giải quyết các vấn đề tương tự trong chương trình Python của bạn
Lời khuyên chung là sử dụng mối quan hệ tạo ra ít phụ thuộc hơn giữa hai lớp. Mối quan hệ này là thành phần. Tuy nhiên, sẽ có lúc việc kế thừa sẽ có ý nghĩa hơn
Các phần sau đây cung cấp một số hướng dẫn để giúp bạn đưa ra lựa chọn đúng đắn giữa kế thừa và thành phần trong Python
Kế thừa mô hình Mối quan hệ “Là A”
Kế thừa chỉ nên được sử dụng để mô hình hóa một mối quan hệ. Nguyên tắc thay thế của Liskov nói rằng một đối tượng kiểu
# In hr.pyclassHourlyEmployee(Employee):def__init__(self,id,name,hours_worked,hour_rate):super().__init__(id,name)self.hours_worked=hours_workedself.hour_rate=hour_ratedefcalculate_payroll(self):returnself.hours_worked*self.hour_rate
6, kế thừa từ
# In hr.pyclassHourlyEmployee(Employee):def__init__(self,id,name,hours_worked,hour_rate):super().__init__(id,name)self.hours_worked=hours_workedself.hour_rate=hour_ratedefcalculate_payroll(self):returnself.hours_worked*self.hour_rate
7, có thể thay thế một đối tượng kiểu
# In hr.pyclassHourlyEmployee(Employee):def__init__(self,id,name,hours_worked,hour_rate):super().__init__(id,name)self.hours_worked=hours_workedself.hour_rate=hour_ratedefcalculate_payroll(self):returnself.hours_worked*self.hour_rate
7 mà không làm thay đổi các thuộc tính mong muốn của chương trình
Nguyên tắc thay thế của Liskov là hướng dẫn quan trọng nhất để xác định xem kế thừa có phải là giải pháp thiết kế phù hợp hay không. Tuy nhiên, câu trả lời có thể không đơn giản trong mọi tình huống. May mắn thay, có một bài kiểm tra đơn giản mà bạn có thể sử dụng để xác định xem thiết kế của mình có tuân theo nguyên tắc thay thế của Liskov hay không
Giả sử bạn có một lớp
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
78 cung cấp cách triển khai và giao diện mà bạn muốn sử dụng lại trong một lớp khác
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
79. Suy nghĩ ban đầu của bạn là bạn có thể lấy
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
79 từ
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
78 và kế thừa cả giao diện và triển khai. Để chắc chắn đây là thiết kế phù hợp, bạn làm theo các bước sau
Đánh giá
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
79 là một
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
78. Hãy suy nghĩ về mối quan hệ này và biện minh cho nó. Liệu nó có ý nghĩa?
Đánh giá
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
78 là một
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
79. Đảo ngược mối quan hệ và biện minh cho nó. Liệu nó cũng có ý nghĩa?
Nếu bạn có thể biện minh cho cả hai mối quan hệ, thì bạn không bao giờ nên kế thừa các lớp đó từ lớp khác. Hãy xem xét một ví dụ cụ thể hơn
Bạn có một lớp
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
86 hiển thị một thuộc tính
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
87. Bạn cần một lớp
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
88, lớp này cũng có một lớp
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
87. Có vẻ như
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
88 là một loại đặc biệt của
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
86, vì vậy có lẽ bạn có thể rút ra từ nó và tận dụng cả giao diện và triển khai
Trước khi bắt đầu triển khai, bạn sử dụng nguyên tắc thay thế của Liskov để đánh giá mối quan hệ
Một
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
88 là một
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
86 vì diện tích của nó được tính từ tích của ____61_______94 nhân với ____61_______95 của nó. Ràng buộc là
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
96 và
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
97 phải bằng nhau
Nó có ý nghĩa. Bạn có thể biện minh cho mối quan hệ và giải thích tại sao một
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
88 lại là một
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
86. Hãy đảo ngược mối quan hệ để xem nó có hợp lý không
Một
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
86 là một
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
88 vì diện tích của nó được tính từ tích của
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
94 nhân với
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
Nó cũng có ý nghĩa. Bạn có thể biện minh cho mối quan hệ và mô tả các ràng buộc đặc biệt cho mỗi lớp. Đây là một dấu hiệu tốt rằng hai lớp này sẽ không bao giờ xuất phát từ nhau
Bạn có thể đã thấy các ví dụ khác dẫn xuất
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
88 từ
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
86 để giải thích quyền thừa kế. Bạn có thể hoài nghi với bài kiểm tra nhỏ bạn vừa làm. Đủ công bằng. Let’s write a program that illustrates the problem with deriving
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
88 from
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
86
Đầu tiên, bạn triển khai
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
86. Bạn thậm chí sẽ đóng gói các thuộc tính để đảm bảo rằng tất cả các ràng buộc đều được đáp ứng
# In hr.pyclassEmployee:def__init__(self,id,name):self.id=idself.name=name
0
Lớp
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
86 được khởi tạo với một
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
95 và một
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
94, và nó cung cấp một thuộc tính
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
87 trả về diện tích.
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
95 và
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
94 được đóng gói để tránh thay đổi chúng trực tiếp
Bây giờ, bạn lấy được
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
88 từ
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
86 và ghi đè giao diện cần thiết để đáp ứng các ràng buộc của một
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
88
# In hr.pyclassEmployee:def__init__(self,id,name):self.id=idself.name=name
1
Lớp
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
94, nhưng điều đó sẽ gây nhầm lẫn cho những người đang xem các phần khác của chương trình nơi mà ____64_______44 đang được thay đổi kích thước và một số trong số chúng không nhận được các khu vực mong đợi vì chúng thực sự là ____64_______45
Trong một chương trình nhỏ như chương trình này, có thể dễ dàng phát hiện ra nguyên nhân của hành vi kỳ lạ, nhưng trong một chương trình phức tạp hơn, vấn đề sẽ khó tìm ra hơn
Thực tế là nếu bạn có thể biện minh cho mối quan hệ thừa kế giữa hai lớp theo cả hai cách, thì bạn không nên lấy lớp này từ lớp khác
Trong ví dụ này, không có nghĩa là
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
Sự khác biệt trong giao diện này biện minh cho việc không bắt nguồn từ
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
88 từ
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
86 như bài kiểm tra đã khuyên ở trên
Remove ads
Trộn các tính năng với các lớp Mixin
Một trong những cách sử dụng đa kế thừa trong Python là mở rộng các tính năng của lớp thông qua mixin. Mixin là một lớp cung cấp các phương thức cho các lớp khác nhưng không được coi là một lớp cơ sở
Mixin cho phép các lớp khác sử dụng lại giao diện và triển khai của nó mà không trở thành siêu lớp. Chúng triển khai một hành vi duy nhất có thể được tổng hợp cho các lớp không liên quan khác. Chúng tương tự như thành phần nhưng chúng tạo ra một mối quan hệ mạnh mẽ hơn
Giả sử bạn muốn chuyển đổi các đối tượng thuộc một số loại nhất định trong ứng dụng của mình thành biểu diễn từ điển của đối tượng. Bạn có thể cung cấp phương thức
# In hr.pyclassSalaryEmployee(Employee):def__init__(self,id,name,weekly_salary):super().__init__(id,name)self.weekly_salary=weekly_salarydefcalculate_payroll(self):returnself.weekly_salary
# In hr.pyclassSalaryEmployee(Employee):def__init__(self,id,name,weekly_salary):super().__init__(id,name)self.weekly_salary=weekly_salarydefcalculate_payroll(self):returnself.weekly_salary
58 để hỗ trợ chức năng. Sẽ rất tuyệt nếu hỗ trợ chức năng tương tự trong lớp
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
# In hr.pyclassSalaryEmployee(Employee):def__init__(self,id,name,weekly_salary):super().__init__(id,name)self.weekly_salary=weekly_salarydefcalculate_payroll(self):returnself.weekly_salary
2
Bạn áp dụng mixin cho lớp
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
58 để hỗ trợ tính năng. Bây giờ, bạn có thể viết một chương trình nhỏ để kiểm tra nó
# In hr.pyclassSalaryEmployee(Employee):def__init__(self,id,name,weekly_salary):super().__init__(id,name)self.weekly_salary=weekly_salarydefcalculate_payroll(self):returnself.weekly_salary
53. Bạn có thể chạy chương trình để xem đầu ra của nó
# In hr.pyclassSalaryEmployee(Employee):def__init__(self,id,name,weekly_salary):super().__init__(id,name)self.weekly_salary=weekly_salarydefcalculate_payroll(self):returnself.weekly_salary
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
58.
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
58 thực hiện tất cả các chức năng để xử lý địa chỉ và nó có thể được sử dụng lại bởi các lớp khác
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
51. Họ có thể tận dụng cùng một triển khai để đảm bảo rằng các địa chỉ được xử lý một cách nhất quán trên ứng dụng
Một vấn đề bạn có thể gặp phải khi sử dụng thành phần là một số lớp của bạn có thể bắt đầu phát triển bằng cách sử dụng nhiều thành phần. Các lớp của bạn có thể yêu cầu nhiều tham số trong hàm tạo chỉ để truyền vào các thành phần mà chúng được tạo thành. Điều này có thể làm cho các lớp học của bạn khó sử dụng
Một cách để tránh vấn đề là sử dụng Factory Method để xây dựng các đối tượng của bạn. Bạn đã làm điều đó với ví dụ thành phần
Nếu bạn nhìn vào việc triển khai lớp
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
41, bạn sẽ nhận thấy rằng nó sử dụng
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
# In hr.pyclassEmployee:def__init__(self,id,name):self.id=idself.name=name
02
Những thay đổi sau đây có thể cải thiện thiết kế của bạn. Bạn có thể bắt đầu với mô-đun
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
34
# In hr.pyclassSalaryEmployee(Employee):def__init__(self,id,name,weekly_salary):super().__init__(id,name)self.weekly_salary=weekly_salarydefcalculate_payroll(self):returnself.weekly_salary
5
Đầu tiên, bạn tạo nội bộ lớp
# In hr.pyclassEmployee:def__init__(self,id,name):self.id=idself.name=name
04, sau đó cung cấp biến nội bộ
# In hr.pyclassEmployee:def__init__(self,id,name):self.id=idself.name=name
05 cho mô-đun. Bạn đang thông báo với các nhà phát triển khác rằng họ không nên tạo hoặc sử dụng trực tiếp
# In hr.pyclassEmployee:def__init__(self,id,name):self.id=idself.name=name
04. Thay vào đó, bạn cung cấp hai chức năng,
# In hr.pyclassEmployee:def__init__(self,id,name):self.id=idself.name=name
# In hr.pyclassSalaryEmployee(Employee):def__init__(self,id,name,weekly_salary):super().__init__(id,name)self.weekly_salary=weekly_salarydefcalculate_payroll(self):returnself.weekly_salary
6
Một lần nữa, bạn tạo
# In hr.pyclassEmployee:def__init__(self,id,name):self.id=idself.name=name
11 nội bộ và cung cấp giao diện công khai cho nó. Ứng dụng sẽ sử dụng giao diện công khai để lấy chính sách và tính lương
Bây giờ bạn sẽ làm tương tự với mô-đun
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
72
# In hr.pyclassSalaryEmployee(Employee):def__init__(self,id,name,weekly_salary):super().__init__(id,name)self.weekly_salary=weekly_salarydefcalculate_payroll(self):returnself.weekly_salary
7
Về cơ bản, bạn đang nói rằng chỉ nên có một
# In hr.pyclassEmployee:def__init__(self,id,name):self.id=idself.name=name
13, một
# In hr.pyclassEmployee:def__init__(self,id,name):self.id=idself.name=name
11 và một
# In hr.pyclassEmployee:def__init__(self,id,name):self.id=idself.name=name
04. Một lần nữa, mẫu thiết kế này được gọi là mẫu thiết kế Singleton, rất hữu ích cho các lớp chỉ nên có một thể hiện duy nhất.
# In hr.pyclassEmployee:def__init__(self,id,name):self.id=idself.name=name
17, nhưng bạn sẽ thực hiện một số thay đổi bổ sung
# In hr.pyclassSalaryEmployee(Employee):def__init__(self,id,name,weekly_salary):super().__init__(id,name)self.weekly_salary=weekly_salarydefcalculate_payroll(self):returnself.weekly_salary
8
Trước tiên, bạn nhập các hàm và lớp có liên quan từ các mô-đun khác.
# In hr.pyclassEmployee:def__init__(self,id,name):self.id=idself.name=name
17 được tạo nội bộ và ở dưới cùng, bạn tạo một phiên bản duy nhất. Phiên bản này là công khai và là một phần của giao diện vì bạn sẽ muốn sử dụng nó trong ứng dụng
You changed the
# In hr.pyclassEmployee:def__init__(self,id,name):self.id=idself.name=name
19 attribute to be a dictionary where the key is the employee
48 và sử dụng các hàm công khai có trong các mô-đun khác để khởi tạo các thuộc tính của nó
Bây giờ bạn có thể thay đổi chương trình để kiểm tra các thay đổi
# In hr.pyclassSalaryEmployee(Employee):def__init__(self,id,name,weekly_salary):super().__init__(id,name)self.weekly_salary=weekly_salarydefcalculate_payroll(self):returnself.weekly_salary
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
34, cũng như lớp
# In hr.pyclassEmployee:def__init__(self,id,name):self.id=idself.name=name
48 của nó. Bạn có thể chạy chương trình để xem đầu ra của nó
# In hr.pyclassHourlyEmployee(Employee):def__init__(self,id,name,hours_worked,hour_rate):super().__init__(id,name)self.hours_worked=hours_workedself.hour_rate=hour_ratedefcalculate_payroll(self):returnself.hours_worked*self.hour_rate
0
Chương trình hoạt động giống như trước đây, nhưng bây giờ bạn có thể thấy rằng một đối tượng
# In hr.pyclassHourlyEmployee(Employee):def__init__(self,id,name,hours_worked,hour_rate):super().__init__(id,name)self.hours_worked=hours_workedself.hour_rate=hour_ratedefcalculate_payroll(self):returnself.hours_worked*self.hour_rate
51 là một hỗn hợp chứa nhiều đối tượng cung cấp các chức năng khác nhau. Nó chứa một
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
58 thực hiện tất cả các chức năng liên quan đến nơi nhân viên sống
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
Bạn đang sử dụng bố cục theo hai cách khác nhau. Lớp
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
51 và các đối tượng đó được kết hợp lỏng lẻo, cung cấp một số khả năng thú vị mà bạn sẽ thấy trong phần tiếp theo
Thành phần để thay đổi hành vi thời gian chạy
Kế thừa, trái ngược với thành phần, là một mối quan hệ cặp đôi chặt chẽ. Với tính kế thừa, chỉ có một cách để thay đổi và tùy chỉnh hành vi. Ghi đè phương thức là cách duy nhất để tùy chỉnh hành vi của lớp cơ sở. Điều này tạo ra những thiết kế cứng nhắc, khó thay đổi
Mặt khác, thành phần cung cấp một mối quan hệ được kết hợp lỏng lẻo cho phép các thiết kế linh hoạt và có thể được sử dụng để thay đổi hành vi trong thời gian chạy
Hãy tưởng tượng bạn cần hỗ trợ chính sách khuyết tật dài hạn (LTD) khi tính bảng lương. Chính sách quy định rằng một nhân viên tại LTD sẽ được trả 60% tiền lương hàng tuần của họ với giả định 40 giờ làm việc
Với thiết kế kế thừa, đây có thể là một yêu cầu rất khó hỗ trợ. Thêm nó vào ví dụ thành phần dễ dàng hơn nhiều. Hãy bắt đầu bằng cách thêm lớp chính sách
# In hr.pyclassHourlyEmployee(Employee):def__init__(self,id,name,hours_worked,hour_rate):super().__init__(id,name)self.hours_worked=hours_workedself.hour_rate=hour_ratedefcalculate_payroll(self):returnself.hours_worked*self.hour_rate
2
Lưu ý rằng
# In hr.pyclassEmployee:def__init__(self,id,name):self.id=idself.name=name
49 không kế thừa
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
06, nhưng triển khai cùng một giao diện. Điều này là do việc triển khai hoàn toàn khác, vì vậy chúng tôi không muốn kế thừa bất kỳ triển khai nào của
>>> classMyError(Exception):.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in __main__.MyError
06
# In hr.pyclassEmployee:def__init__(self,id,name):self.id=idself.name=name
49 khởi tạo
# In hr.pyclassEmployee:def__init__(self,id,name):self.id=idself.name=name
53 thành
>>> classMyError:.. pass...>>> raiseMyError()Traceback (most recent call last): File "", line 1, in TypeError: exceptions must derive from BaseException
68 và cung cấp một phương thức ____71_______55 nội bộ để đưa ra một ngoại lệ nếu ______71_______56 chưa được áp dụng. Sau đó, nó cung cấp một phương thức
# In hr.pyclassEmployee:def__init__(self,id,name):self.id=idself.name=name
57 để chỉ định
# In hr.pyclassEmployee:def__init__(self,id,name):self.id=idself.name=name
53
Trước tiên, giao diện công khai kiểm tra xem
# In hr.pyclassEmployee:def__init__(self,id,name):self.id=idself.name=name
53 đã được áp dụng chưa, sau đó triển khai chức năng theo chính sách cơ sở đó. Phương thức
# In hr.pyclassEmployee:def__init__(self,id,name):self.id=idself.name=name
# In hr.pyclassHourlyEmployee(Employee):def__init__(self,id,name,hours_worked,hour_rate):super().__init__(id,name)self.hours_worked=hours_workedself.hour_rate=hour_ratedefcalculate_payroll(self):returnself.hours_worked*self.hour_rate
3
Bạn đã thêm một phương pháp
# In hr.pyclassEmployee:def__init__(self,id,name):self.id=idself.name=name
64 áp dụng chính sách bảng lương hiện có cho chính sách mới và sau đó thay thế nó. Bây giờ bạn có thể sửa đổi chương trình để áp dụng chính sách cho đối tượng
# In hr.pyclassHourlyEmployee(Employee):def__init__(self,id,name,hours_worked,hour_rate):super().__init__(id,name)self.hours_worked=hours_workedself.hour_rate=hour_ratedefcalculate_payroll(self):returnself.hours_worked*self.hour_rate
4
Chương trình truy cập vào
# In hr.pyclassEmployee:def__init__(self,id,name):self.id=idself.name=name
66, được đặt tại chỉ mục
# In hr.pyclassEmployee:def__init__(self,id,name):self.id=idself.name=name
67, tạo đối tượng
# In hr.pyclassEmployee:def__init__(self,id,name):self.id=idself.name=name
47 được gọi, thay đổi được phản ánh. Bạn có thể chạy chương trình để đánh giá đầu ra
# In hr.pyclassHourlyEmployee(Employee):def__init__(self,id,name,hours_worked,hour_rate):super().__init__(id,name)self.hours_worked=hours_workedself.hour_rate=hour_ratedefcalculate_payroll(self):returnself.hours_worked*self.hour_rate
5
Số tiền séc cho nhân viên Kevin Bacon, là nhân viên bán hàng, hiện là $1080 thay vì $1800. Đó là vì
# In hr.pyclassEmployee:def__init__(self,id,name):self.id=idself.name=name
49 đã được áp dụng cho tiền lương
Như bạn có thể thấy, bạn có thể hỗ trợ các thay đổi chỉ bằng cách thêm một chính sách mới và sửa đổi một vài giao diện. Đây là loại linh hoạt mà thiết kế chính sách dựa trên thành phần mang lại cho bạn
Lựa chọn giữa Kế thừa và Thành phần trong Python
Python, với tư cách là một ngôn ngữ lập trình hướng đối tượng, hỗ trợ cả kế thừa và thành phần. Bạn đã thấy rằng kế thừa được sử dụng tốt nhất để mô hình hóa một mối quan hệ, trong khi các mô hình thành phần a có một mối quan hệ
Đôi khi, thật khó để biết mối quan hệ giữa hai lớp nên như thế nào, nhưng bạn có thể làm theo các hướng dẫn sau
Sử dụng tính kế thừa đối với thành phần trong Python để mô hình hóa mối quan hệ rõ ràng. Đầu tiên, chứng minh mối quan hệ giữa lớp dẫn xuất và cơ sở của nó. Then, reverse the relationship and try to justify it. Nếu bạn có thể biện minh cho mối quan hệ theo cả hai hướng, thì bạn không nên sử dụng tính kế thừa giữa chúng
Sử dụng tính kế thừa trên thành phần trong Python để tận dụng cả giao diện và triển khai của lớp cơ sở
Sử dụng tính kế thừa đối với thành phần trong Python để cung cấp các tính năng mixin cho một số lớp không liên quan khi chỉ có một triển khai tính năng đó
Sử dụng thành phần thay vì thừa kế trong Python để mô hình hóa mối quan hệ thúc đẩy việc triển khai lớp thành phần
Sử dụng thành phần thay vì thừa kế trong Python để tạo các thành phần có thể được sử dụng lại bởi nhiều lớp trong các ứng dụng Python của bạn
Sử dụng thành phần thay vì thừa kế trong Python để triển khai các nhóm hành vi và chính sách có thể được áp dụng thay thế cho các lớp khác để tùy chỉnh hành vi của chúng
Sử dụng thành phần thay vì thừa kế trong Python để cho phép thay đổi hành vi trong thời gian chạy mà không ảnh hưởng đến các lớp hiện có
Phần kết luận
Bạn đã khám phá tính kế thừa và thành phần trong Python. Bạn đã học về loại mối quan hệ mà thừa kế và thành phần tạo ra. Bạn cũng đã trải qua một loạt bài tập để hiểu cách kế thừa và thành phần được triển khai trong Python
Trong bài viết này, bạn đã học cách
Sử dụng tính kế thừa để thể hiện một mối quan hệ giữa hai lớp
Đánh giá nếu thừa kế là mối quan hệ đúng
Sử dụng đa kế thừa trong Python và đánh giá MRO của Python để khắc phục sự cố đa kế thừa
Mở rộng các lớp với mixin và sử dụng lại việc triển khai chúng
Sử dụng thành phần để thể hiện một mối quan hệ giữa hai lớp
Cung cấp các thiết kế linh hoạt bằng cách sử dụng thành phần
Sử dụng lại mã hiện có thông qua thiết kế chính sách dựa trên thành phần
đề xuất đọc
Dưới đây là một số sách và bài viết khám phá sâu hơn về thiết kế hướng đối tượng và có thể hữu ích để giúp bạn hiểu cách sử dụng chính xác tính kế thừa và thành phần trong Python hoặc các ngôn ngữ khác
mẫu thiết kế. Các yếu tố của phần mềm hướng đối tượng tái sử dụng
Các mẫu thiết kế đầu tiên. Hướng dẫn thân thiện với não bộ
Mã sạch. Sổ tay thủ công phần mềm linh hoạt
Nguyên tắc RẮN
Nguyên tắc thay thế Liskov
Đánh dấu là đã hoàn thành
Xem ngay Hướng dẫn này có một khóa học video liên quan do nhóm Real Python tạo. Xem nó cùng với hướng dẫn bằng văn bản để hiểu sâu hơn. Kế thừa và thành phần. Hướng dẫn OOP Python
🐍 Thủ thuật Python 💌
Nhận một Thủ thuật Python ngắn và hấp dẫn được gửi đến hộp thư đến của bạn vài ngày một lần. Không có thư rác bao giờ. Hủy đăng ký bất cứ lúc nào. Được quản lý bởi nhóm Real Python
Gửi cho tôi thủ thuật Python »
Giới thiệu về Isaac Rodríguez
Xin chào, tôi là Isaac. Tôi xây dựng, lãnh đạo và cố vấn cho các nhóm phát triển phần mềm và trong vài năm qua, tôi đã tập trung vào các dịch vụ đám mây và ứng dụng phụ trợ bằng Python cùng với các ngôn ngữ khác. Rất thích nghe từ bạn ở đây tại Real Python
» Thông tin thêm về Y-sác
Mỗi hướng dẫn tại Real Python được tạo bởi một nhóm các nhà phát triển để nó đáp ứng các tiêu chuẩn chất lượng cao của chúng tôi. Các thành viên trong nhóm đã làm việc trong hướng dẫn này là
Alex
Aldren
Joanna
Bậc thầy Kỹ năng Python trong thế giới thực Với quyền truy cập không giới hạn vào Python thực
Tham gia với chúng tôi và có quyền truy cập vào hàng nghìn hướng dẫn, khóa học video thực hành và cộng đồng các Pythonistas chuyên gia
Nâng cao kỹ năng Python của bạn »
Master Real-World Python Skills
Với quyền truy cập không giới hạn vào Python thực
Tham gia với chúng tôi và có quyền truy cập vào hàng ngàn hướng dẫn, khóa học video thực hành và cộng đồng Pythonistas chuyên gia
Nâng cao kỹ năng Python của bạn »
What Do You Think?
Đánh giá bài viết này
Tweet Chia sẻ Chia sẻ Email
Bài học số 1 hoặc điều yêu thích mà bạn đã học được là gì?
Commenting Tips. Những nhận xét hữu ích nhất là những nhận xét được viết với mục đích học hỏi hoặc giúp đỡ các sinh viên khác. and get answers to common questions in our support portal
What are the types of inheritance in Python?
Types of inheritance. There are five types of inheritance in python programming. .
1). thừa kế duy nhất
2). Multiple inheritances
3). Multilevel inheritance
4). Hierarchical inheritance
5). Hybrid inheritance
How many inheritance are there in Python?
Depending upon the number of child and parent classes involved, there are four types of inheritance in python.
What is inheritance with example in Python?
Mối quan hệ kế thừa xác định các lớp kế thừa từ các lớp khác dưới dạng lớp dẫn xuất, lớp con hoặc lớp con . Base class remains to be the source from which a subclass inherits. Ví dụ: bạn có lớp Cơ sở là “Động vật” và “Sư tử” là lớp Dẫn xuất. Quyền thừa kế sẽ là Sư tử là một con vật.