Hướng dẫn c3 linearization algorithm python - python thuật toán tuyến tính hóa c3
Show Trong phần trước, mình đã đề cập các tính chất cơ bản của class trong Python. Trong số này, mình sẽ đề cập về cách tính chất, đặc điểm nâng cao của class. I. Kế thừa nhiều classes (Multi-inheritance)Không như Java — ngôn ngữ chỉ cho kế thừa một class duy nhất cho một class, Python cho phép cho chúng ta kết thừa nhiều class cho một class. Ví dụ:
Kết quả của Child.bases trong trường hợp này đó là:
II. Tìm attributes với kế thừaTheo logic, quá trình tìm kiếm attributes như sau:
Mình sẽ làm rõ ý cuối cùng ở các phần tiếp theo của bài. III. MROMRO là tên viết tắt của Method Resolution Order. Là một chuỗi inheritance mà Python tính toán và lưu nó ở MRO attribute trong class. Như đã nói ở trên khi tìm attributes, Python sẽ đi lần lượt qua các phần tử trong MRO. Để xem MRO của một class, ta dùng cú pháp ".__mro__". Ví dụ: def mro(cls: type) -> List[type]: """ Return a list of classes in order corresponding to Python's MRO. """ result = [cls] if not cls.__bases__: return result else: return result + _merge(*[mro(kls) for kls in cls.__bases__], cls.__bases__)0 Output: def mro(cls: type) -> List[type]: """ Return a list of classes in order corresponding to Python's MRO. """ result = [cls] if not cls.__bases__: return result else: return result + _merge(*[mro(kls) for kls in cls.__bases__], cls.__bases__)1 Python sử dụng cooperative multiple inheritance để quy định một số luật về thứ tự của class:
Để hiểu rõ hơn, các bạn hãy thử động não, thử giải thích MRO của class E dưới đây: def mro(cls: type) -> List[type]: """ Return a list of classes in order corresponding to Python's MRO. """ result = [cls] if not cls.__bases__: return result else: return result + _merge(*[mro(kls) for kls in cls.__bases__], cls.__bases__)2 Thuật toán này là có tên là "C3 Linearization Algorithm" nhưng để đơn giản và nhớ hiểu, hãy tưởng tượng đến thứ tự thoát hiểm khi một sự cố như cháy nhà, chìm tàu xảy ra: "Trẻ em đầu tiên, sau đó mới là người lớn" (Children first, followed by parents). IV. Ví dụ về multi-inheritancedef mro(cls: type) -> List[type]: """ Return a list of classes in order corresponding to Python's MRO. """ result = [cls] if not cls.__bases__: return result else: return result + _merge(*[mro(kls) for kls in cls.__bases__], cls.__bases__)3 def mro(cls: type) -> List[type]: """ Return a list of classes in order corresponding to Python's MRO. """ result = [cls] if not cls.__bases__: return result else: return result + _merge(*[mro(kls) for kls in cls.__bases__], cls.__bases__)4 def mro(cls: type) -> List[type]: """ Return a list of classes in order corresponding to Python's MRO. """ result = [cls] if not cls.__bases__: return result else: return result + _merge(*[mro(kls) for kls in cls.__bases__], cls.__bases__)5 super() sẽ gọi class kế tiếp của class hiện tại trong MRO Ví dụ: MRO của NoisyPerson: def mro(cls: type) -> List[type]: """ Return a list of classes in order corresponding to Python's MRO. """ result = [cls] if not cls.__bases__: return result else: return result + _merge(*[mro(kls) for kls in cls.__bases__], cls.__bases__)6 Thử gọi method talks của NoisyPerson instance: def mro(cls: type) -> List[type]: """ Return a list of classes in order corresponding to Python's MRO. """ result = [cls] if not cls.__bases__: return result else: return result + _merge(*[mro(kls) for kls in cls.__bases__], cls.__bases__)7 Output: def mro(cls: type) -> List[type]: """ Return a list of classes in order corresponding to Python's MRO. """ result = [cls] if not cls.__bases__: return result else: return result + _merge(*[mro(kls) for kls in cls.__bases__], cls.__bases__)8 Khi talk() method của girl được gọi, do bản thân NoisyPerson không có method này nên nó sẽ tìm ở class tiếp theo trong MRO là Noisy. Noisy có talk() method sẽ được execute. super().talk() sẽ tìm gọi method talk() của class kế tiếp trong MRO - Person (return 'alo alo'). Đoạn string 'alo alo' này sẽ được upper() và return. Do đó output trả về là "ALO ALO" Bây giờ nếu ta đổi chỗ 2 parent classes với nhau thì sao? def mro(cls: type) -> List[type]: """ Return a list of classes in order corresponding to Python's MRO. """ result = [cls] if not cls.__bases__: return result else: return result + _merge(*[mro(kls) for kls in cls.__bases__], cls.__bases__)9 Chạy lại talks method def _merge(*lists) -> list: result: List[Optional[type]] = [] linearizations = DependencyList(*lists) while True: if linearizations.exhausted: return result for head in linearizations.heads: if head and (head not in linearizations.tails): # type: ignore result.append(head) linearizations.remove(head) # Once candidate is found, continue iteration # from the first element of the list break else: # Loop never broke, no linearization could possibly be found raise ValueError('Cannot compute linearization, a cycle found')0 Output: def _merge(*lists) -> list: result: List[Optional[type]] = [] linearizations = DependencyList(*lists) while True: if linearizations.exhausted: return result for head in linearizations.heads: if head and (head not in linearizations.tails): # type: ignore result.append(head) linearizations.remove(head) # Once candidate is found, continue iteration # from the first element of the list break else: # Loop never broke, no linearization could possibly be found raise ValueError('Cannot compute linearization, a cycle found')1 Đây là MRO của NoisyPerson bây giờ: def _merge(*lists) -> list: result: List[Optional[type]] = [] linearizations = DependencyList(*lists) while True: if linearizations.exhausted: return result for head in linearizations.heads: if head and (head not in linearizations.tails): # type: ignore result.append(head) linearizations.remove(head) # Once candidate is found, continue iteration # from the first element of the list break else: # Loop never broke, no linearization could possibly be found raise ValueError('Cannot compute linearization, a cycle found')2 Ta thấy class Person được kiểm tra trước Noisy, trong khi đó Person có method talks() nên nó sẽ được execute. V. Kết luậnQua hai phần về chủ đề class, hy vọng các bạn có thêm kiến thức về class và có thể áp dụng nó vào trong công việc của mình. Các bạn hãy đón chờ các bài tiếp theo về chủ đề Python trên tech blog BizFly Cloud nha! 02-05-2019 12:10 | | trong blog | 851 từ | 4 phút để đọc lại: Python Cpython MRO Thuật toán | | in Blog | 851 words | 4 min to read Thứ tự độ phân giải phương pháp (MRO) là một thứ tự trong đó các phương thức nên được kế thừa trong trường hợp nhiều iheritance. Thuật toán tuyến tính hóa C3 là cách MRO hoạt động dưới mui xe kể từ phiên bản 2.3.MRO) is a order in which methods should be inherited in the case of multiple iheritance. C3 linearization algorithm is how MRO works under the hood since version 2.3. Wikipedia thực hiện một công việc tuyệt vời giải thích thuật toán. Nó có thể được giảm xuống các bước sau & nbsp; các bước:
Ví dụ nhiều kế thừa phức tạp, lịch sự H2Power Xem xét quá trình tuyến tính hóa cho lớp K1: // first, find the linearizations of K1's parents, L(A), L(B), and L(C), // and merge them with the parent list [A, B, C] L(K1) := [K1] + merge(L(A), L(B), L(C), [A, B, C]) // class A is a good candidate for the first merge step, because it only // appears as the head of the first and last lists = [K1] + merge([A, O], [B, O], [C, O], [A, B, C]) // class O is not a good candidate for the next merge step, because it also // appears in the tails of list 2 and 3; but class B is a good candidate = [K1, A] + merge([O], [B, O], [C, O], [B, C]) // class C is a good candidate; class O still appears in the tail of list 3 = [K1, A, B] + merge([O], [O], [C, O], [C]) // finally, class O is a valid candidate, which also exhausts all remaining lists = [K1, A, B, C] + merge([O], [O], [O]) = [K1, A, B, C, O] Vì vậy, ở cấp độ cao hơn, việc triển khai ngây thơ của thuật toán tuyến tính hóa C3 có thể được biểu thị dưới dạng đơn giản & nbsp; đệ quy: đệ quy: def mro(cls: type) -> List[type]: """ Return a list of classes in order corresponding to Python's MRO. """ result = [cls] if not cls.__bases__: return result else: return result + _merge(*[mro(kls) for kls in cls.__bases__], cls.__bases__) Sau đó, _merge liên tục kiểm tra xem danh sách của nó có cạn kiệt và nối các đầu thích hợp vào MRO kết quả:MRO: def _merge(*lists) -> list: result: List[Optional[type]] = [] linearizations = DependencyList(*lists) while True: if linearizations.exhausted: return result for head in linearizations.heads: if head and (head not in linearizations.tails): # type: ignore result.append(head) linearizations.remove(head) # Once candidate is found, continue iteration # from the first element of the list break else: # Loop never broke, no linearization could possibly be found raise ValueError('Cannot compute linearization, a cycle found') Để ẩn một số danh sách phụ thuộc nội bộ và sự trừu tượng của danh sách phụ thuộc là & nbsp; được sử dụng: from collections import deque from itertools import islice from typing import List, Tuple, Optional class Dependency(deque): @property def head(self) -> Optional[type]: try: return self[0] except IndexError: return None @property def tail(self) -> islice: # type: ignore """ Return islice object, which is suffice for iteration or calling `in` """ try: return islice(self, 1, self.__len__()) except (ValueError, IndexError): return islice([], 0, 0) class DependencyList: """ A class represents list of linearizations (dependencies) The last element of DependencyList is a list of parents. It's needed to the merge process preserves the local precedence order of direct parent classes. """ def __init__(self, *lists: Tuple[List[type]]) -> None: self._lists = [Dependency(i) for i in lists] def __contains__(self, item: type) -> bool: """ Return True if any linearization's tail contains an item """ return any([item in l.tail for l in self._lists]) # type: ignore def __len__(self): size = len(self._lists) return (size - 1) if size else 0 def __repr__(self): return self._lists.__repr__() @property def heads(self) -> List[Optional[type]]: return [h.head for h in self._lists] @property def tails(self) -> 'DependencyList': # type: ignore """ Return self so that __contains__ could be called Used for readability reasons only """ return self @property def exhausted(self) -> bool: """ Return True if all elements of the lists are exhausted """ return all(map(lambda x: len(x) == 0, self._lists)) def remove(self, item: Optional[type]) -> None: """ Remove an item from the lists Once an item removed from heads, the leftmost elements of the tails get promoted to become the new heads. """ for i in self._lists: if i and i.head == item: i.popleft() Toàn bộ cơ sở mã có thể được tìm thấy trong kho lưu trữ C3linear của tôi. Bạn có thể cài đặt nó từ mã nguồn hoặc thông qua & nbsp; pypi: python setup.py install # from the source code pip install c3linear # from the Cheese Shop Sau đó, chỉ cần nhập nó và kiểm tra đối với phương pháp MRO của Python đối tượng: from c3linear.mro import mro class A: pass class B(A): pass mro(B) == B.mro() Hãy xem các bài kiểm tra để đi sâu vào nhiều kế thừa phức tạp hơn & nbsp; ví dụ. |