W pełni zdaję sobie sprawę, że pylint
i inne narzędzia analizy statycznej nie są wszechwiedzące, a czasem ich radom należy się nie posłuchać. (Dotyczy to różnych klas wiadomości, nie tylko convention
s.)
Jeśli mam zajęcia takie jak
class related_methods():
def a_method(self):
self.stack.function(self.my_var)
class more_methods():
def b_method(self):
self.otherfunc()
class implement_methods(related_methods, more_methods):
def __init__(self):
self.stack = some()
self.my_var = other()
def otherfunc(self):
self.a_method()
Oczywiście jest to wymyślone. Oto lepszy przykład, jeśli chcesz .
Uważam, że ten styl nazywa się przy użyciu „miksów”.
Podobnie jak inne narzędzia, pylint
ocenia ten kod na -21.67 / 10
, przede wszystkim dlatego, że myśli more_methods
i related_methods
nie ma self
atrybutów otherfunc
, a także dlatego stack
, my_var
że bez uruchomienia kodu najwyraźniej nie widzi related_methods
i nie more_methods
jest w to zamieszany implement_methods
.
Kompilatory i narzędzia do analizy statycznej nie zawsze mogą rozwiązać problem zatrzymania , ale uważam, że jest to z pewnością przypadek, w którym sprawdzenie, co odziedziczyłoby implement_methods
, pokazałoby, że jest to całkowicie poprawne, i to byłoby bardzo łatwe.
Dlaczego narzędzia analizy statycznej odrzucają ten prawidłowy (myślę) wzór OOP?
Zarówno:
Nie próbują nawet sprawdzać dziedziczenia lub
mixiny są odradzane w idiomatycznym, czytelnym Pythonie
# 1 jest oczywiście niepoprawny, ponieważ jeśli poproszę pylint
o powiedzenie mi o klasie, która dziedziczy, unittest.TestCase
że używa self.assertEqual
((coś zdefiniowanego tylko w unittest.TestCase
)), to nie narzeka.
Czy miksy są niepytoniczne czy zniechęcone?
Odpowiedzi:
Mixiny po prostu nie są przypadkiem użycia rozważanym przez narzędzie. To nie znaczy, że niekoniecznie jest to zły przypadek użycia, po prostu rzadki dla Pythona.
To, czy miksy są odpowiednio stosowane w konkretnym przypadku, to inna sprawa. Anty-wzorzec mixinowy, który widzę najczęściej, używa mixin, gdy kiedykolwiek ma być tylko jedna kombinacja mieszana. To tylko okrągły sposób na ukrycie klasy boga. Jeśli nie można myśleć o przyczyny tej chwili zamienić się lub opuścić jedną z wstawek, nie powinno być wstawek.
źródło
Wierzę, że Mixiny mogą być absolutnie Pythonic. Jednak idiomatycznym sposobem wyciszenia linera - i poprawienia czytelności Mixinów - jest zarówno (1) zdefiniowanie metod abstrakcyjnych, które jawnie określają metody, które dzieci Mixina muszą wdrożyć, oraz (2) wstępne zdefiniowanie
None
-wartościowe pola dla członków danych Mixin, które dzieci muszą zainicjować.Zastosowanie tego wzoru do Twojego przykładu:
źródło
abstract other(self): pass
rzecz zamienia zamieszanie liniowca na mojeMyślę, że mixiny mogą być dobre, ale myślę, że pylint ma rację w tym przypadku. Zastrzeżenie: następujące rzeczy oparte na opiniach.
Dobra klasa, w tym mixiny, ma jedną wyraźną odpowiedzialność. Idealnie, mixin powinien przenosić cały stan, do którego ma dostęp, i logikę do obsługi. Np. Dobry mixin może dodać
last_updated
pole do klasy modelu ORM, zapewnić logikę do jego ustawiania oraz metody wyszukiwania najstarszego / najnowszego rekordu.Odwoływanie się do niezadeklarowanych członków instancji (zmiennych i metod) wygląda trochę dziwnie.
Właściwe podejście bardzo zależy od danego zadania.
Może to być mixin z zachowanym odpowiednim bitem stanu.
Może to być inna hierarchia klas, w której metody, które obecnie rozpowszechniasz za pomocą mixinu, należą do klasy podstawowej, podczas gdy różnice w implementacji niższego poziomu należą do podklas. Wygląda to najbardziej pasujące do twojego przypadku z operacjami stosu.
Może to być dekorator klasy, który dodaje metodę lub dwie; zwykle ma to sens, gdy trzeba przekazać argumentowi dekoratorowi, aby wpłynąć na generowanie metody.
Podaj swój problem, wyjaśnij swoje większe obawy dotyczące projektu, a następnie możemy spierać się, czy w Twoim przypadku coś jest anty-wzorem.
źródło
Linter nie wie, że używasz klasy jako mixin. Pylint jest świadomy, że używasz mixinu, jeśli dodasz sufiks „mixin” lub „Mixin” na końcu nazwy klasy, wówczas linijka przestaje narzekać.
Mixiny nie są złe ani dobre same w sobie, są tylko narzędziem. Sprawiasz, że są dobre lub złe.
źródło
Czy mixiny są w porządku?
Mixiny nie są odradzane - stanowią dobry przypadek wielokrotnego dziedziczenia.
Dlaczego twój linter narzeka?
Pylint skarży się oczywiście, bo nie wiem gdzie
otherfunc
,stack
imy_var
pochodzi.Trywialny?
Nie ma od razu widocznego dobrego powodu, abyś podzielił te dwie metody na osobne klasy nadrzędne, ani w twoim przykładzie w pytaniu, ani w bardziej trywialnym połączonym przykładzie, pokazanym tutaj.
Koszty miksów i hałasu
Koszty związane z tym, co robisz, powodują, że Twój linter zgłasza hałas. Ten hałas może zasłaniać ważniejsze problemy z kodem. Ważenie to ważny koszt. Kolejnym kosztem jest to, że dzielisz swój powiązany kod na różne przestrzenie nazw, co może utrudnić programistom odkrycie znaczenia.
Wniosek
Dziedziczenie pozwala na ponowne użycie kodu. Jeśli ponownie wykorzystasz kod ze swoimi miksami, to świetnie, stworzyły one dla ciebie wartość, która prawdopodobnie przewyższa ewentualne inne koszty. Jeśli nie otrzymujesz ponownego użycia / deduplikacji kodu linii kodu, prawdopodobnie nie zyskujesz zbyt wiele na swoich miksach, i w tym momencie myślę, że koszt hałasu jest większy niż korzyści.
źródło