Một lớp có thể kế thừa từ nhiều cha. Ví dụ: bạn có thể xây dựng một lớp biểu diễn hình dạng 3D bằng cách kế thừa từ hai hình dạng 2D
class RightPyramid[Triangle, Square]:
def __init__[self, base, slant_height]:
self.base = base
self.slant_height = slant_height
def what_am_i[self]:
return 'RightPyramid'
Thứ tự phân giải phương thức [MRO] xác định nơi Python tìm kiếm một phương thức khi có một hệ thống phân cấp các lớp. Sử dụng
class A:
def __init__[self]:
print['A']
super[].__init__[]
class B[A]:
def __init__[self]:
print['B']
super[].__init__[]
class X:
def __init__[self]:
print['X']
super[].__init__[]
class Forward[B, X]:
def __init__[self]:
print['Forward']
super[].__init__[]
class Backward[X, B]:
def __init__[self]:
print['Backward']
super[].__init__[]
6 truy cập lớp tiếp theo trong MROclass A:
def __init__[self]:
print['A']
super[].__init__[]
class B[A]:
def __init__[self]:
print['B']
super[].__init__[]
class X:
def __init__[self]:
print['X']
super[].__init__[]
class Forward[B, X]:
def __init__[self]:
print['Forward']
super[].__init__[]
class Backward[X, B]:
def __init__[self]:
print['Backward']
super[].__init__[]
Nếu bạn kết hợp tính năng MRO và tính năng
class A:
def __init__[self]:
print['A']
super[].__init__[]
class B[A]:
def __init__[self]:
print['B']
super[].__init__[]
class X:
def __init__[self]:
print['X']
super[].__init__[]
class Forward[B, X]:
def __init__[self]:
print['Forward']
super[].__init__[]
class Backward[X, B]:
def __init__[self]:
print['Backward']
super[].__init__[]
8 để chỉ định các cặp tên-giá trị trong quá trình xây dựng, bạn có thể viết mã truyền tham số cho các lớp cha ngay cả khi chúng có các tên khác nhauclass Rectangle:
def __init__[self, length, width, **kwargs]:
self.length = length
self.width = width
super[].__init__[**kwargs]
def area[self]:
return self.length * self.width
def perimeter[self]:
return 2 * self.length + 2 * self.width
class Square[Rectangle]:
def __init__[self, length, **kwargs]:
super[].__init__[length=length, width=length, **kwargs]
class Triangle:
def __init__[self, base, height, **kwargs]:
self.base = base
self.height = height
super[].__init__[**kwargs]
def tri_area[self]:
return 0.5 * self.base * self.height
class RightPyramid[Square, Triangle]:
def __init__[self, base, slant_height, **kwargs]:
self.base = base
self.slant_height = slant_height
kwargs["height"] = slant_height
kwargs["length"] = base
super[].__init__[base=base, **kwargs]
def area[self]:
base_area = super[].area[]
perimeter = super[].perimeter[]
return 0.5 * perimeter * self.slant_height + base_area
def area_2[self]:
base_area = super[].area[]
triangle_area = super[].tri_area[]
return triangle_area * 4 + base_area
Nhiều kế thừa có thể trở nên phức tạp một cách nhanh chóng. Một trường hợp sử dụng đơn giản phổ biến trong lĩnh vực này là viết một mixin. Mixin là một lớp không quan tâm đến vị trí của nó trong hệ thống phân cấp mà chỉ cung cấp một hoặc nhiều phương thức tiện lợi
class SurfaceAreaMixin:
def surface_area[self]:
surface_area = 0
for surface in self.surfaces:
surface_area += surface.area[self]
return surface_area
class Cube[Square, SurfaceAreaMixin]:
def __init__[self, length]:
super[].__init__[length]
self.surfaces = [Square, Square, Square, Square, Square, Square]
class RightPyramid[Square, Triangle, SurfaceAreaMixin]:
def __init__[self, base, slant_height]:
self.base = base
self.slant_height = slant_height
self.height = slant_height
self.length = base
self.width = base
self.surfaces = [Square, Triangle, Triangle, Triangle, Triangle]
Đây là những gì bạn nhận được
>>>
>>> cube = Cube[3]
>>> cube.surface_area[]
54
Tải xuống
Slide khóa học [PDF]
896. 4 KB
Xin chúc mừng, bạn đã hoàn thành khóa học. Bài học số 1 hoặc điều yêu thích mà bạn đã học được là gì?
Richard Morris trên
Tuyệt vời động lực, có tổ chức, và nhịp độ. Cảm kích nhất
Alex trên
Cảm ơn bạn, đặc biệt là ví dụ về Mixins
Ẩn danh trên
Phải, tôi đã đọc tài liệu nhiều lần, nhưng cách trình bày tài liệu này khiến nó cực kỳ dễ hiểu và rõ ràng - được kết hợp rất tốt. Bây giờ để xem nó 5 lần nữa
rhuang trên
hướng dẫn tuyệt vời. Cảm ơn
ajp4 trên
Lời giải thích tốt nhất mà tôi đã thấy. Cảm ơn bạn
SkyFox trên
Tôi đến với hướng dẫn này để hiểu khái niệm về Mixins. Tôi thực sự hạnh phúc tôi đã có mọi thứ trong vòng chưa đầy 30 phút. Thực sự đánh giá cao sự đơn giản giải thích như vậy
Ryan Cook trên
Tôi thích phần giải thích về “tại sao” trong việc tạo Mix-in và những cạm bẫy tiềm ẩn của đa kế thừa. Tôi thích cách giải thích đơn giản và tốc độ giọng hát được đo lường của bạn. Hãy tiếp tục phát huy
Erikton Konomi trên
hướng dẫn tuyệt vời. Tôi thực sự thích cách ngắn gọn và đi thẳng vào vấn đề của cả ba video, với các ví dụ cụ thể. Tuy nhiên, sự ra đời của mẫu mixin đã tạo ra sự khác biệt cuối cùng. Tôi sẽ sớm tách một số mã tại nơi làm việc với điều này. ] Cảm ơn
ricardoaparicio92 trên
tôi bị lạc
Ricky White Nhóm RP trên
@richardoaparicio92 Bạn đang gặp khó khăn gì vậy?
Liz Schley trên
Điều này là tuyệt vời, vì vậy cảm ơn bạn. Mục đích của tôi là hiểu cách OOP hoạt động trong Python, để tôi có khả năng thiết kế mã tốt khi cần.
Liz Schley trên
Điều tôi thích nhất là phương pháp mro và sử dụng mixin để tránh nhầm lẫn. Chắc chắn là kế hoạch của tôi, nếu có thể vì mã khó hiểu sẽ tạo ra các lỗi tốn thời gian để sửa
graham17 trên
Thực sự hữu ích - một vài đồng xu đã giảm ngay tại đây. Điều duy nhất tôi không nhận được là khối cuối cùng = SACube[3] Tôi nghi ngờ đây là một lỗi - Tôi không thể tìm thấy bất kỳ giới thiệu nào về lớp SACube ở bất cứ đâu - nhưng có lẽ tôi đã bỏ lỡ nó - về tổng thể - một hướng dẫn ngắn gọn tuyệt vời
Christopher Trudeau Nhóm RP trên
Xin chào gham17,
Nắm bắt tốt. Đó là một hiện vật từ phiên bản trước của mã. Chúng tôi sẽ khắc phục sự cố trong thời gian ngắn. Cảm ơn vì đã cho chúng tôi biết. …ct
samsku1986 trên
Trong trường hợp kế thừa đơn lẻ, tại sao lại sử dụng phương thức super[] khi chúng ta có thể gọi phương thức trực tiếp bằng tên lớp ??. Ý tôi là lợi thế là gì?
lớp chữ nhật. def init[bản thân, chiều dài, chiều rộng]. bản thân. chiều dài = chiều dài bản thân. chiều rộng = chiều rộng
def area[self]:
return [self.length * self.width]
def permiter[self]:
return [2 * self.length + 2 * self.width]
lớp Hình vuông [Hình chữ nhật]
________số 8
Vijay Alagappan trên
Giải thích rõ ràng về các khái niệm như MRO và Mixins. Cảm ơn rất nhiều
Nathan L trên
Bạn đã chỉ ra với ________ 195 rằng bạn có thể truy cập _________ 405 bằng ________ 406 hoặc
class Rectangle:
def __init__[self, length, width, **kwargs]:
self.length = length
self.width = width
super[].__init__[**kwargs]
def area[self]:
return self.length * self.width
def perimeter[self]:
return 2 * self.length + 2 * self.width
class Square[Rectangle]:
def __init__[self, length, **kwargs]:
super[].__init__[length=length, width=length, **kwargs]
class Triangle:
def __init__[self, base, height, **kwargs]:
self.base = base
self.height = height
super[].__init__[**kwargs]
def tri_area[self]:
return 0.5 * self.base * self.height
class RightPyramid[Square, Triangle]:
def __init__[self, base, slant_height, **kwargs]:
self.base = base
self.slant_height = slant_height
kwargs["height"] = slant_height
kwargs["length"] = base
super[].__init__[base=base, **kwargs]
def area[self]:
base_area = super[].area[]
perimeter = super[].perimeter[]
return 0.5 * perimeter * self.slant_height + base_area
def area_2[self]:
base_area = super[].area[]
triangle_area = super[].tri_area[]
return triangle_area * 4 + base_area
07. Thực hành tốt nhất là gì? Christopher Trudeau Nhóm RP trên
Chào Nathan,
Nói chung, bạn sử dụng tự. method[] trừ khi có lý do để làm khác. Nếu tôi phải gọi phương thức cha, thì super[] hoặc nếu có một số tình huống cần sự rõ ràng thì tôi sẽ gọi phương thức cha
nj8456 trên
Đã gặp mã này trong “Tạo trình quản lý mô hình tùy chỉnh ở Django” trong Django bằng Sách ví dụ
GIVEN đoạn mã sau
class A:
def __init__[self]:
print['A']
super[].__init__[]
class B[A]:
def __init__[self]:
print['B']
super[].__init__[]
class X:
def __init__[self]:
print['X']
super[].__init__[]
class Forward[B, X]:
def __init__[self]:
print['Forward']
super[].__init__[]
class Backward[X, B]:
def __init__[self]:
print['Backward']
super[].__init__[]
5AND GIVEN
class Rectangle:
def __init__[self, length, width, **kwargs]:
self.length = length
self.width = width
super[].__init__[**kwargs]
def area[self]:
return self.length * self.width
def perimeter[self]:
return 2 * self.length + 2 * self.width
class Square[Rectangle]:
def __init__[self, length, **kwargs]:
super[].__init__[length=length, width=length, **kwargs]
class Triangle:
def __init__[self, base, height, **kwargs]:
self.base = base
self.height = height
super[].__init__[**kwargs]
def tri_area[self]:
return 0.5 * self.base * self.height
class RightPyramid[Square, Triangle]:
def __init__[self, base, slant_height, **kwargs]:
self.base = base
self.slant_height = slant_height
kwargs["height"] = slant_height
kwargs["length"] = base
super[].__init__[base=base, **kwargs]
def area[self]:
base_area = super[].area[]
perimeter = super[].perimeter[]
return 0.5 * perimeter * self.slant_height + base_area
def area_2[self]:
base_area = super[].area[]
triangle_area = super[].tri_area[]
return triangle_area * 4 + base_area
10 là Trình quản lý mô hình mặc định cho Bài đăng,SAU ĐÓ, mã
class Rectangle:
def __init__[self, length, width, **kwargs]:
self.length = length
self.width = width
super[].__init__[**kwargs]
def area[self]:
return self.length * self.width
def perimeter[self]:
return 2 * self.length + 2 * self.width
class Square[Rectangle]:
def __init__[self, length, **kwargs]:
super[].__init__[length=length, width=length, **kwargs]
class Triangle:
def __init__[self, base, height, **kwargs]:
self.base = base
self.height = height
super[].__init__[**kwargs]
def tri_area[self]:
return 0.5 * self.base * self.height
class RightPyramid[Square, Triangle]:
def __init__[self, base, slant_height, **kwargs]:
self.base = base
self.slant_height = slant_height
kwargs["height"] = slant_height
kwargs["length"] = base
super[].__init__[base=base, **kwargs]
def area[self]:
base_area = super[].area[]
perimeter = super[].perimeter[]
return 0.5 * perimeter * self.slant_height + base_area
def area_2[self]:
base_area = super[].area[]
triangle_area = super[].tri_area[]
return triangle_area * 4 + base_area
11 tương đương với việc gọi Trình quản lý mặc định Đối tượng - class Rectangle:
def __init__[self, length, width, **kwargs]:
self.length = length
self.width = width
super[].__init__[**kwargs]
def area[self]:
return self.length * self.width
def perimeter[self]:
return 2 * self.length + 2 * self.width
class Square[Rectangle]:
def __init__[self, length, **kwargs]:
super[].__init__[length=length, width=length, **kwargs]
class Triangle:
def __init__[self, base, height, **kwargs]:
self.base = base
self.height = height
super[].__init__[**kwargs]
def tri_area[self]:
return 0.5 * self.base * self.height
class RightPyramid[Square, Triangle]:
def __init__[self, base, slant_height, **kwargs]:
self.base = base
self.slant_height = slant_height
kwargs["height"] = slant_height
kwargs["length"] = base
super[].__init__[base=base, **kwargs]
def area[self]:
base_area = super[].area[]
perimeter = super[].perimeter[]
return 0.5 * perimeter * self.slant_height + base_area
def area_2[self]:
base_area = super[].area[]
triangle_area = super[].tri_area[]
return triangle_area * 4 + base_area
12 từ bên trong một thể hiện của lớp PublishedManager phải không?Christopher Trudeau Nhóm RP trên
Xin chào nj8456,
Vâng bạn đã đúng. PublishedManager đang ghi đè các mô hình. Người quản lý. get_queryset[], vì vậy trong phần ghi đè đó, nếu bạn gọi self. get_queryset[] bạn sẽ nhận được phiên bản bị ghi đè - một cuộc gọi đệ quy. Việc sử dụng super[] ở đây giúp bạn có được phương thức của cha mẹ
Đây là một mẫu phổ biến trong các mô hình Django. Bạn làm điều gì đó tương tự nếu bạn muốn ghi đè phương thức save[] của Mô hình – gọi cấp độ gốc, để thực hiện những gì nó thường làm, sau đó chạy mã chuyên dụng của bạn
Trong trường hợp PublishedManager. get_queryset[], bạn muốn thực hiện truy vấn giống như truy vấn gốc, nhưng lần này cũng áp dụng bộ lọc. Cha mẹ được gọi, sau đó bộ lọc được áp dụng, sau đó kết quả được lọc được trả về
Ký hiệu ngoặc là một hình thức ngắn để làm
class A:
def __init__[self]:
print['A']
super[].__init__[]
class B[A]:
def __init__[self]:
print['B']
super[].__init__[]
class X:
def __init__[self]:
print['X']
super[].__init__[]
class Forward[B, X]:
def __init__[self]:
print['Forward']
super[].__init__[]
class Backward[X, B]:
def __init__[self]:
print['Backward']
super[].__init__[]
9Bởi vì get_queryset[] trả về một QuerySet, nên
class A:
def __init__[self]:
print['A']
super[].__init__[]
class B[A]:
def __init__[self]:
print['B']
super[].__init__[]
class X:
def __init__[self]:
print['X']
super[].__init__[]
class Forward[B, X]:
def __init__[self]:
print['Forward']
super[].__init__[]
class Backward[X, B]:
def __init__[self]:
print['Backward']
super[].__init__[]
0mẫu, xâu chuỗi các kết quả của từng mẫu lại với nhau, gọi hàm tiếp theo trên bất kỳ thứ gì được trả về bởi hàm trước đó
Omkar trên
Vì lớp A hoặc X ở đây là lớp cuối cùng trong lớp tiến và lùi, nên chúng ta đã hoàn thành chuỗi. Nhưng điều đó có nghĩa là lớp ____
def __init__[self,length]:
Rectangle.__init__[self,length,length] >>>>>>>>>>>>>>>>>>>>calling Rectangle,method[] directly instead of super
#super[].__init__[length,length]
2 init cũng được gọi ở đây khi cuối cùng trên chuỗi?class A:
def __init__[self]:
print['A']
super[].__init__[]
class B[A]:
def __init__[self]:
print['B']
super[].__init__[]
class X:
def __init__[self]:
print['X']
super[].__init__[]
class Forward[B, X]:
def __init__[self]:
print['Forward']
super[].__init__[]
class Backward[X, B]:
def __init__[self]:
print['Backward']
super[].__init__[]
0Cuối cùng trong chuỗi hoặc nếu ngay cả khi đây chỉ là một lớp duy nhất gọi ________ 16 của nó thì có nghĩa là gọi ________ 82 đúng vì nó là lớp cha?
Christopher Trudeau Nhóm RP trên
Xin chào Omkar,
Vâng, đó là một chút khó khăn. Bản thân A sẽ không cần super[]. init[] vì nó super chỉ là lớp Object cơ sở
Trường hợp nó trở nên quan trọng là thông qua chuỗi. Trong trường hợp của lớp Backward, A's super[]. init[] không làm gì cả. Trong trường hợp của lớp Forward, đó là lý do tại sao hàm tạo của X được gọi
super[] gọi lớp tiếp theo trong MRO
Chuỗi hoạt động như thế này
Lùi -> X -> B -> A
Vì vậy, lời gọi của A tới super[]. init[] không làm gì cả. Ngược lại mặc dù
Chuyển tiếp -> B -> A -> X
Trong trường hợp này, không có super[] của A. init[], phương thức init của X sẽ không được gọi
Nếu bạn đang viết các lớp có khả năng bị trộn lẫn hoặc được sử dụng với tính kế thừa, thì cách tốt nhất là gọi “super[]. init[]” trong trường hợp các lập trình viên khác sử dụng lớp của bạn thay đổi thứ tự kế thừa
Omkar trên
Cảm ơn vì lời giải thích rõ ràng. ] Thích thú khi trở thành một phần của cộng đồng này
James trên
Tôi không hiểu lắm phần này của mixin
class A:
def __init__[self]:
print['A']
super[].__init__[]
class B[A]:
def __init__[self]:
print['B']
super[].__init__[]
class X:
def __init__[self]:
print['X']
super[].__init__[]
class Forward[B, X]:
def __init__[self]:
print['Forward']
super[].__init__[]
class Backward[X, B]:
def __init__[self]:
print['Backward']
super[].__init__[]
1class A:
def __init__[self]:
print['A']
super[].__init__[]
class B[A]:
def __init__[self]:
print['B']
super[].__init__[]
class X:
def __init__[self]:
print['X']
super[].__init__[]
class Forward[B, X]:
def __init__[self]:
print['Forward']
super[].__init__[]
class Backward[X, B]:
def __init__[self]:
print['Backward']
super[].__init__[]
2Tại sao họ có những giá trị này? . Cảm ơn
Christopher Trudeau Nhóm RP trên
Chào James,
Ý tưởng ở đây là làm nổi bật chức năng của Mixin. mã phổ biến trên một số lớp mà không nhất thiết phải có kiến thức sâu về lớp
The SurvaceAreaMixin. Phương thức surface_area[] tính toán diện tích bề mặt của hình dạng 3D bằng cách tìm thuộc tính có tên là “các bề mặt” và gọi phương thức area[] cho từng bề mặt, cộng chúng lại với nhau
Khối lập phương có sáu mặt, mỗi mặt là hình vuông. Bằng cách đặt Cube. bề mặt thành sáu Hình vuông, phương thức surface_area[] của mixin sẽ tính toán chính xác diện tích bề mặt của Khối lập phương
Kim tự tháp bên phải bao gồm một cơ sở hình vuông và bốn mặt hình tam giác. Nó thể hiện điều này bằng cách đặt thuộc tính “bề mặt” thành [Square, Triangle, Triangle, Triangle, Triangle]
Mixin biết ở mức độ trừu tượng cách tính diện tích bề mặt [bằng cách gọi phương thức area[] trên mỗi hình dạng trong thuộc tính “surfaces”], nhưng không cần biết bề mặt của đối tượng kế thừa mixin là gì
Các chi tiết cụ thể của hình dạng 3D được mô tả trong phần triển khai của lớp [Cube hoặc RightPyramid], nhưng thuật toán tính diện tích bề mặt có thể được tách ra khỏi lớp này thành một lớp mixin chung
Nếu không có mixin, bạn sẽ cần viết các phương thức surface_area[] riêng biệt cho Cube và RightPyramid. Có nó trong mixin có nghĩa là viết và kiểm tra nó ở một nơi duy nhất
Ghani trên
Rất rõ ràng và giải thích tốt
Saul vào
vật liệu tuyệt vời. Tôi có một phân minh nhỏ và một số quan sát hữu ích hy vọng. Xin hãy sửa tôi nếu tôi đi lạc lối. Vào khoảng 7. 18, cần lưu ý rằng hàm tạo của lớp Square nhận cơ sở, độ nghiêng, chiều cao và độ dài làm đối số. Nhưng slant_height không thực sự được bao gồm trong các đối số đó. Nó được ghi lại dưới dạng tham số vị trí trong hàm tạo cho RightPyramid, cùng với cơ sở. Lý do bản thân cơ sở được chuyển lên chuỗi là vì chúng tôi đặc biệt gửi lại cơ sở trong lệnh gọi phương thức
class Rectangle:
def __init__[self, length, width, **kwargs]:
self.length = length
self.width = width
super[].__init__[**kwargs]
def area[self]:
return self.length * self.width
def perimeter[self]:
return 2 * self.length + 2 * self.width
class Square[Rectangle]:
def __init__[self, length, **kwargs]:
super[].__init__[length=length, width=length, **kwargs]
class Triangle:
def __init__[self, base, height, **kwargs]:
self.base = base
self.height = height
super[].__init__[**kwargs]
def tri_area[self]:
return 0.5 * self.base * self.height
class RightPyramid[Square, Triangle]:
def __init__[self, base, slant_height, **kwargs]:
self.base = base
self.slant_height = slant_height
kwargs["height"] = slant_height
kwargs["length"] = base
super[].__init__[base=base, **kwargs]
def area[self]:
base_area = super[].area[]
perimeter = super[].perimeter[]
return 0.5 * perimeter * self.slant_height + base_area
def area_2[self]:
base_area = super[].area[]
triangle_area = super[].tri_area[]
return triangle_area * 4 + base_area
16. Chúng tôi không gửi lại slant_height vì nó không được sử dụng bởi bất kỳ siêu lớp nàoclass A:
def __init__[self]:
print['A']
super[].__init__[]
class B[A]:
def __init__[self]:
print['B']
super[].__init__[]
class X:
def __init__[self]:
print['X']
super[].__init__[]
class Forward[B, X]:
def __init__[self]:
print['Forward']
super[].__init__[]
class Backward[X, B]:
def __init__[self]:
print['Backward']
super[].__init__[]
3Trên thực tế, nếu chúng tôi đã bao gồm slant_height, một ngoại lệ sau đó sẽ xảy ra khi lệnh gọi đối tượng
class Rectangle:
def __init__[self, length, width, **kwargs]:
self.length = length
self.width = width
super[].__init__[**kwargs]
def area[self]:
return self.length * self.width
def perimeter[self]:
return 2 * self.length + 2 * self.width
class Square[Rectangle]:
def __init__[self, length, **kwargs]:
super[].__init__[length=length, width=length, **kwargs]
class Triangle:
def __init__[self, base, height, **kwargs]:
self.base = base
self.height = height
super[].__init__[**kwargs]
def tri_area[self]:
return 0.5 * self.base * self.height
class RightPyramid[Square, Triangle]:
def __init__[self, base, slant_height, **kwargs]:
self.base = base
self.slant_height = slant_height
kwargs["height"] = slant_height
kwargs["length"] = base
super[].__init__[base=base, **kwargs]
def area[self]:
base_area = super[].area[]
perimeter = super[].perimeter[]
return 0.5 * perimeter * self.slant_height + base_area
def area_2[self]:
base_area = super[].area[]
triangle_area = super[].tri_area[]
return triangle_area * 4 + base_area
17 cuối cùng xảy raLoạiLỗi. vật. init[] không nhận tham số
Sử dụng
class Rectangle:
def __init__[self, length, width, **kwargs]:
self.length = length
self.width = width
super[].__init__[**kwargs]
def area[self]:
return self.length * self.width
def perimeter[self]:
return 2 * self.length + 2 * self.width
class Square[Rectangle]:
def __init__[self, length, **kwargs]:
super[].__init__[length=length, width=length, **kwargs]
class Triangle:
def __init__[self, base, height, **kwargs]:
self.base = base
self.height = height
super[].__init__[**kwargs]
def tri_area[self]:
return 0.5 * self.base * self.height
class RightPyramid[Square, Triangle]:
def __init__[self, base, slant_height, **kwargs]:
self.base = base
self.slant_height = slant_height
kwargs["height"] = slant_height
kwargs["length"] = base
super[].__init__[base=base, **kwargs]
def area[self]:
base_area = super[].area[]
perimeter = super[].perimeter[]
return 0.5 * perimeter * self.slant_height + base_area
def area_2[self]:
base_area = super[].area[]
triangle_area = super[].tri_area[]
return triangle_area * 4 + base_area
17 theo cách này để xâu chuỗi trên nhiều hệ thống phân cấp thừa kế [bằng cách tuân theo MRO] có nghĩa là chúng tôi không thể có bất kỳ đối số từ khóa không liên quan hoặc không sử dụng nào. Chúng phải được ghi lại bởi các tham số có cùng tên trong hàm tạo ở đâu đó trong chuỗi. Đó là cách duy nhất để chúng bị tiêu thụ và bị loại khỏi từ điển kwargsCái khác. Lúc đầu, tôi gặp một chút rắc rối khi gán từ điển kwargs trong hàm tạo cho RightPyramid. Tôi không thể hiểu tại sao chúng ta lại chuyển chiều cao và chiều dài làm đối số với các câu lệnh gán này nhưng sau đó lại chuyển cơ sở làm đối số trong lệnh gọi
class Rectangle:
def __init__[self, length, width, **kwargs]:
self.length = length
self.width = width
super[].__init__[**kwargs]
def area[self]:
return self.length * self.width
def perimeter[self]:
return 2 * self.length + 2 * self.width
class Square[Rectangle]:
def __init__[self, length, **kwargs]:
super[].__init__[length=length, width=length, **kwargs]
class Triangle:
def __init__[self, base, height, **kwargs]:
self.base = base
self.height = height
super[].__init__[**kwargs]
def tri_area[self]:
return 0.5 * self.base * self.height
class RightPyramid[Square, Triangle]:
def __init__[self, base, slant_height, **kwargs]:
self.base = base
self.slant_height = slant_height
kwargs["height"] = slant_height
kwargs["length"] = base
super[].__init__[base=base, **kwargs]
def area[self]:
base_area = super[].area[]
perimeter = super[].perimeter[]
return 0.5 * perimeter * self.slant_height + base_area
def area_2[self]:
base_area = super[].area[]
triangle_area = super[].tri_area[]
return triangle_area * 4 + base_area
19. Vâng, có vẻ như những cách tiếp cận này là tương đương. Chúng tôi cũng có thể đã làm một trong những điều sau đâyclass A:
def __init__[self]:
print['A']
super[].__init__[]
class B[A]:
def __init__[self]:
print['B']
super[].__init__[]
class X:
def __init__[self]:
print['X']
super[].__init__[]
class Forward[B, X]:
def __init__[self]:
print['Forward']
super[].__init__[]
class Backward[X, B]:
def __init__[self]:
print['Backward']
super[].__init__[]
4class A:
def __init__[self]:
print['A']
super[].__init__[]
class B[A]:
def __init__[self]:
print['B']
super[].__init__[]
class X:
def __init__[self]:
print['X']
super[].__init__[]
class Forward[B, X]:
def __init__[self]:
print['Forward']
super[].__init__[]
class Backward[X, B]:
def __init__[self]:
print['Backward']
super[].__init__[]
5Một lần nữa, xin vui lòng cho tôi biết nếu tôi đang thiếu một cái gì đó. Cảm ơn
Christopher Trudeau Nhóm RP trên
Chào Saul,
Cảm ơn ý kiến của bạn
Vào khoảng 7. 18, cần lưu ý rằng hàm tạo của lớp Square nhận cơ sở, độ nghiêng, chiều cao và độ dài làm đối số. Nhưng slant_height không thực sự được bao gồm trong các đối số đó
Tôi tin rằng những gì tôi đang cố gắng truyền đạt là slant_height được chuyển vào nhưng dưới dạng đối số chiều cao. Bạn đã đúng rằng slant_height không được giữ làm đối số được đặt tên
Bạn cũng đúng là bạn phải cẩn thận với những thứ này và những gì được tiêu thụ. Bạn chỉ phải đảm bảo rằng tất cả chúng đều được sử dụng nếu có một lớp ở đâu đó có init[] trống, nếu các hàm tạo của bạn luôn có các đối số
class Rectangle:
def __init__[self, length, width, **kwargs]:
self.length = length
self.width = width
super[].__init__[**kwargs]
def area[self]:
return self.length * self.width
def perimeter[self]:
return 2 * self.length + 2 * self.width
class Square[Rectangle]:
def __init__[self, length, **kwargs]:
super[].__init__[length=length, width=length, **kwargs]
class Triangle:
def __init__[self, base, height, **kwargs]:
self.base = base
self.height = height
super[].__init__[**kwargs]
def tri_area[self]:
return 0.5 * self.base * self.height
class RightPyramid[Square, Triangle]:
def __init__[self, base, slant_height, **kwargs]:
self.base = base
self.slant_height = slant_height
kwargs["height"] = slant_height
kwargs["length"] = base
super[].__init__[base=base, **kwargs]
def area[self]:
base_area = super[].area[]
perimeter = super[].perimeter[]
return 0.5 * perimeter * self.slant_height + base_area
def area_2[self]:
base_area = super[].area[]
triangle_area = super[].tri_area[]
return triangle_area * 4 + base_area
20 thì bạn sẽ ổn thôi [anh ấy lo lắng viết mà không cần kiểm tra. ] ]. Điều đó đang được nói, đây là lý do tại sao tôi có xu hướng chỉ thích sử dụng tính kế thừa cho Mixins. Những loại tinh tế này chắc chắn có thể gây ra cho bạn những vấn đề kỳ lạ cả khi biên dịch và thời gian chạyLúc đầu, tôi hơi gặp rắc rối khi gán cho từ điển kwargs … Chà, có vẻ như những cách tiếp cận này là tương đương
Đúng, bạn nói đúng. Đã quá lâu kể từ khi tôi viết mã đó, tôi không nhớ tại sao tôi lại làm như vậy. Tôi nghi ngờ nó có liên quan đến cách nó phát triển ra khỏi các phiên bản trước đó. Một trong hai cách tiếp cận hoạt động
Mã hóa vui vẻ
anindo78 trên
Hướng dẫn tuyệt vời về thừa kế
rikhuygen vào
Hướng dẫn tuyệt vời, và giải thích rất rõ ràng
Có một điều tôi không hoàn toàn bị thuyết phục và đó là ví dụ về Mixin. Phương thức
class Rectangle:
def __init__[self, length, width, **kwargs]:
self.length = length
self.width = width
super[].__init__[**kwargs]
def area[self]:
return self.length * self.width
def perimeter[self]:
return 2 * self.length + 2 * self.width
class Square[Rectangle]:
def __init__[self, length, **kwargs]:
super[].__init__[length=length, width=length, **kwargs]
class Triangle:
def __init__[self, base, height, **kwargs]:
self.base = base
self.height = height
super[].__init__[**kwargs]
def tri_area[self]:
return 0.5 * self.base * self.height
class RightPyramid[Square, Triangle]:
def __init__[self, base, slant_height, **kwargs]:
self.base = base
self.slant_height = slant_height
kwargs["height"] = slant_height
kwargs["length"] = base
super[].__init__[base=base, **kwargs]
def area[self]:
base_area = super[].area[]
perimeter = super[].perimeter[]
return 0.5 * perimeter * self.slant_height + base_area
def area_2[self]:
base_area = super[].area[]
triangle_area = super[].tri_area[]
return triangle_area * 4 + base_area
21 trong lớp SurfaceAreaMixin sử dụng class Rectangle:
def __init__[self, length, width, **kwargs]:
self.length = length
self.width = width
super[].__init__[**kwargs]
def area[self]:
return self.length * self.width
def perimeter[self]:
return 2 * self.length + 2 * self.width
class Square[Rectangle]:
def __init__[self, length, **kwargs]:
super[].__init__[length=length, width=length, **kwargs]
class Triangle:
def __init__[self, base, height, **kwargs]:
self.base = base
self.height = height
super[].__init__[**kwargs]
def tri_area[self]:
return 0.5 * self.base * self.height
class RightPyramid[Square, Triangle]:
def __init__[self, base, slant_height, **kwargs]:
self.base = base
self.slant_height = slant_height
kwargs["height"] = slant_height
kwargs["length"] = base
super[].__init__[base=base, **kwargs]
def area[self]:
base_area = super[].area[]
perimeter = super[].perimeter[]
return 0.5 * perimeter * self.slant_height + base_area
def area_2[self]:
base_area = super[].area[]
triangle_area = super[].tri_area[]
return triangle_area * 4 + base_area
22 mà bạn đã định nghĩa trong các lớp con. Điều đó nghe có vẻ hơi kỳ lạ đối với tôi. Làm cách nào để tôi biết từ lớp Mixin mà tôi phải xác định các biến thể hiện nào để phương thức không gặp sự cố với AttributeError. Đó có phải là thực hành tốt nhất? Cảm ơn, Rik
Christopher Trudeau Nhóm RP trên
Xin chào @rikhuygen,
Đúng, đây là một trong những thách thức khi cố gắng dạy mixin và các bài học hướng đối tượng. Việc sử dụng thực sự tốt loại công nghệ này có xu hướng yêu cầu nhiều thông tin cơ bản hơn
Toàn bộ điều "sử dụng hình dạng" để giải thích tính kế thừa OO đã được thử và đúng nhưng có những hạn chế của nó. Ngay cả khi tôi định viết một giao diện đồ họa sử dụng các hình dạng, tôi có thể sẽ không sử dụng hết OO hoặc nếu có, lớp cơ sở sẽ nhẹ hơn nhiều so với được sử dụng trong các giải thích thông thường
Nơi tốt nhất cho những thứ như Mixins là nơi bạn có nhiều quyền độc lập và đang cố gắng thêm một tính năng không cụ thể
Ví dụ: gần đây tôi đã viết một cái gì đó bằng Django yêu cầu một loại định danh đặc biệt. Mã định danh phức tạp hơn một chút so với chỉ một trường và cần một số phương thức. Tất cả những thứ này được đặt bên trong một mixin để bất kỳ đối tượng Django nào cần loại định danh này sẽ trộn nó vào. Vấn đề với việc giảng dạy với loại ví dụ này là sau đó bạn phải giải thích Django là gì và cách nó mô hình hóa các đối tượng và cách điều đó liên quan đến các trường và toàn bộ nội dung khác
Đối với câu hỏi cụ thể của bạn, lượng mã được lưu bằng cách sử dụng mixin này có thể không đảm bảo việc ẩn quá trình triển khai diễn ra theo cách nó được thực hiện. Trong thế giới thực, có lẽ tôi sẽ không viết mã theo cách đó, nhưng sau đó tôi sẽ không có ví dụ về mixin