W jednym z moich projektów, musiałem też zrobić jedną konkretną rzecz, że jest to, że nawet podstawowa obiekt powinien właściwie wykonać metodę został ponownie zastosowany w dekoratorze. W rzeczywistości jest to dość łatwe, jeśli wiesz, gdzie celować.
Przypadek stosowanie jest:
- mam obiektu X ze sposobami A i B.
- Tworzę klasę dekoratora Y, która zastępuje A.
- Jeśli zainicjuję Y (X) i zadzwonię A, użyje on udekorowanego A zgodnie z oczekiwaniami.
- Jeśli B zadzwoni A, to jeśli zainicjuję Y (X) i wywołasz B na dekoratorze, wywołanie z wnętrza B następnie przechodzi do starego A na pierwotnym obiekcie, co było niepożądane. Chcę, żeby stary B również nazwał nowy A.
Jest możliwe, aby osiągnąć ten problem tak:
import inspect
import six # for handling 2-3 compatibility
class MyBaseDecorator(object):
def __init__(self, decorated):
self.decorated = decorated
def __getattr__(self, attr):
value = getattr(self.decorated, attr)
if inspect.ismethod(value):
function = six.get_method_function(value)
value = function.__get__(self, type(self))
return value
class SomeObject(object):
def a(self):
pass
def b(self):
pass
class MyDecorator(MyBaseDecorator):
def a(self):
pass
decorated = MyDecorator(SomeObject())
ta może nie działać po wyjęciu z pudełka, jak Wpisałem wszystko inne oprócz metody getattr od wierzchołka głowy.
Kod wyszukuje żądany atrybut w dekorowanym obiekcie, a jeśli jest to metoda (nie działa teraz dla właściwości, ale zmiana w celu ich obsługi nie powinna być zbyt trudna), kod pobiera następnie rzeczywistą wartość funkcja poza metodą i za pomocą wywołania interfejsu deskryptora "rebinduje" funkcję jako metodę, ale na dekoratorze. Następnie jest zwracana i najprawdopodobniej wykonywana.
Efekt jest taki, że jeśli b
kiedykolwiek wywoła a
na oryginalnym obiekcie, wtedy gdy obiekt zostanie udekorowany i wywoływane jest dowolne wywołanie metody z dekoratora, dekorator upewnia się, że wszystkie metody dostępne są powiązane z obiektem. dekorator zamiast tego, dlatego przegląda rzeczy przy użyciu dekoratora, a nie oryginalnego obiektu, dlatego metody określone w dekoratorze mają pierwszeństwo.
P.S .: Tak, wiem, że wygląda prawie jak dziedzictwo, ale odbywa się to w sensie kompozycji wielu obiektów.
Czy możesz podać przykład, w którym proste podklasy nie działa? Możesz też podklasować dynamicznie - ten wzorzec wydaje się być obejściem dla języków, które nie mogą tego zrobić lub nie obsługują wielu dziedzin. –
Chcę udekorować obiekty w czasie wykonywania. Chcę zastosować różne dekoratory do obiektu i móc je ponownie usunąć. Podklasy nie można zmienić instancji po jej utworzeniu, czy też nie? –
Jeśli masz klasę 'A' i zmienisz' A', tj. Dodanie nowej metody, 'A.foo = lambda self: self', to będzie odzwierciedlać wszystkie wystąpienia A .. ponieważ * wszystko * jest określane w czasie wykonywania. Świetny sposób na stworzenie absolutnie nieosiągalnego kodu. –