Lập trình hướng đối tượng trong python datacamp github

"self" được trình thông dịch gán cho đối tượng hiện tại khi một phương thức được gọi và trình thông dịch mong đợi đối số đầu tiên của mỗi phương thức sẽ tính đến điều này

  • Ghi đè là thay đổi hoặc thay thế một phương thức của lớp cha bằng một phương thức mới (có cùng tên) trong lớp con. Không cần cú pháp đặc biệt để làm điều này;

  • Hàm super() trả về đối tượng như một thể hiện của lớp cha, cho phép chúng ta gọi trực tiếp phương thức cha

  • đa thừa kế. Một lớp con kế thừa từ nhiều hơn một lớp cha có thể truy cập chức năng từ cả hai lớp đó. Hình thức đa thừa kế đơn giản và hữu ích nhất được gọi là mixin. Một mixin nói chung là một siêu lớp không tồn tại riêng mà được kế thừa bởi một số lớp khác để cung cấp chức năng bổ sung

  • # Example
    class Contact:
    	#all_contacts = []
    	all_contacts = ContactList()
    	
    	def __init__(self, name, email):
    		self.name = name
    		self.email = email
    		#Contact.all_contacts.append(self)
    		self.all_contacts.append(self)
            
     class MailSender:
    	def send_mail(self, message):
    		print("sending mail to " + self.email)
            
    # multiple inheritance
    class EmailableContact(Contact, MailSender):
    	pass

    Cú pháp đa thừa kế trông giống như một danh sách tham số trong định nghĩa lớp. Thay vì bao gồm một lớp cơ sở bên trong dấu ngoặc đơn, chúng tôi bao gồm hai (hoặc nhiều hơn) được phân tách bằng dấu phẩy

    >>>e = EmailableContact("Test user ", "[email protected]")
    >>>e.send_mail("hello, test email here")
    Sending mail to [email protected]
    

    • Đa kế thừa hoạt động tốt khi trộn các phương thức từ các lớp khác nhau, nhưng sẽ rất lộn xộn khi chúng ta phải làm việc với các phương thức gọi trên lớp cha. Vì có nhiều lớp cha. Làm thế nào để chúng ta biết cái nào để gọi?

    Vấn đề kim cương

    • Nếu chúng ta có hai phương thức init gốc mà cả hai đều cần được khởi tạo và chúng cần được khởi tạo với các đối số khác nhau. làm sao chúng ta làm việc đó bây giờ?

    class Addressholder:
    	def __init__(self, street, city, state, code):
    		self.street = street
    		self.city = city
    		self.state = state
    		self.code = code
    	
    class Friend(Contact, Addressholder):
    	def __init__(self, name, email, phone, street, city, state, code):
    		Contact.__init__(self, name, email)
    		AddressHolder.__init__(self, street, city, state, code)
    		self.phone = phone

    Trong ví dụ này, chúng ta gọi trực tiếp hàm init trên mỗi lớp cha và chuyển đối số self một cách rõ ràng. Ví dụ này hoạt động về mặt kỹ thuật; chúng ta có thể truy cập các biến khác nhau trực tiếp trên lớp. Nhưng có một vài vấn đề

    1. Có khả năng một siêu lớp không được khởi tạo nếu chúng ta bỏ qua việc gọi trình khởi tạo một cách rõ ràng

    2. Khả năng siêu lớp được gọi nhiều lần, do tổ chức của hệ thống phân cấp lớp. Sơ đồ thừa kế bên dưới

    Lập trình hướng đối tượng trong python datacamp github

    Phương thức init từ lớp Friend trước tiên gọi init trên Contact để khởi tạo hoàn toàn siêu lớp đối tượng (tất cả các lớp bắt nguồn từ obejct). Sau đó, Friend gọi lệnh init trên AddressHolder, lệnh này ngầm khởi tạo lại siêu lớp đối tượng. Lớp cha đã được thiết lập hai lần. Hãy tưởng tượng cố gắng kết nối với cơ sở dữ liệu hai lần cho mọi yêu cầu. Lớp cơ sở chỉ nên được gọi một lần

    • Về mặt kỹ thuật, thứ tự mà các phương thức có thể được gọi có thể được điều chỉnh nhanh chóng bằng cách sửa đổi thuộc tính mro (Thứ tự phân giải phương thức) của lớp

    Hãy xem xét một ví dụ thứ hai minh họa vấn đề này rõ ràng hơn. Ở đây có một lớp cơ sở có một phương thức tên là call_me. Hai lớp con ghi đè phương thức đó và sau đó một lớp con khác mở rộng cả hai lớp này bằng cách sử dụng đa kế thừa. Điều này được gọi là kế thừa kim cương vì hình dạng kim cương của sơ đồ lớp

    Lập trình hướng đối tượng trong python datacamp github

    Kim cương là thứ khiến cho việc thừa kế trở nên khó khăn. Về mặt kỹ thuật, tất cả đa kế thừa trong Python3 là kế thừa kim cương, bởi vì tất cả các lớp đều kế thừa từ đối tượng

    class MyClass:
    
    	@classmethod                #<--use decorator to declare a class method
    	def my_method(cls, args..): #<--cls argument refers to the class
    		# execute
    		# can't use any instance attributes
    0

    class MyClass:
    
    	@classmethod                #<--use decorator to declare a class method
    	def my_method(cls, args..): #<--cls argument refers to the class
    		# execute
    		# can't use any instance attributes
    1

    Phương thức call_me của lớp cơ sở đã được gọi hai lần

    • Điều cần lưu ý với đa kế thừa là chúng ta chỉ muốn gọi phương thức "tiếp theo" trong hệ thống phân cấp lớp chứ không phải phương thức "cha". Trên thực tế, phương thức tiếp theo đó có thể không nằm trên cha hoặc tổ tiên của lớp hiện tại
    • Từ khóa "siêu" một lần nữa xuất hiện. Thật vậy, super ban đầu được phát triển để tạo ra các dạng đa kế thừa phức tạp. Đây là cùng một mã được viết bằng siêu

    class MyClass:
    
    	@classmethod                #<--use decorator to declare a class method
    	def my_method(cls, args..): #<--cls argument refers to the class
    		# execute
    		# can't use any instance attributes
    2

    class MyClass:
    
    	@classmethod                #<--use decorator to declare a class method
    	def my_method(cls, args..): #<--cls argument refers to the class
    		# execute
    		# can't use any instance attributes
    3

    • Phương thức cơ sở chỉ được gọi một lần. Call_me đầu tiên của Subclass gọi super(). call_me(), có liên quan đến LeftSubclass. gọi cho tôi(). Phân lớp bên trái. call_me() sau đó gọi super(). call_me(), nhưng trong trường hợp này, super() đang đề cập đến RightSubclass. gọi cho tôi()
    • Cuộc gọi super không gọi phương thức trên superclass của LeftSubclass (là Baseclass), nó đang gọi RightSubclass, mặc dù nó không phải là cha của LeftSubclass. Đây là phương thức tiếp theo, không phải phương thức cha. RightSubclass sau đó gọi BaseClass và siêu gọi đã đảm bảo mỗi phương thức trong hệ thống phân cấp lớp được thực thi một lần

    Quá tải toán tử. so sánh

    bình đẳng đối tượng

    class MyClass:
    
    	@classmethod                #<--use decorator to declare a class method
    	def my_method(cls, args..): #<--cls argument refers to the class
    		# execute
    		# can't use any instance attributes
    4

    • Trong trường hợp này, điều đó có thể hợp lý, vì chúng tôi có thể có 2 khách hàng có cùng tên và số dư tài khoản. Nhưng nếu khách hàng có một số id duy nhất thì sao. Sau đó, 2 khách hàng có cùng ID sẽ được coi là bình đẳng, nhưng họ không
    • Lý do tại sao Python không coi hai đối tượng có cùng dữ liệu bằng nhau theo mặc định liên quan đến cách đối tượng và các biến đại diện cho chúng được lưu trữ. Nếu chúng tôi cố gắng chỉ in giá trị của đối tượng khách hàng, chúng tôi có thể thấy các địa chỉ khác nhau
    • Python lưu trữ các tham chiếu đến dữ liệu tại các địa chỉ này. Vì vậy, khi chúng ta so sánh 2 đối tượng, chúng ta đang so sánh 2 tham chiếu chứ không phải dữ liệu. Bcz khách hàng1 và khách hàng2 trỏ đến các khối khác nhau trong bộ nhớ, chúng không được coi là bằng nhau. Nhưng nó có thể không giống nhau trong mọi trường hợp

    So sánh tùy chỉnh

    class MyClass:
    
    	@classmethod                #<--use decorator to declare a class method
    	def my_method(cls, args..): #<--cls argument refers to the class
    		# execute
    		# can't use any instance attributes
    5

    • Làm thế nào chúng ta có thể thực thi điều này cho các lớp tùy chỉnh?

    Quá tải eq() (bình đẳng)

    • class SavingsAccount(BankAccount):
      	def __init__(self, balance, interest_rate):
      		BankAccount.__init__(self, balance)
      		self.interest_rate = interest_rate
      
      	# new functionality
      	def compute_interest(self, n_periods=1):
      		return self.balance * ((1 + self.interest_rate) ** n_periods - 1)
      3 được gọi bất cứ khi nào 2 đối tượng của một lớp được so sánh với nhau bằng cách sử dụng
      class SavingsAccount(BankAccount):
      	def __init__(self, balance, interest_rate):
      		BankAccount.__init__(self, balance)
      		self.interest_rate = interest_rate
      
      	# new functionality
      	def compute_interest(self, n_periods=1):
      		return self.balance * ((1 + self.interest_rate) ** n_periods - 1)
      4
    • Chúng tôi có thể xác định lại phương pháp này để thực hiện so sánh tùy chỉnh. Phương thức nên chấp nhận 2 đối số đề cập đến các đối tượng được so sánh. Chúng thường được gọi là
      >>>e = EmailableContact("Test user ", "[email protected]")
      >>>e.send_mail("hello, test email here")
      Sending mail to [email protected]
      
      17 và
      class SavingsAccount(BankAccount):
      	def __init__(self, balance, interest_rate):
      		BankAccount.__init__(self, balance)
      		self.interest_rate = interest_rate
      
      	# new functionality
      	def compute_interest(self, n_periods=1):
      		return self.balance * ((1 + self.interest_rate) ** n_periods - 1)
      6 theo quy ước. Trả về một boolean
    • Khi so sánh hai đối tượng của một lớp tùy chỉnh bằng ==, Python theo mặc định chỉ so sánh các tham chiếu đối tượng, không phải dữ liệu chứa trong các đối tượng. Để ghi đè hành vi này, lớp có thể triển khai phương thức eq() đặc biệt, phương thức này chấp nhận hai đối số -- đối tượng được so sánh -- và trả về Đúng hoặc Sai. Phương thức này sẽ được gọi ngầm khi hai đối tượng được so sánh

    class MyClass:
    
    	@classmethod                #<--use decorator to declare a class method
    	def my_method(cls, args..): #<--cls argument refers to the class
    		# execute
    		# can't use any instance attributes
    6

    Các toán tử so sánh khác

    • class SavingsAccount(BankAccount):
      	def __init__(self, balance, interest_rate):
      		BankAccount.__init__(self, balance)
      		self.interest_rate = interest_rate
      
      	# new functionality
      	def compute_interest(self, n_periods=1):
      		return self.balance * ((1 + self.interest_rate) ** n_periods - 1)
      7 ,
      class SavingsAccount(BankAccount):
      	def __init__(self, balance, interest_rate):
      		BankAccount.__init__(self, balance)
      		self.interest_rate = interest_rate
      
      	# new functionality
      	def compute_interest(self, n_periods=1):
      		return self.balance * ((1 + self.interest_rate) ** n_periods - 1)
      8 ,
      class SavingsAccount(BankAccount):
      	def __init__(self, balance, interest_rate):
      		BankAccount.__init__(self, balance)
      		self.interest_rate = interest_rate
      
      	# new functionality
      	def compute_interest(self, n_periods=1):
      		return self.balance * ((1 + self.interest_rate) ** n_periods - 1)
      9 ,
      >>>e = EmailableContact("Test user ", "[email protected]")
      >>>e.send_mail("hello, test email here")
      Sending mail to [email protected]
      
      70 ,
      >>>e = EmailableContact("Test user ", "[email protected]")
      >>>e.send_mail("hello, test email here")
      Sending mail to [email protected]
      
      71 ,
      >>>e = EmailableContact("Test user ", "[email protected]")
      >>>e.send_mail("hello, test email here")
      Sending mail to [email protected]
      
      72
    • Có một phương thức
      >>>e = EmailableContact("Test user ", "[email protected]")
      >>>e.send_mail("hello, test email here")
      Sending mail to [email protected]
      
      73 cho phép chúng ta sử dụng các đối tượng làm khóa từ điển và theo bộ

    Kiểm tra bình đẳng lớp

    • Chúng tôi đã định nghĩa một lớp BankAccount với thuộc tính số được sử dụng để so sánh. Nhưng nếu chúng ta so sánh một đối tượng BankAccount với một đối tượng của lớp khác cũng có thuộc tính số, chúng ta có thể nhận được kết quả không mong muốn

    Xét hai lớp

    class MyClass:
    
    	@classmethod                #<--use decorator to declare a class method
    	def my_method(cls, args..): #<--cls argument refers to the class
    		# execute
    		# can't use any instance attributes
    7

    • Chạy
      >>>e = EmailableContact("Test user ", "[email protected]")
      >>>e.send_mail("hello, test email here")
      Sending mail to [email protected]
      
      74 sẽ trả về True, mặc dù chúng tôi đang so sánh số điện thoại với số tài khoản ngân hàng. Bạn nên kiểm tra lớp đối tượng được truyền cho phương thức eq() để đảm bảo việc so sánh có ý nghĩa
    • Bây giờ chỉ so sánh các đối tượng của cùng một lớp BankAccount mới có thể trả về True. Một cách khác để đảm bảo rằng một đối tượng có cùng kiểu như bạn mong đợi là sử dụng hàm isinstance(obj, Class). Điều này có thể hữu ích khi xử lý tính kế thừa, vì Python coi một đối tượng là một thể hiện của cả lớp cha và lớp con

    So sánh và kế thừa

    • Điều gì xảy ra khi một đối tượng được so sánh với một đối tượng của lớp con?

    class MyClass:
    
    	@classmethod                #<--use decorator to declare a class method
    	def my_method(cls, args..): #<--cls argument refers to the class
    		# execute
    		# can't use any instance attributes
    8

    • Python luôn gọi phương thức eq() của con khi so sánh đối tượng con với đối tượng cha

    Quá tải toán tử. biểu diễn chuỗi

    Chuỗi đại diện của các đối tượng

    • Có hai phương thức đặc biệt trong Python trả về một chuỗi biểu diễn của một đối tượng. str() được gọi khi bạn sử dụng print() hoặc str() trên một đối tượng và repr() được gọi khi bạn sử dụng repr() trên một đối tượng

    In một đối tượng

    • Chúng tôi đã thấy rằng đối tượng in của lớp tùy chỉnh, in vị trí bộ nhớ của đối tượng. Nhưng có rất nhiều lớp mà bản in có nhiều thông tin hơn. cho e. g nếu chúng ta in một mảng hoặc khung dữ liệu có nhiều mảng, chúng ta sẽ thấy dữ liệu thực chứa trong đối tượng
    • Có 2 phương thức đặc biệt mà chúng ta có thể định nghĩa trong một lớp sẽ trả về một biểu diễn có thể in được của một đối tượng
    • Phương thức
      >>>e = EmailableContact("Test user ", "[email protected]")
      >>>e.send_mail("hello, test email here")
      Sending mail to [email protected]
      
      75 được thực thi khi chúng ta gọi print(np. mảng([1,2,3])) hoặc str(np. mảng([1,2,3])) trên một đối tượng. [in(obj), str(obj)]
    • Phương thức
      >>>e = EmailableContact("Test user ", "[email protected]")
      >>>e.send_mail("hello, test email here")
      Sending mail to [email protected]
      
      76 được thực thi khi chúng ta gọi repr trên một đối tượng. [repr(obj)]
    • Sự khác biệt là
      >>>e = EmailableContact("Test user ", "[email protected]")
      >>>e.send_mail("hello, test email here")
      Sending mail to [email protected]
      
      77 cung cấp một biểu diễn không chính thức (biểu diễn chuỗi) và
      >>>e = EmailableContact("Test user ", "[email protected]")
      >>>e.send_mail("hello, test email here")
      Sending mail to [email protected]
      
      78 chủ yếu được sử dụng bởi các nhà phát triển. Cách thực hành tốt nhất là sử dụng
      >>>e = EmailableContact("Test user ", "[email protected]")
      >>>e.send_mail("hello, test email here")
      Sending mail to [email protected]
      
      78, có thể được sử dụng để tái tạo đối tượng.
      >>>e = EmailableContact("Test user ", "[email protected]")
      >>>e.send_mail("hello, test email here")
      Sending mail to [email protected]
      
      78 cũng được sử dụng làm dự phòng cho bản in, khi không xác định được
      >>>e = EmailableContact("Test user ", "[email protected]")
      >>>e.send_mail("hello, test email here")
      Sending mail to [email protected]
      
      77

    Thực hiện. str

    • Nó không nên chấp nhận bất kỳ đối số nào ngoài
      >>>e = EmailableContact("Test user ", "[email protected]")
      >>>e.send_mail("hello, test email here")
      Sending mail to [email protected]
      
      17 và nó sẽ trả về một
      class MyClass:
      
      	@classmethod                #<--use decorator to declare a class method
      	def my_method(cls, args..): #<--cls argument refers to the class
      		# execute
      		# can't use any instance attributes
      23. Nếu bây giờ chúng ta tạo một đối tượng Khách hàng và in, chúng ta sẽ thấy đầu ra thân thiện với người dùng

    class MyClass:
    
    	@classmethod                #<--use decorator to declare a class method
    	def my_method(cls, args..): #<--cls argument refers to the class
    		# execute
    		# can't use any instance attributes
    9

    Thực hiện. đại diện

    • Chấp nhận một đối số
      >>>e = EmailableContact("Test user ", "[email protected]")
      >>>e.send_mail("hello, test email here")
      Sending mail to [email protected]
      
      17 và trả về một
      class MyClass:
      
      	@classmethod                #<--use decorator to declare a class method
      	def my_method(cls, args..): #<--cls argument refers to the class
      		# execute
      		# can't use any instance attributes
      23. repr được sử dụng để tái tạo đối tượng, trong trường hợp này là cuộc gọi khởi tạo chính xác

    >>>e = EmailableContact("Test user ", "[email protected]")
    >>>e.send_mail("hello, test email here")
    Sending mail to [email protected]
    
    10

    • Chúng ta phải luôn định nghĩa ít nhất một trong các phương thức biểu diễn chuỗi cho đối tượng out để đảm bảo rằng người sử dụng lớp của chúng ta có thể lấy thông tin quan trọng về đối tượng một cách dễ dàng

    ngoại lệ

    xử lý ngoại lệ

    • sử dụng mã
      class MyClass:
      
      	@classmethod                #<--use decorator to declare a class method
      	def my_method(cls, args..): #<--cls argument refers to the class
      		# execute
      		# can't use any instance attributes
      26 -
      class MyClass:
      
      	@classmethod                #<--use decorator to declare a class method
      	def my_method(cls, args..): #<--cls argument refers to the class
      		# execute
      		# can't use any instance attributes
      27 -
      class MyClass:
      
      	@classmethod                #<--use decorator to declare a class method
      	def my_method(cls, args..): #<--cls argument refers to the class
      		# execute
      		# can't use any instance attributes
      28

    >>>e = EmailableContact("Test user ", "[email protected]")
    >>>e.send_mail("hello, test email here")
    Sending mail to [email protected]
    
    11

    Ngoại lệ là các lớp

    • Trong python, các ngoại lệ thực sự là các lớp được kế thừa từ các lớp dựng sẵn,
      class MyClass:
      
      	@classmethod                #<--use decorator to declare a class method
      	def my_method(cls, args..): #<--cls argument refers to the class
      		# execute
      		# can't use any instance attributes
      29 hoặc
      # Example
      class Contact:
      	#all_contacts = []
      	all_contacts = ContactList()
      	
      	def __init__(self, name, email):
      		self.name = name
      		self.email = email
      		#Contact.all_contacts.append(self)
      		self.all_contacts.append(self)
              
       class MailSender:
      	def send_mail(self, message):
      		print("sending mail to " + self.email)
              
      # multiple inheritance
      class EmailableContact(Contact, MailSender):
      	pass
      0

    Ngoại lệ tùy chỉnh

    • Để xác định ngoại lệ tùy chỉnh, chỉ cần xác định một lớp kế thừa từ lớp
      # Example
      class Contact:
      	#all_contacts = []
      	all_contacts = ContactList()
      	
      	def __init__(self, name, email):
      		self.name = name
      		self.email = email
      		#Contact.all_contacts.append(self)
      		self.all_contacts.append(self)
              
       class MailSender:
      	def send_mail(self, message):
      		print("sending mail to " + self.email)
              
      # multiple inheritance
      class EmailableContact(Contact, MailSender):
      	pass
      0 tích hợp hoặc một trong các lớp con của nó
    • Thông thường, một lớp trống và tính kế thừa thôi là đủ để đảm bảo rằng python sẽ coi lớp này là một lớp Ngoại lệ

    >>>e = EmailableContact("Test user ", "[email protected]")
    >>>e.send_mail("hello, test email here")
    Sending mail to [email protected]
    
    12

    Bắt ngoại lệ tùy chỉnh

    >>>e = EmailableContact("Test user ", "[email protected]")
    >>>e.send_mail("hello, test email here")
    Sending mail to [email protected]
    
    13

    Xử lý phân cấp ngoại lệ

    • Tốt hơn là liệt kê các khối ngoại trừ theo thứ tự cụ thể tăng dần, tôi. e. con trước cha mẹ, nếu không thì ngoại lệ con sẽ được gọi trong khối cha ngoại trừ

    Thiết kế cho sự kế thừa và đa hình

    đa hình

    • Sử dụng giao diện thống nhất để thao tác trên các đối tượng thuộc các lớp khác nhau

    Lập trình hướng đối tượng trong python datacamp github

    • Lớp BankAccount, SavingsAccount vàCheckingAccount có phương thức rút tiền nhưng phương thức ChecingAccount đang thực thi mã khác

    Tất cả những gì quan trọng là một giao diện

    • Giả sử chúng ta định nghĩa một chức năng để rút cùng một lượng tiền từ toàn bộ danh sách tài khoản cùng một lúc. Hàm không quan tâm liệu các đối tượng được truyền cho nó làCheckingAccount, SavingsAccount hay hỗn hợp. Tất cả vấn đề là họ có một phương thức rút tiền chấp nhận một đối số đủ để hàm hoạt động
    • Nó không kiểm tra việc rút tiền nào nên gọi là bản gốc hay bản sửa đổi. Khi phương thức rút tiền thực sự được gọi là python sẽ tự động kéo đúng phương thức
    • Rút tiền đã sửa đổi khi Tài khoản kiểm tra đang được xử lý và phương thức cơ bản khi Tài khoản tiết kiệm hoặc tài khoản thông thường được gọi

    >>>e = EmailableContact("Test user ", "[email protected]")
    >>>e.send_mail("hello, test email here")
    Sending mail to [email protected]
    
    14

    • # Example
      class Contact:
      	#all_contacts = []
      	all_contacts = ContactList()
      	
      	def __init__(self, name, email):
      		self.name = name
      		self.email = email
      		#Contact.all_contacts.append(self)
      		self.all_contacts.append(self)
              
       class MailSender:
      	def send_mail(self, message):
      		print("sending mail to " + self.email)
              
      # multiple inheritance
      class EmailableContact(Contact, MailSender):
      	pass
      2 không cần kiểm tra đối tượng để biết phải gọi
      # Example
      class Contact:
      	#all_contacts = []
      	all_contacts = ContactList()
      	
      	def __init__(self, name, email):
      		self.name = name
      		self.email = email
      		#Contact.all_contacts.append(self)
      		self.all_contacts.append(self)
              
       class MailSender:
      	def send_mail(self, message):
      		print("sending mail to " + self.email)
              
      # multiple inheritance
      class EmailableContact(Contact, MailSender):
      	pass
      3 nào

    Nguyên tắc thay thế Liskov

    • Có một nguyên tắc thiết kế hướng đối tượng cơ bản về thời điểm và cách sử dụng tính kế thừa đúng cách được gọi là nguyên tắc thay thế Liskov. `Lớp cơ sở có thể hoán đổi với bất kỳ lớp con nào của nó mà không làm thay đổi bất kỳ thuộc tính nào của chương trình
    • Điều đó có nghĩa là bất cứ nơi nào
      # Example
      class Contact:
      	#all_contacts = []
      	all_contacts = ContactList()
      	
      	def __init__(self, name, email):
      		self.name = name
      		self.email = email
      		#Contact.all_contacts.append(self)
      		self.all_contacts.append(self)
              
       class MailSender:
      	def send_mail(self, message):
      		print("sending mail to " + self.email)
              
      # multiple inheritance
      class EmailableContact(Contact, MailSender):
      	pass
      4 hoạt động, thì
      # Example
      class Contact:
      	#all_contacts = []
      	all_contacts = ContactList()
      	
      	def __init__(self, name, email):
      		self.name = name
      		self.email = email
      		#Contact.all_contacts.append(self)
      		self.all_contacts.append(self)
              
       class MailSender:
      	def send_mail(self, message):
      		print("sending mail to " + self.email)
              
      # multiple inheritance
      class EmailableContact(Contact, MailSender):
      	pass
      5 cũng sẽ hoạt động. cho e. g Hàm
      # Example
      class Contact:
      	#all_contacts = []
      	all_contacts = ContactList()
      	
      	def __init__(self, name, email):
      		self.name = name
      		self.email = email
      		#Contact.all_contacts.append(self)
      		self.all_contacts.append(self)
              
       class MailSender:
      	def send_mail(self, message):
      		print("sending mail to " + self.email)
              
      # multiple inheritance
      class EmailableContact(Contact, MailSender):
      	pass
      6 hoạt động bất kể loại tài khoản nào được sử dụng

    LSP vi phạm

    • không tương thích cú pháp.
      # Example
      class Contact:
      	#all_contacts = []
      	all_contacts = ContactList()
      	
      	def __init__(self, name, email):
      		self.name = name
      		self.email = email
      		#Contact.all_contacts.append(self)
      		self.all_contacts.append(self)
              
       class MailSender:
      	def send_mail(self, message):
      		print("sending mail to " + self.email)
              
      # multiple inheritance
      class EmailableContact(Contact, MailSender):
      	pass
      7 yêu cầu 1 tham số, nhưng
      # Example
      class Contact:
      	#all_contacts = []
      	all_contacts = ContactList()
      	
      	def __init__(self, name, email):
      		self.name = name
      		self.email = email
      		#Contact.all_contacts.append(self)
      		self.all_contacts.append(self)
              
       class MailSender:
      	def send_mail(self, message):
      		print("sending mail to " + self.email)
              
      # multiple inheritance
      class EmailableContact(Contact, MailSender):
      	pass
      8 yêu cầu 2
    • Phân lớp tăng cường điều kiện đầu vào.
      # Example
      class Contact:
      	#all_contacts = []
      	all_contacts = ContactList()
      	
      	def __init__(self, name, email):
      		self.name = name
      		self.email = email
      		#Contact.all_contacts.append(self)
      		self.all_contacts.append(self)
              
       class MailSender:
      	def send_mail(self, message):
      		print("sending mail to " + self.email)
              
      # multiple inheritance
      class EmailableContact(Contact, MailSender):
      	pass
      7 chấp nhận bất kỳ số lượng nào, nhưng
      # Example
      class Contact:
      	#all_contacts = []
      	all_contacts = ContactList()
      	
      	def __init__(self, name, email):
      		self.name = name
      		self.email = email
      		#Contact.all_contacts.append(self)
      		self.all_contacts.append(self)
              
       class MailSender:
      	def send_mail(self, message):
      		print("sending mail to " + self.email)
              
      # multiple inheritance
      class EmailableContact(Contact, MailSender):
      	pass
      8 cho rằng số lượng đó bị hạn chế
    • Phân lớp làm suy yếu điều kiện đầu ra.
      # Example
      class Contact:
      	#all_contacts = []
      	all_contacts = ContactList()
      	
      	def __init__(self, name, email):
      		self.name = name
      		self.email = email
      		#Contact.all_contacts.append(self)
      		self.all_contacts.append(self)
              
       class MailSender:
      	def send_mail(self, message):
      		print("sending mail to " + self.email)
              
      # multiple inheritance
      class EmailableContact(Contact, MailSender):
      	pass
      7 chỉ có thể để lại số dư dương hoặc gây ra lỗi,
      # Example
      class Contact:
      	#all_contacts = []
      	all_contacts = ContactList()
      	
      	def __init__(self, name, email):
      		self.name = name
      		self.email = email
      		#Contact.all_contacts.append(self)
      		self.all_contacts.append(self)
              
       class MailSender:
      	def send_mail(self, message):
      		print("sending mail to " + self.email)
              
      # multiple inheritance
      class EmailableContact(Contact, MailSender):
      	pass
      8 có thể để lại số dư âm
    • Thay đổi các thuộc tính bổ sung trong phương thức của lớp con không được thay đổi trong lớp cơ sở
    • Ném các ngoại lệ bổ sung trong phương thức của lớp con mà lớp cơ sở không ném

    Không LSP - Không kế thừa

    • Nếu hệ thống phân cấp lớp làm hỏng LSP, thì chúng ta không nên sử dụng tính kế thừa bcz, nó có khả năng hoạt động mã theo những cách không thể đoán trước