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
Đến cuối bài viết này, bạn sẽ biết cách
- Sử dụng thừa kế trong Python
- 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
Kế thừa và Thành phần là gì?
Kế thừa và thành phần là hai khái niệm chính trong lập trình hướng đối tượng, mô hình hóa mối quan hệ giữa hai lớp. Họ thúc đẩy thiết kế của một ứng dụng và xác định cách ứng dụng sẽ phát triển khi các tính năng mới được thêm vào hoặc các yêu cầu thay đổi
Cả hai đều cho phép tái sử dụng mã, nhưng chúng thực hiện theo những cách khác nhau
Loại bỏ các quảng cáoKế thừa là gì?
Các mô hình thừa kế cái được gọi là một mối quan hệ. Điều này có nghĩa là khi bạn có một lớp
# In hr.py
class HourlyEmployee[Employee]:
def __init__[self, id, name, hours_worked, hour_rate]:
super[].__init__[id, name]
self.hours_worked = hours_worked
self.hour_rate = hour_rate
def calculate_payroll[self]:
return self.hours_worked * self.hour_rate
6 kế thừa từ một lớp # In hr.py
class HourlyEmployee[Employee]:
def __init__[self, id, name, hours_worked, hour_rate]:
super[].__init__[id, name]
self.hours_worked = hours_worked
self.hour_rate = hour_rate
def calculate_payroll[self]:
return self.hours_worked * self.hour_rate
7, bạn đã tạo một mối quan hệ trong đó # In hr.py
class HourlyEmployee[Employee]:
def __init__[self, id, name, hours_worked, hour_rate]:
super[].__init__[id, name]
self.hours_worked = hours_worked
self.hour_rate = hour_rate
def calculate_payroll[self]:
return self.hours_worked * self.hour_rate
6 là một phiên bản đặc biệt của # In hr.py
class HourlyEmployee[Employee]:
def __init__[self, id, name, hours_worked, hour_rate]:
super[].__init__[id, name]
self.hours_worked = hours_worked
self.hour_rate = hour_rate
def calculate_payroll[self]:
return self.hours_worked * self.hour_rate
7Tính kế thừa được biểu diễn bằng Ngôn ngữ mô hình hóa thống nhất hoặc UML theo cách sau
Các lớp được biểu diễn dưới dạng các hộp có tên lớp ở trên cùng. Mối quan hệ thừa kế được biểu diễn bằng mũi tên từ lớp dẫn xuất trỏ đến lớp cơ sở. Từ kéo dài thường được thêm vào mũi tên
Ghi chú. Trong quan hệ thừa kế
- Các lớp kế thừa từ một lớp khác được gọi là lớp dẫn xuất, lớp con hoặc kiểu con
- Các lớp mà các lớp khác được dẫn xuất từ đó được gọi là các lớp cơ sở hoặc siêu lớp
- Một lớp dẫn xuất được cho là kế thừa, kế thừa hoặc mở rộng một lớp cơ sở
Giả sử bạn có một lớp cơ sở
# In hr.py
class CommissionEmployee[SalaryEmployee]:
def __init__[self, id, name, weekly_salary, commission]:
super[].__init__[id, name, weekly_salary]
self.commission = commission
def calculate_payroll[self]:
fixed = super[].calculate_payroll[]
return fixed + self.commission
0 và bạn lấy từ nó để tạo một lớp # In hr.py
class CommissionEmployee[SalaryEmployee]:
def __init__[self, id, name, weekly_salary, commission]:
super[].__init__[id, name, weekly_salary]
self.commission = commission
def calculate_payroll[self]:
fixed = super[].calculate_payroll[]
return fixed + self.commission
1. Mối quan hệ thừa kế nói rằng một # In hr.py
class CommissionEmployee[SalaryEmployee]:
def __init__[self, id, name, weekly_salary, commission]:
super[].__init__[id, name, weekly_salary]
self.commission = commission
def calculate_payroll[self]:
fixed = super[].calculate_payroll[]
return fixed + self.commission
1 là một # In hr.py
class CommissionEmployee[SalaryEmployee]:
def __init__[self, id, name, weekly_salary, commission]:
super[].__init__[id, name, weekly_salary]
self.commission = commission
def calculate_payroll[self]:
fixed = super[].calculate_payroll[]
return fixed + self.commission
0. Điều này có nghĩa là # In hr.py
class CommissionEmployee[SalaryEmployee]:
def __init__[self, id, name, weekly_salary, commission]:
super[].__init__[id, name, weekly_salary]
self.commission = commission
def calculate_payroll[self]:
fixed = super[].calculate_payroll[]
return fixed + self.commission
1 kế thừa giao diện và triển khai của # In hr.py
class CommissionEmployee[SalaryEmployee]:
def __init__[self, id, name, weekly_salary, commission]:
super[].__init__[id, name, weekly_salary]
self.commission = commission
def calculate_payroll[self]:
fixed = super[].calculate_payroll[]
return fixed + self.commission
0, và các đối tượng # In hr.py
class CommissionEmployee[SalaryEmployee]:
def __init__[self, id, name, weekly_salary, commission]:
super[].__init__[id, name, weekly_salary]
self.commission = commission
def calculate_payroll[self]:
fixed = super[].calculate_payroll[]
return fixed + self.commission
1 có thể được sử dụng để thay thế các đối tượng # In hr.py
class CommissionEmployee[SalaryEmployee]:
def __init__[self, id, name, weekly_salary, commission]:
super[].__init__[id, name, weekly_salary]
self.commission = commission
def calculate_payroll[self]:
fixed = super[].calculate_payroll[]
return fixed + self.commission
0 trong ứng dụngĐiều này được gọi là nguyên tắc thay thế Liskov. Nguyên tắc nói rằng “trong một chương trình máy tính, nếu
# In hr.py
class CommissionEmployee[SalaryEmployee]:
def __init__[self, id, name, weekly_salary, commission]:
super[].__init__[id, name, weekly_salary]
self.commission = commission
def calculate_payroll[self]:
fixed = super[].calculate_payroll[]
return fixed + self.commission
8 là một kiểu phụ của # In hr.py
class CommissionEmployee[SalaryEmployee]:
def __init__[self, id, name, weekly_salary, commission]:
super[].__init__[id, name, weekly_salary]
self.commission = commission
def calculate_payroll[self]:
fixed = super[].calculate_payroll[]
return fixed + self.commission
9, thì các đối tượng kiểu # In hr.py
class CommissionEmployee[SalaryEmployee]:
def __init__[self, id, name, weekly_salary, commission]:
super[].__init__[id, name, weekly_salary]
self.commission = commission
def calculate_payroll[self]:
fixed = super[].calculate_payroll[]
return fixed + self.commission
9 có thể được thay thế bằng các đối tượng kiểu # In hr.py
class CommissionEmployee[SalaryEmployee]:
def __init__[self, id, name, weekly_salary, commission]:
super[].__init__[id, name, weekly_salary]
self.commission = commission
def calculate_payroll[self]:
fixed = super[].calculate_payroll[]
return fixed + 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. Điều này có nghĩa là một lớp
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
02 có thể chứa một đối tượng của một lớp khác >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
03. Mối quan hệ này có nghĩa là một >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
02 có một >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
03UML đại diện cho thành phần như sau
Thành phần được thể hiện thông qua một đường có hình thoi tại lớp tổng hợp trỏ đến lớp thành phần. Mặt tổng hợp có thể thể hiện bản chất của mối quan hệ. Bản số cho biết số lượng hoặc phạm vi hợp lệ của các thể hiện
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
03 mà lớp >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
02 sẽ chứaTrong sơ đồ trên,
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
08 biểu thị rằng lớp >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
02 chứa một đối tượng thuộc loại >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
03. Cardinality có thể được thể hiện theo những cách sau- Một số cho biết số lượng phiên bản
03 có trong>>> c = MyClass[] >>> dir[c] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
02>>> c = MyClass[] >>> dir[c] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
- Biểu tượng * chỉ ra rằng lớp
02 có thể chứa một số lượng biến thể của>>> c = MyClass[] >>> dir[c] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
03>>> c = MyClass[] >>> dir[c] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
- Một phạm vi 1. 4 chỉ ra rằng lớp
02 có thể chứa một loạt các phiên bản>>> c = MyClass[] >>> dir[c] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
03. Phạm vi được chỉ định với số lượng phiên bản tối thiểu và tối đa hoặc tối thiểu và nhiều phiên bản như trong 1. *>>> c = MyClass[] >>> dir[c] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
Ghi chú. Các lớp chứa các đối tượng của các lớp khác thường được gọi là các lớp tổng hợp, trong đó các lớp được sử dụng để tạo các loại phức tạp hơn được gọi là các thành phần
Ví dụ: lớp
# In hr.py
class CommissionEmployee[SalaryEmployee]:
def __init__[self, id, name, weekly_salary, commission]:
super[].__init__[id, name, weekly_salary]
self.commission = commission
def calculate_payroll[self]:
fixed = super[].calculate_payroll[]
return fixed + 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 >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
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.py
class CommissionEmployee[SalaryEmployee]:
def __init__[self, id, name, weekly_salary, commission]:
super[].__init__[id, name, weekly_salary]
self.commission = commission
def calculate_payroll[self]:
fixed = super[].calculate_payroll[]
return fixed + self.commission
1 có một >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
18Thà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.py
class CommissionEmployee[SalaryEmployee]:
def __init__[self, id, name, weekly_salary, commission]:
super[].__init__[id, name, weekly_salary]
self.commission = commission
def calculate_payroll[self]:
fixed = super[].calculate_payroll[]
return fixed + self.commission
1 và lớp >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
22 đều có thể tận dụng chức năng của lớp >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
18 thông qua thành phần mà không cần lấy lớp này từ lớp kiaTổ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ì
Loại bỏ các quảng cáoSiêu lớp đối tượng
Cách dễ nhất để xem tính kế thừa trong Python là nhảy vào và viết một chút mã. Bạn sẽ bắt đầu bằng cách viết lớp đơn giản nhất có thể
>>>
>>> class MyClass:
.. pass
...
Bạn đã khai báo một lớp
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
24 không làm được gì nhiều, nhưng nó sẽ minh họa các khái niệm kế thừa cơ bản nhất. Bây giờ bạn đã khai báo lớp, bạn có thể sử dụng hàm >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
25 để liệt kê các thành viên của nó>>>
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
trả về danh sách tất cả các thành viên trong đối tượng được chỉ định. Bạn chưa khai báo bất kỳ thành viên nào trong
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
24, vậy danh sách này đến từ đâu? >>>
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
Như bạn có thể thấy, hai danh sách gần như giống hệt nhau. Có một số thành viên bổ sung trong lớp
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
24 như >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
29 và >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
30, nhưng mọi thành viên của lớp >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
31 cũng có mặt trong lớp >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
24Điều này là do mọi lớp bạn tạo trong Python đều bắt nguồn hoàn toàn từ
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
31. Bạn có thể viết rõ ràng hơn và viết >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
34, nhưng nó dư thừa và không cần thiếtGhi chú. Trong Python 2, bạn phải bắt nguồn rõ ràng từ
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
31 vì những lý do nằm ngoài phạm vi của bài viết này, nhưng bạn có thể đọc về nó trong phần tài liệu Python 2Ngoại lệ là một ngoại lệ
Mỗi lớp mà bạn tạo bằng Python sẽ ngầm định xuất phát từ
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
31. Ngoại lệ đối với quy tắc này là các lớp được sử dụng để chỉ ra lỗi bằng cách đưa ra một ngoại lệBạn có thể thấy sự cố khi sử dụng trình thông dịch tương tác Python
>>>
>>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
Bạn đã tạo một lớp mới để chỉ ra một loại lỗi. Sau đó, bạn đã cố gắng sử dụng nó để đưa ra một ngoại lệ. Một ngoại lệ được đưa ra nhưng đầu ra cho biết rằng ngoại lệ đó thuộc loại
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
37 không phải >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
38 và tất cả là >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
39>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
40 là lớp cơ sở được cung cấp cho tất cả các loại lỗi. Để tạo một loại lỗi mới, bạn phải dẫn xuất lớp của mình từ >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
40 hoặc một trong các lớp dẫn xuất của nó. Quy ước trong Python là lấy các loại lỗi tùy chỉnh của bạn từ >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
42, từ đó bắt nguồn từ >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
40Cách chính xác để xác định loại lỗi của bạn là như sau
>>>
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
Như bạn có thể thấy, khi bạn đưa ra
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
38, đầu ra cho biết chính xác loại lỗi được đưa raTạo phân cấp lớp
Kế thừa là cơ chế bạn sẽ sử dụng để tạo phân cấp của các lớp liên quan. Các lớp liên quan này sẽ chia sẻ một giao diện chung sẽ được định nghĩa trong các lớp cơ sở. Các lớp dẫn xuất có thể chuyên biệt hóa giao diện bằng cách cung cấp một triển khai cụ thể khi áp dụng
Trong phần này, bạn sẽ bắt đầu lập mô hình hệ thống nhân sự. Ví dụ này sẽ chứng minh việc sử dụng tính kế thừa và cách các lớp dẫn xuất có thể cung cấp triển khai cụ thể của giao diện lớp cơ sở
Hệ thống nhân sự cần xử lý bảng lương cho nhân viên của công ty, nhưng có nhiều loại nhân viên khác nhau tùy thuộc vào cách tính lương của họ
Bạn bắt đầu bằng cách triển khai một lớp
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
45 xử lý bảng lương# In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
45 thực hiện một phương pháp >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
47 lấy một tập hợp các nhân viên và in >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
48, >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
49 của họ và kiểm tra số lượng bằng cách sử dụng phương pháp >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
47 hiển thị trên từng đối tượng nhân viênBây giờ, bạn triển khai lớp cơ sở
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 xử lý giao diện chung cho mọi loại nhân viên# In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 là lớp cơ sở cho tất cả các loại nhân viên. Nó được xây dựng với một >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
48 và một >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
49. Những gì bạn đang nói là mọi >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 phải có một >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
48 được chỉ định cũng như một cái tênHệ thống nhân sự yêu cầu mọi
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 được xử lý phải cung cấp giao diện >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
47 trả về tiền lương hàng tuần cho nhân viên. Việc triển khai giao diện đó khác nhau tùy thuộc vào loại >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51Ví 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.py
class SalaryEmployee[Employee]:
def __init__[self, id, name, weekly_salary]:
super[].__init__[id, name]
self.weekly_salary = weekly_salary
def calculate_payroll[self]:
return self.weekly_salary
Bạn tạo một lớp dẫn xuất
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
60 kế thừa >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51. Lớp được khởi tạo với >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
48 và >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
49 theo yêu cầu của lớp cơ sở và bạn sử dụng >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
64 để khởi tạo các thành viên của lớp cơ sở. Bạn có thể đọc tất cả về >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
64 trong Supercharge Your Classs With Python super[]>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
60 cũng yêu cầu tham số khởi tạo >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
67 đại diện cho số tiền mà nhân viên kiếm được mỗi tuầnLớp cung cấp phương pháp
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
47 bắt buộc được sử dụng bởi hệ thống nhân sự. Việc triển khai chỉ trả về số tiền được lưu trữ trong >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
67Công ty cũng sử dụng công nhân sản xuất được trả lương theo giờ, vì vậy bạn thêm một số
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
70 vào hệ thống nhân sự# In hr.py
class HourlyEmployee[Employee]:
def __init__[self, id, name, hours_worked, hour_rate]:
super[].__init__[id, name]
self.hours_worked = hours_worked
self.hour_rate = hour_rate
def calculate_payroll[self]:
return self.hours_worked * self.hour_rate
Lớp
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
70 được khởi tạo với >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
48 và >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
49, giống như lớp cơ sở, cộng với >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
74 và >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
75 cần thiết để tính bảng lương. Phương pháp >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
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
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
77# In hr.py
class CommissionEmployee[SalaryEmployee]:
def __init__[self, id, name, weekly_salary, commission]:
super[].__init__[id, name, weekly_salary]
self.commission = commission
def calculate_payroll[self]:
fixed = super[].calculate_payroll[]
return fixed + self.commission
Bạn lấy được
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
77 từ >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
60 vì cả hai lớp đều có một >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
67 để xem xét. Đồng thời, >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
77 được khởi tạo với giá trị >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
82 dựa trên doanh số bán hàng cho nhân viên>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
47 tận dụng việc triển khai lớp cơ sở để truy xuất mức lương >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
84 và thêm giá trị hoa hồngSince
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
77 derives from >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
60, you have access to the >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
67 property directly, and you could’ve implemented >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
47 using the value of that propertyThe problem with accessing the property directly is that if the implementation of
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
89 changes, then you’ll have to also change the implementation of >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
90. It’s better to rely on the already implemented method in the base class and extend the functionality as neededYou created your first class hierarchy for the system. The UML diagram of the classes looks like this
The diagram shows the inheritance hierarchy of the classes. The derived classes implement the
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
91 interface, which is required by the >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
45. The >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
93 implementation requires that the >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
94 objects passed contain an >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
48, >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
49, and >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
97 implementationInterfaces are represented similarly to classes with the word interface above the interface name. Interface names are usually prefixed with a capital
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
98The application creates its employees and passes them to the payroll system to process payroll
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
0You can run the program in the command line and see the results
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
1The program creates three employee objects, one for each of the derived classes. Then, it creates the payroll system and passes a list of the employees to its
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
47 method, which calculates the payroll for each employee and prints the resultsNotice how the
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 base class doesn’t define a >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
47 method. This means that if you were to create a plain >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 object and pass it to the >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
45, then you’d get an error. You can try it in the Python interactive interpreter>>>
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
2While you can instantiate an
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 object, the object can’t be used by the >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
45. Why? Because it can’t >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
47 for an >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51. To meet the requirements of >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
45, you’ll want to convert the >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 class, which is currently a concrete class, to an abstract class. That way, no employee is ever just an >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51, but one that implements >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
47Loại bỏ các quảng cáoAbstract Base Classes in Python
The
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 class in the example above is what is called an abstract base class. Abstract base classes exist to be inherited, but never instantiated. Python provides the >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
13 module to define abstract base classesYou can use leading underscores in your class name to communicate that objects of that class should not be created. Underscores provide a friendly way to prevent misuse of your code, but they don’t prevent eager users from creating instances of that class
The in the Python standard library provides functionality to prevent creating objects from abstract base classes
You can modify the implementation of the
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 class to ensure that it can’t be instantiated>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
3You derive
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 from >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
17, making it an abstract base class. Then, you decorate the >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
47 method with the >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
19 decoratorThis change has two nice side-effects
- You’re telling users of the module that objects of type
51 can’t be created>>> c = MyClass[] >>> dir[c] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
- You’re telling other developers working on the
21 module that if they derive from>>> o = object[] >>> dir[o] ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
51, then they must override the>>> c = MyClass[] >>> dir[c] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
47 abstract method>>> c = MyClass[] >>> dir[c] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
You can see that objects of type
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 can’t be created using the interactive interpreter>>>
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
4The output shows that the class cannot be instantiated because it contains an abstract method
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
97. Derived classes must override the method to allow creating objects of their typeImplementation Inheritance vs Interface Inheritance
When you derive one class from another, the derived class inherits both
Giao diện lớp cơ sở. The derived class inherits all the methods, properties, and attributes of the base class
The base class implementation. The derived class inherits the code that implements the class interface
Most of the time, you’ll want to inherit the implementation of a class, but you will want to implement multiple interfaces, so your objects can be used in different situations
Modern programming languages are designed with this basic concept in mind. They allow you to inherit from a single class, but you can implement multiple interfaces
In Python, you don’t have to explicitly declare an interface. Any object that implements the desired interface can be used in place of another object. This is known as . Duck typing is usually explained as “if it behaves like a duck, then it’s a duck. ”
To illustrate this, you will now add a
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
26 class to the example above which doesn’t derive from >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
5The
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
26 class doesn’t derive from >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51, but it exposes the same interface required by the >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
45. The >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
93 requires a list of objects that implement the following interface- An
48 property or attribute that returns the employee’s id>>> c = MyClass[] >>> dir[c] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
- A
49 property or attribute that represents the employee’s name>>> c = MyClass[] >>> dir[c] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
- A
47 method that doesn’t take any parameters and returns the payroll amount to process>>> c = MyClass[] >>> dir[c] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
All these requirements are met by the
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
26 class, so the >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
45 can still calculate its payrollYou can modify the program to use the
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
26 class>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
6The program creates a
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
26 object and adds it to the list processed by the >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
45. You can now run the program and see its output>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
7As you can see, the
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
45 can still process the new object because it meets the desired interfaceSince you don’t have to derive from a specific class for your objects to be reusable by the program, you may be asking why you should use inheritance instead of just implementing the desired interface. The following rules may help you
Use inheritance to reuse an implementation. Your derived classes should leverage most of their base class implementation. They must also model an is a relationship. A
41 class might also have an>>> o = object[] >>> dir[o] ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
48 and a>>> c = MyClass[] >>> dir[c] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
49, but a>>> c = MyClass[] >>> dir[c] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
41 is not an>>> o = object[] >>> dir[o] ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
51, so you should not use inheritance>>> c = MyClass[] >>> dir[c] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
Implement an interface to be reused. When you want your class to be reused by a specific part of your application, you implement the required interface in your class, but you don’t need to provide a base class, or inherit from another class
You can now clean up the example above to move onto the next topic. You can delete the
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
46 file and then modify the >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
21 module to its original state>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
8You removed the import of the
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
13 module since the >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 class doesn’t need to be abstract. You also removed the abstract >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
97 method from it since it doesn’t provide any implementationBasically, you are inheriting the implementation of the
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
48 and >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
49 attributes of the >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 class in your derived classes. Since >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
47 is just an interface to the >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
93 method, you don’t need to implement it in the >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 base classNotice how the
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
77 class derives from >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
60. This means that >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
77 inherits the implementation and interface of >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
60. You can see how the >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
90 method leverages the base class implementation because it relies on the result from >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
62 to implement its own versionLoại bỏ các quảng cáoThe Class Explosion Problem
If you are not careful, inheritance can lead you to a huge hierarchical structure of classes that is hard to understand and maintain. Đây được gọi là vấn đề bùng nổ lớp
Bạn đã bắt đầu xây dựng hệ thống phân cấp lớp gồm
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 loại được sử dụng bởi >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
45 để tính bảng lương. Bây giờ, bạn cần thêm một số chức năng cho các lớp đó để chúng có thể được sử dụng với >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
65 mới>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
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. They have a salary, but they also get commissions for sales
- Công nhân nhà máy. Họ sản xuất các sản phẩm cho công ty. They are paid by the hour
With those requirements, you start to see that
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 and its derived classes might belong somewhere other than the >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
21 module because now they’re also used by the >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
65You create an
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
70 module and move the classes there>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
9The implementation remains the same, but you move the classes to the
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
94 module. Now, you change your program to support the change>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
0You run the program and verify that it still works
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
1With everything in place, you start adding the new classes
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
2First, you add a
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
72 class that derives from >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
60. The class exposes a method >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
74 that will be used by the productivity system. The method takes the >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
75 the employee workedThen you add
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
76, >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
77, and >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
78 and then implement the >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
74 interface, so they can be used by the productivity systemNow, you can add the
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
80 class>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
3The class tracks employees in the
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
81 method that takes a list of employees and the number of hours to track. You can now add the productivity system to your program>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
4The program creates a list of employees of different types. The employee list is sent to the productivity system to track their work for 40 hours. Then the same list of employees is sent to the payroll system to calculate their payroll
You can run the program to see the output
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
5The program shows the employees working for 40 hours through the productivity system. Then it calculates and displays the payroll for each of the employees
The program works as expected, but you had to add four new classes to support the changes. As new requirements come, your class hierarchy will inevitably grow, leading to the class explosion problem where your hierarchies will become so big that they’ll be hard to understand and maintain
The following diagram shows the new class hierarchy
The diagram shows how the class hierarchy is growing. Additional requirements might have an exponential effect in the number of classes with this design
Loại bỏ các quảng cáoInheriting Multiple Classes
Python is one of the few modern programming languages that supports multiple inheritance. Multiple inheritance is the ability to derive a class from multiple base classes at the same time
Multiple inheritance has a bad reputation to the extent that most modern programming languages don’t support it. Instead, modern programming languages support the concept of interfaces. In those languages, you inherit from a single base class and then implement multiple interfaces, so your class can be re-used in different situations
This approach puts some constraints in your designs. You can only inherit the implementation of one class by directly deriving from it. You can implement multiple interfaces, but you can’t inherit the implementation of multiple classes
This constraint is good for software design because it forces you to design your classes with fewer dependencies on each other. You will see later in this article that you can leverage multiple implementations through composition, which makes software more flexible. This section, however, is about multiple inheritance, so let’s take a look at how it works
It turns out that sometimes temporary secretaries are hired when there is too much paperwork to do. The
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
82 class performs the role of a >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
76 in the context of the >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
65, but for payroll purposes, it is an >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
70Bạn nhìn vào thiết kế lớp học của bạn. It has grown a little bit, but you can still understand how it works. It seems you have two options
Derive from
76. Bạn có thể bắt nguồn từ>>> o = object[] >>> dir[o] ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
76 để kế thừa phương thức>>> o = object[] >>> dir[o] ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
88 cho vai trò, sau đó ghi đè phương thức>>> o = object[] >>> dir[o] ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
47 để triển khai nó dưới dạng>>> c = MyClass[] >>> dir[c] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
70>>> c = MyClass[] >>> dir[c] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
Xuất phát từ
70. Bạn có thể bắt nguồn từ>>> c = MyClass[] >>> dir[c] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
70 để kế thừa phương thức>>> c = MyClass[] >>> dir[c] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
47, sau đó ghi đè phương thức>>> c = MyClass[] >>> dir[c] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
88 để triển khai nó dưới dạng>>> o = object[] >>> dir[o] ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
76>>> o = object[] >>> dir[o] ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
Sau đó, bạn nhớ rằng Python hỗ trợ đa kế thừa, vì vậy bạn quyết định xuất phát từ cả
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
76 và >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
70>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
6Python cho phép bạn kế thừa từ hai lớp khác nhau bằng cách chỉ định chúng giữa dấu ngoặc đơn trong khai báo lớp
Bây giờ, bạn sửa đổi chương trình của mình để thêm nhân viên thư ký tạm thời mới
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
7Bạn chạy chương trình để kiểm tra
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
8Bạn nhận được một ngoại lệ nói rằng
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
99 đối số vị trí được mong đợi, nhưng >>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
00 đã được đưa raĐiều này là do bạn bắt nguồn từ
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
82 đầu tiên từ >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
76 và sau đó từ >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
70, vì vậy trình thông dịch đang cố gắng sử dụng >>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
04 để khởi tạo đối tượngĐược rồi, hãy đảo ngược nó
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
9Bây giờ, hãy chạy lại chương trình và xem điều gì sẽ xảy ra
>>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
0Bây giờ có vẻ như bạn đang thiếu một tham số
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
67, tham số này cần thiết để khởi tạo >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
76, nhưng tham số đó không có ý nghĩa trong ngữ cảnh của một >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
82 bởi vì nó là một >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
70Có thể thực hiện
>>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
09 sẽ giúp ích>>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
1Thử nó
>>> class MyError:
.. pass
...
>>> raise MyError[]
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
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
64 để xác định phương thức hoặc thuộc tính nào sẽ gọi. Bạn có thể tìm hiểu thêm về >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
64 trong Supercharge Your Classs With Python super[]Bạn có thể đánh giá MRO của lớp
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
82 bằng trình thông dịch tương tác>>>
>>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
3MRO 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
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
82Phương pháp
14 được gọi là>>> class MyError: .. pass ... >>> raise MyError[] Traceback [most recent call last]: File "", line 1, in TypeError: exceptions must derive from BaseException
Cuộc gọi
15 phù hợp với>>> class MyError: .. pass ... >>> raise MyError[] Traceback [most recent call last]: File "", line 1, in TypeError: exceptions must derive from BaseException
16>>> class MyError: .. pass ... >>> raise MyError[] Traceback [most recent call last]: File "", line 1, in TypeError: exceptions must derive from BaseException
70 cuộc gọi>>> c = MyClass[] >>> dir[c] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
18, mà MRO sẽ khớp với>>> class MyError: .. pass ... >>> raise MyError[] Traceback [most recent call last]: File "", line 1, in TypeError: exceptions must derive from BaseException
04, được kế thừa từ>>> class MyError: .. pass ... >>> raise MyError[] Traceback [most recent call last]: File "", line 1, in TypeError: exceptions must derive from BaseException
20>>> class MyError: .. pass ... >>> raise MyError[] Traceback [most recent call last]: File "", line 1, in TypeError: exceptions must derive from BaseException
Bởi vì các tham số không khớp, một ngoại lệ
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
37 được đưa raBạ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
>>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
22 như sau>>> class MyError:
.. pass
...
>>> raise MyError[]
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 đề
>>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
5Vấn đề bây giờ là vì bạn đã đảo ngược thứ tự thừa kế, MRO đang tìm phương pháp
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
47 của >>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
24 trước phương pháp trong >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
70. Bạn cần ghi đè >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
47 trong >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
82 và gọi triển khai đúng từ đó>>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
6Phương thức
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
97 gọi trực tiếp >>> class MyError:
.. pass
...
>>> raise MyError[]
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>>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
7Chươ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.
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
82 sử dụng đa thừa kế để dẫn xuất từ hai lớp mà cuối cùng cũng dẫn xuất từ >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51. Điều này khiến hai đường dẫn đến lớp cơ sở >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51, đây là điều bạn muốn tránh trong thiết kế của mìnhVấ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
Các lớp dẫn xuất
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 được sử dụng bởi hai hệ thống khác nhauHệ thống năng suất theo dõi năng suất của nhân viên
The payroll system that calculates the employee payroll
Đ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
>>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
8Mô-đun
>>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
34 triển khai lớp >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
65, cũng như các vai trò liên quan mà nó hỗ trợ. Các lớp triển khai giao diện >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
74 theo yêu cầu của hệ thống, nhưng chúng không bắt nguồn từ >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51Bạn có thể làm tương tự với mô-đun
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
21>>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
9Mô-đun
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
21 thực hiện >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
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ừ >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 nữaBây giờ bạn có thể thêm các lớp cần thiết vào mô-đun
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
94>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
0Mô-đun
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
70 nhập các chính sách và vai trò từ các mô-đun khác và triển khai các loại >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
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ạoLư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
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
72 và >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
76 giống hệt nhau. Ngoài ra, phần khởi tạo của >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
78 và >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
82 giống nhauBạn sẽ không muốn có kiểu sao chép mã này trong các thiết kế phức tạp hơn, vì vậy bạn phải cẩn thận khi thiết kế hệ thống phân cấp lớp
Đây là sơ đồ UML cho thiết kế mới
Sơ đồ hiển thị các mối quan hệ để xác định
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
76 và >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
82 bằng cách sử dụng đa thừa kế, nhưng tránh vấn đề kim cươngBạn có thể chạy chương trình và xem nó hoạt động như thế nào
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
1Bạ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
Loại bỏ các quảng cáoThà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
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51, bạn sẽ thấy rằng nó chứa hai thuộc tính
48 để xác định nhân viên>>> c = MyClass[] >>> dir[c] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
49 để chứa tên của nhân viên>>> c = MyClass[] >>> dir[c] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
Hai thuộc tính này là các đối tượng mà lớp
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 có. Do đó, bạn có thể nói rằng một >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 có một >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
48 và có một tênMột thuộc tính khác cho một
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 có thể là một >>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
58>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
2Bạ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
>>> class MyError:
.. pass
...
>>> raise MyError[]
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
>>> class MyError:
.. pass
...
>>> raise MyError[]
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 >>> class MyError:
.. pass
...
>>> raise MyError[]
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>>>
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
3Khi bạn
>>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
62 biến >>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
63, phương thức đặc biệt >>> class MyError:
.. pass
...
>>> raise MyError[]
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ạnBây giờ bạn có thể thêm
>>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
58 vào lớp >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 thông qua thành phần>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
4Bây giờ, bạn khởi tạo thuộc tính
>>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
63 thành >>> class MyError:
.. pass
...
>>> raise MyError[]
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 >>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
58 cho một >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51. Cũng lưu ý rằng không có tham chiếu nào trong mô-đun >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
94 đến mô-đun >>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
72Thà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
The UML diagram representing the relationship between
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 and >>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
58 looks like thisSơ đồ cho thấy mối quan hệ thành phần cơ bản giữa
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 và >>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
58Bây giờ bạn có thể sửa đổi lớp
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
45 để tận dụng thuộc tính >>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
63 trong >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
5Bạn kiểm tra xem đối tượng
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
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>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
6Bạn đã thêm một vài địa chỉ vào các đối tượng
>>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
81 và >>> class MyError:
.. pass
...
>>> raise MyError[]
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>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
7Lưu ý cách đầu ra bảng lương cho các đối tượng
>>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
81 và >>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
82 hiển thị địa chỉ nơi séc được gửiLớp
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 tận dụng việc triển khai lớp >>> class MyError:
.. pass
...
>>> raise MyError[]
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 >>> class MyError:
.. pass
...
>>> raise MyError[]
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 >>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
58 mà không ảnh hưởng đến lớp >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51Loại bỏ các quảng cáoThiết kế linh hoạt với bố cục
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
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
45 và >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
65Bạn có thể bắt đầu bằng cách triển khai chức năng của
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
65>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
8Lớp
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
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 >>> class MyError:
.. pass
...
>>> raise MyError[]
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ệ >>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
95 sẽ được đưa raNó cũng hiển thị chức năng trước đó trong phương pháp
>>> class MyError:
.. pass
...
>>> raise MyError[]
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
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
9Mỗi vai trò mà bạn đã triển khai đều cho thấy một
>>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
97 chiếm số lượng >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
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
Bây giờ, bạn có thể triển khai
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
45 cho ứng dụng# In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
0>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
45 lưu giữ cơ sở dữ liệu nội bộ về các chính sách trả lương cho từng nhân viên. Nó cho thấy một >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
01, được cung cấp cho một nhân viên >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
48, trả về chính sách trả lương của nó. Nếu một >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
48 được chỉ định không tồn tại trong hệ thống, thì phương thức này sẽ tạo ra một ngoại lệ >>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
95Việc triển khai
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
47 hoạt động giống như trước đây. Nó lấy danh sách nhân viên, tính bảng lương và in kết quảBây giờ bạn có thể thực hiện các lớp chính sách trả lương
# In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
1Trước tiên, bạn triển khai lớp
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
06 đóng vai trò là lớp cơ sở cho tất cả các chính sách trả lương. Lớp này theo dõi >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
74, phổ biến cho tất cả các chính sách trả lươngCác lớp chính sách khác bắt nguồn từ
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
06. Chúng tôi sử dụng tính kế thừa ở đây vì chúng tôi muốn tận dụng việc triển khai >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
06. Ngoài ra, >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
10, >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
11, và >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
12 là một >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
06>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
10 được khởi tạo với giá trị >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
67 sau đó được sử dụng trong >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
47. >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
11 được khởi tạo với >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
75 và triển khai >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
47 bằng cách tận dụng lớp cơ sở >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
74Lớp
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
12 bắt nguồn từ lớp >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
10 vì nó muốn kế thừa việc thực hiện của nó. Nó được khởi tạo với tham số >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
67, nhưng nó cũng yêu cầu tham số >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
24>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
24 được sử dụng để tính toán >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
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à >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
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ị >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
24>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
12 thực hiện phương pháp >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
47 bằng cách trước tiên tận dụng việc triển khai trong >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
10 và sau đó thêm hoa hồng được tính toánBây giờ bạn có thể thêm lớp
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
32 để quản lý địa chỉ nhân viên# In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
2Lớp
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
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 >>> class MyError:
.. pass
...
>>> raise MyError[]
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 >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
35 trả về địa chỉ của nhân viên được chỉ định >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
48. Nếu nhân viên >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
48 không tồn tại, thì nó sẽ tăng >>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
95Việc triển khai lớp
>>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
58 vẫn giống như trước đây>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
2Lớ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
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
70 và các lớp của nóBạn có thể bắt đầu bằng cách thực hiện một lớp
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
41# In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
4>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
41 theo dõi tất cả nhân viên trong công ty. Đối với mỗi nhân viên, nó theo dõi >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
48, >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
49 và >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
45. Nó có một phiên bản của >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
65, >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
45 và >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
32. Những trường hợp này được sử dụng để tạo nhân viênNó hiển thị một thuộc tính
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
49 trả về danh sách nhân viên. Các đối tượng >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 được tạo trong một phương thức nội bộ >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
51. Lưu ý rằng bạn không có các loại lớp học >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 khác nhau. Bạn chỉ cần triển khai một lớp >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 duy nhất# In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
5The
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 class is initialized with the >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
48, >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
49, and >>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
63 attributes. Nó cũng đòi hỏi năng suất >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
45 của nhân viên và chính sách >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
59Lớp đưa ra một phương pháp
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
88 mất nhiều giờ làm việc. Phương pháp này trước tiên truy xuất >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
61 từ >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
45. Nói cách khác, nó ủy quyền cho đối tượng >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
45 để thực hiện nhiệm vụ của mìnhTheo cách tương tự, nó ủy quyền cho đối tượng
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
59 để theo dõi công việc >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
75. >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
59, như bạn đã thấy, sử dụng số giờ đó để tính bảng lương nếu cầnSơ đồ sau đây cho thấy thiết kế thành phần được sử dụng
Sơ đồ cho thấy thiết kế của các chính sách dựa trên thành phần. Có một
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 duy nhất bao gồm các đối tượng dữ liệu khác như >>> class MyError:
.. pass
...
>>> raise MyError[]
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 >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
69 và >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
91 để ủy thác công việc. Có nhiều triển khai của các giao diện nàyBây giờ bạn có thể sử dụng thiết kế này trong chương trình của mình
# In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
6Bạn có thể chạy chương trình để xem đầu ra của nó
# In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
7Thiế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
Loại bỏ các quảng cáoTù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
>>> class MyError:
.. pass
...
>>> raise MyError[]
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# In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
8Chương trình lấy danh sách nhân viên từ
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
41 và lấy nhân viên đầu tiên, đó là người quản lý mà chúng tôi muốn. Sau đó, nó tạo một >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
11 mới được khởi tạo ở mức $55 mỗi giờ và gán nó cho đối tượng người quản lýChính sách mới hiện được sử dụng bởi
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
45 để sửa đổi hành vi hiện có. Bạn có thể chạy lại chương trình để xem kết quả# In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
9Tấ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.py
class HourlyEmployee[Employee]:
def __init__[self, id, name, hours_worked, hour_rate]:
super[].__init__[id, name]
self.hours_worked = hours_worked
self.hour_rate = hour_rate
def calculate_payroll[self]:
return self.hours_worked * self.hour_rate
6, kế thừa từ # In hr.py
class HourlyEmployee[Employee]:
def __init__[self, id, name, hours_worked, hour_rate]:
super[].__init__[id, name]
self.hours_worked = hours_worked
self.hour_rate = hour_rate
def calculate_payroll[self]:
return self.hours_worked * self.hour_rate
7, có thể thay thế một đối tượng kiểu # In hr.py
class HourlyEmployee[Employee]:
def __init__[self, id, name, hours_worked, hour_rate]:
super[].__init__[id, name]
self.hours_worked = hours_worked
self.hour_rate = hour_rate
def calculate_payroll[self]:
return self.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ìnhNguyên tắc thay thế 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
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
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 >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
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 >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
79 từ >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
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á
79 là một>>> class MyError[Exception]: .. pass ... >>> raise MyError[] 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?>>> class MyError[Exception]: .. pass ... >>> raise MyError[] Traceback [most recent call last]: File "", line 1, in __main__.MyError
Evaluate
78 is a>>> class MyError[Exception]: .. pass ... >>> raise MyError[] Traceback [most recent call last]: File "", line 1, in __main__.MyError
79. Reverse the relationship and justify it. Does it also make sense?>>> class MyError[Exception]: .. pass ... >>> raise MyError[] Traceback [most recent call last]: File "", line 1, in __main__.MyError
If you can justify both relationships, then you should never inherit those classes from one another. Let’s look at a more concrete example
You have a class
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
86 which exposes an >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
87 property. You need a class >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
88, which also has an >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
87. It seems that a >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
88 is a special type of >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
86, so maybe you can derive from it and leverage both the interface and implementationBefore you jump into the implementation, you use Liskov’s substitution principle to evaluate the relationship
A
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
88 is a >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
86 because its area is calculated from the product of its >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
94 times its >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
95. The constraint is that >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
96 and >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
97 must be equalIt makes sense. You can justify the relationship and explain why a
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
88 is a >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
86. Let’s reverse the relationship to see if it makes senseA
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
86 is a >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
88 because its area is calculated from the product of its >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
94 times its >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
95. The difference is that # In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
04 and # In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
05 can change independentlyIt also makes sense. You can justify the relationship and describe the special constraints for each class. This is a good sign that these two classes should never derive from each other
You might have seen other examples that derive
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
88 from >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
86 to explain inheritance. You might be skeptical with the little test you just did. Đủ công bằng. Hãy viết một chương trình minh họa vấn đề với việc dẫn xuất >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
88 từ >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
86Đầu tiên, bạn triển khai
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
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.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
0Lớp
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
86 được khởi tạo với một >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
95 và một >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
94, và nó cung cấp một thuộc tính >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
87 trả về diện tích. >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
95 và >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
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ếpBây giờ, bạn lấy được
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
88 từ >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
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 >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
88# In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
1Lớp
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
88 được khởi tạo với một # In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
21, được sử dụng để khởi tạo cả hai thành phần của lớp cơ sở. Bây giờ, bạn viết một chương trình nhỏ để kiểm tra hành vi# In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
2Chương trình tạo một
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
86 và một >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
88 và khẳng định rằng >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
87 của chúng được tính toán chính xác. Bạn có thể chạy chương trình và thấy rằng mọi thứ là # In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
25 cho đến nay# In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
3Chương trình thực thi chính xác, vì vậy có vẻ như
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
88 chỉ là trường hợp đặc biệt của >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
86Sau này, bạn cần hỗ trợ thay đổi kích thước đối tượng
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
86, vì vậy bạn thực hiện các thay đổi thích hợp cho lớp# In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
4# In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
29 lấy # In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
30 và # In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
31 cho đối tượng. Bạn có thể thêm đoạn mã sau vào chương trình để xác minh rằng nó hoạt động chính xác# In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
5Bạn thay đổi kích thước đối tượng hình chữ nhật và xác nhận rằng khu vực mới là chính xác. Bạn có thể chạy chương trình để xác minh hành vi
# In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
3Xác nhận vượt qua và bạn thấy rằng chương trình chạy chính xác
Vì vậy, điều gì sẽ xảy ra nếu bạn thay đổi kích thước một hình vuông?
# In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
7Bạn chuyển các tham số tương tự cho
# In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
33 mà bạn đã sử dụng với # In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
34 và in vùng. Khi bạn chạy chương trình, bạn sẽ thấy# In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
8Chương trình cho thấy diện tích mới là
# In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
35 giống như đối tượng # In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
34. Vấn đề bây giờ là đối tượng # In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
32 không còn đáp ứng ràng buộc của lớp >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
88 rằng >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
95 và >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
94 phải bằng nhauLàm thế nào bạn có thể khắc phục vấn đề đó? . Bạn có thể ghi đè
# In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
29 trong # In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
32 và bỏ qua tham số >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
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_______45Trong 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à
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
88 kế thừa giao diện và triển khai của # In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
29 từ >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
86. Điều đó không có nghĩa là các đối tượng >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
88 không thể thay đổi kích thước. Có nghĩa là giao diện khác vì nó chỉ cần tham số # In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
21Sự khác biệt trong giao diện này biện minh cho việc không bắt nguồn từ
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
88 từ >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
86 như bài kiểm tra đã khuyên ở trênLoại bỏ các quảng cáoTrộ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.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
53 trong mọi lớp mà bạn muốn hỗ trợ tính năng này, nhưng việc triển khai phương thức # In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
53 có vẻ rất giống nhauĐây có thể là một ứng cử viên sáng giá cho mixin. Bạn bắt đầu bằng cách sửa đổi một chút lớp
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 từ ví dụ thành phần# In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
9Sự thay đổi là rất nhỏ. Bạn vừa thay đổi các thuộc tính
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
45 và >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
59 thành nội bộ bằng cách thêm dấu gạch dưới ở đầu vào tên của chúng. Bạn sẽ sớm thấy tại sao bạn lại thực hiện thay đổi đóBây giờ, bạn thêm lớp
# In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
58# In hr.py
class SalaryEmployee[Employee]:
def __init__[self, id, name, weekly_salary]:
super[].__init__[id, name]
self.weekly_salary = weekly_salary
def calculate_payroll[self]:
return self.weekly_salary
0Lớp
# In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
58 hiển thị phương thức # In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
53 trả về biểu diễn của chính nó dưới dạng từ điển. Phương pháp này được triển khai dưới dạng hiểu # In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
61 có nội dung: “Tạo ánh xạ từ điển # In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
62 đến # In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
63 cho mỗi mục trong # In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
64 nếu # In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
62 không phải là nội bộ. ”Ghi chú. Đây là lý do tại sao chúng tôi tạo các thuộc tính vai trò và bảng lương bên trong lớp
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51, bởi vì chúng tôi không muốn đại diện cho chúng trong từ điểnNhư bạn đã thấy ở phần đầu, việc tạo một lớp kế thừa một số thành viên từ
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
31 và một trong những thành viên đó là >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
29, về cơ bản là ánh xạ tất cả các thuộc tính trong một đối tượng với giá trị của chúngBạn duyệt qua tất cả các mục trong
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
29 và lọc ra những mục có tên bắt đầu bằng dấu gạch dưới bằng cách sử dụng # In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
70# In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
71 kiểm tra giá trị được chỉ định. Nếu giá trị là một >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
31, thì nó sẽ xem liệu nó cũng có một thành viên # In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
53 hay không và sử dụng nó để đại diện cho đối tượng. Mặt khác, nó trả về một biểu diễn chuỗi. Nếu giá trị không phải là >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
31, thì nó chỉ trả về giá trịYou can modify the
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 class to support this mixin# In hr.py
class SalaryEmployee[Employee]:
def __init__[self, id, name, weekly_salary]:
super[].__init__[id, name]
self.weekly_salary = weekly_salary
def calculate_payroll[self]:
return self.weekly_salary
1Tất cả những gì bạn phải làm là kế thừa
# In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
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 >>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
58, vì vậy thuộc tính # In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
78 được biểu diễn theo cùng một cách# In hr.py
class SalaryEmployee[Employee]:
def __init__[self, id, name, weekly_salary]:
super[].__init__[id, name]
self.weekly_salary = weekly_salary
def calculate_payroll[self]:
return self.weekly_salary
2Bạn áp dụng mixin cho lớp
>>> class MyError:
.. pass
...
>>> raise MyError[]
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.py
class SalaryEmployee[Employee]:
def __init__[self, id, name, weekly_salary]:
super[].__init__[id, name]
self.weekly_salary = weekly_salary
def calculate_payroll[self]:
return self.weekly_salary
3Chương trình triển khai một
# In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
80 chuyển đổi từ điển thành chuỗi JSON bằng cách sử dụng thụt đầu dòng để đầu ra trông đẹp hơnSau đó, nó lặp qua tất cả các nhân viên, in biểu diễn từ điển được cung cấp bởi
# In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
53. Bạn có thể chạy chương trình để xem đầu ra của nó# In hr.py
class SalaryEmployee[Employee]:
def __init__[self, id, name, weekly_salary]:
super[].__init__[id, name]
self.weekly_salary = weekly_salary
def calculate_payroll[self]:
return self.weekly_salary
4Bạn đã tận dụng việc triển khai
# In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
58 trong cả hai lớp >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 và >>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
58 ngay cả khi chúng không liên quan. Bởi vì # In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
58 chỉ cung cấp hành vi, nó dễ dàng sử dụng lại với các lớp khác mà không gây ra vấn đềLoại bỏ các quảng cáoThành phần cho Mô hình Mối quan hệ “Có A”
Các mô hình thành phần a có mối quan hệ. Với thành phần, một lớp
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
02 có một thể hiện của lớp >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
03 và có thể tận dụng việc triển khai nó. Lớp >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
03 có thể được sử dụng lại trong các lớp khác hoàn toàn không liên quan đến lớp >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
02Trong ví dụ thành phần ở trên, lớp
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 có một đối tượng >>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
58. >>> class MyError:
.. pass
...
>>> raise MyError[]
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ácCác lớp khác như
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
41 hoặc # In hr.py
class PayrollSystem:
def calculate_payroll[self, employees]:
print['Calculating Payroll']
print['===================']
for employee in employees:
print[f'Payroll for: {employee.id} - {employee.name}']
print[f'- Check amount: {employee.calculate_payroll[]}']
print['']
94 có thể sử dụng lại >>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
58 mà không liên quan đến >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
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ụngMộ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
>>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
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 >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
51 để xây dựng một đối tượng >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 với các tham số phù hợpThiết kế này sẽ hoạt động, nhưng lý tưởng nhất là bạn có thể xây dựng một đối tượng
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 chỉ bằng cách chỉ định một >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
48, ví dụ như # In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
02Nhữ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
>>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
34# In hr.py
class SalaryEmployee[Employee]:
def __init__[self, id, name, weekly_salary]:
super[].__init__[id, name]
self.weekly_salary = weekly_salary
def calculate_payroll[self]:
return self.weekly_salary
5Đầu tiên, bạn tạo nội bộ lớp
# In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
04, sau đó cung cấp biến nội bộ # In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.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.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
04. Thay vào đó, bạn cung cấp hai chức năng, # In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
07 và >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
81, làm giao diện chung cho mô-đun. Đây là những gì các mô-đun khác nên sử dụngĐiều bạn đang nói là
# In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
04 là một Singleton và chỉ nên có một đối tượng được tạo từ nóBây giờ, bạn có thể làm tương tự với mô-đun
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
21# In hr.py
class SalaryEmployee[Employee]:
def __init__[self, id, name, weekly_salary]:
super[].__init__[id, name]
self.weekly_salary = weekly_salary
def calculate_payroll[self]:
return self.weekly_salary
6Một lần nữa, bạn tạo
# In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.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 cộng để lấy chính sách và tính lươngBây giờ bạn sẽ làm tương tự với mô-đun
>>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
72# In hr.py
class SalaryEmployee[Employee]:
def __init__[self, id, name, weekly_salary]:
super[].__init__[id, name]
self.weekly_salary = weekly_salary
def calculate_payroll[self]:
return self.weekly_salary
7Về cơ bản, bạn đang nói rằng chỉ nên có một
# In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
13, một # In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
11 và một # In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.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.Bây giờ, bạn có thể làm việc trên mô-đun
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
70. Bạn cũng sẽ thực hiện một Singleton trong số # In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
17, nhưng bạn sẽ thực hiện một số thay đổi bổ sung# In hr.py
class SalaryEmployee[Employee]:
def __init__[self, id, name, weekly_salary]:
super[].__init__[id, name]
self.weekly_salary = weekly_salary
def calculate_payroll[self]:
return self.weekly_salary
8Trướ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.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.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ụngBạn đã thay đổi thuộc tính
# In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
19 thành một từ điển trong đó khóa là nhân viên >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
48 và giá trị là thông tin nhân viên. Bạn cũng đã sử dụng một phương pháp # In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
21 để trả lại thông tin cho nhân viên được chỉ định # In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
22Thuộc tính
# In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
23 hiện sắp xếp chìa khóa để trả lại cho nhân viên được sắp xếp theo số >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
48 của họ. Bạn đã thay thế phương thức đã xây dựng các đối tượng >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 bằng các lệnh gọi trực tiếp tới bộ khởi tạo >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51Lớp
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 hiện được khởi tạo với lớp >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
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.py
class SalaryEmployee[Employee]:
def __init__[self, id, name, weekly_salary]:
super[].__init__[id, name]
self.weekly_salary = weekly_salary
def calculate_payroll[self]:
return self.weekly_salary
9Bạn nhập các hàm có liên quan từ các mô-đun
>>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
21 và >>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
34, cũng như lớp # In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
31 và >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51. Chương trình sạch hơn vì bạn đã hiển thị giao diện cần thiết và đóng gói cách các đối tượng được truy cậpLưu ý rằng bây giờ bạn có thể tạo một đối tượng
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 trực tiếp chỉ bằng cách sử dụng đối tượng >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
48 của nó. Bạn có thể chạy chương trình để xem đầu ra của nó# In hr.py
class HourlyEmployee[Employee]:
def __init__[self, id, name, hours_worked, hour_rate]:
super[].__init__[id, name]
self.hours_worked = hours_worked
self.hour_rate = hour_rate
def calculate_payroll[self]:
return self.hours_worked * self.hour_rate
0Chương trình hoạt động giống như trước, nhưng bây giờ bạn có thể thấy rằng một đối tượng
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 duy nhất có thể được tạo từ >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
48 của nó và hiển thị biểu diễn từ điển của nóXem kỹ lớp học
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51# In hr.py
class HourlyEmployee[Employee]:
def __init__[self, id, name, hours_worked, hour_rate]:
super[].__init__[id, name]
self.hours_worked = hours_worked
self.hour_rate = hour_rate
def calculate_payroll[self]:
return self.hours_worked * self.hour_rate
1Lớp
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
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 >>> class MyError:
.. pass
...
>>> raise MyError[]
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>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 cũng chứa vai trò năng suất do mô-đun >>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
34 cung cấp và chính sách trả lương do mô-đun >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
21 cung cấp. Hai đối tượng này cung cấp các triển khai được sử dụng bởi lớp >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 để theo dõi công việc theo phương thức >>> o = object[]
>>> dir[o]
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
88 và để tính bảng lương trong phương thức >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
47Bạn đang sử dụng bố cục theo hai cách khác nhau. Lớp
>>> class MyError:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
TypeError: exceptions must derive from BaseException
58 cung cấp dữ liệu bổ sung cho >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51 trong đó các đối tượng vai trò và bảng lương cung cấp hành vi bổ sungTuy nhiên, mối quan hệ giữa
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
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 theoThà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.py
class HourlyEmployee[Employee]:
def __init__[self, id, name, hours_worked, hour_rate]:
super[].__init__[id, name]
self.hours_worked = hours_worked
self.hour_rate = hour_rate
def calculate_payroll[self]:
return self.hours_worked * self.hour_rate
2Lưu ý rằng
# In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
49 không kế thừa >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
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 >>> class MyError[Exception]:
.. pass
...
>>> raise MyError[]
Traceback [most recent call last]:
File "", line 1, in
__main__.MyError
06# In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
49 khởi tạo # In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
53 thành >>> class MyError:
.. pass
...
>>> raise MyError[]
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.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
57 để chỉ định # In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
53Trước tiên, giao diện công khai kiểm tra xem
# In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.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.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
60 chỉ ủy quyền cho chính sách cơ sở và >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
47 sử dụng nó để tính toán # In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
62 và sau đó trả về 60%Bây giờ bạn có thể thực hiện một thay đổi nhỏ đối với lớp
>>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51# In hr.py
class HourlyEmployee[Employee]:
def __init__[self, id, name, hours_worked, hour_rate]:
super[].__init__[id, name]
self.hours_worked = hours_worked
self.hour_rate = hour_rate
def calculate_payroll[self]:
return self.hours_worked * self.hour_rate
3Bạn đã thêm một phương pháp
# In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.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 >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
51# In hr.py
class HourlyEmployee[Employee]:
def __init__[self, id, name, hours_worked, hour_rate]:
super[].__init__[id, name]
self.hours_worked = hours_worked
self.hour_rate = hour_rate
def calculate_payroll[self]:
return self.hours_worked * self.hour_rate
4Chương trình truy cập vào
# In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
66, được đặt tại chỉ mục # In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
67, tạo đối tượng # In hr.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
49 và áp dụng chính sách cho nhân viên. Khi >>> c = MyClass[]
>>> dir[c]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__']
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.py
class HourlyEmployee[Employee]:
def __init__[self, id, name, hours_worked, hour_rate]:
super[].__init__[id, name]
self.hours_worked = hours_worked
self.hour_rate = hour_rate
def calculate_payroll[self]:
return self.hours_worked * self.hour_rate
5Số 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.py
class Employee:
def __init__[self, id, name]:
self.id = id
self.name = name
49 đã được áp dụng cho tiền lươngNhư 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ó. Sau đó, đảo ngược mối quan hệ và cố gắng biện minh cho nó. 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
Use composition over inheritance in Python to enable run-time behavior changes without affecting existing classes
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ácMỗ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 »
Chuyên gia 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 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 »
Bạn nghĩ sao?
Đánh giá bài viết này
Tweet Chia sẻ Chia sẻ EmailBài học số 1 hoặc điều yêu thích mà bạn đã học được là gì?
Mẹo bình luận. The most useful comments are those written with the goal of learning from or helping out other students. và nhận câu trả lời cho các câu hỏi phổ biến trong cổng thông tin hỗ trợ của chúng tôi