Mam coś mniej więcej podobnego do następującego. Zasadniczo muszę uzyskać dostęp do klasy metody instancji z dekoratora używanego w metodzie instancji w jej definicji.
def decorator(view):
# do something that requires view's class
print view.im_class
return view
class ModelA(object):
@decorator
def a_method(self):
# do some stuff
pass
Kod taki jaki jest daje:
AttributeError: obiekt „function” nie ma atrybutu „im_class”
Znalazłem podobne pytanie / odpowiedzi - dekorator Pythona sprawia, że funkcja zapomina, że należy do klasy, a klasa Get w dekoratorze Pythona - ale te polegają na obejściu, które przechwytuje instancję w czasie wykonywania, przechwytując pierwszy parametr. W moim przypadku będę wywoływał metodę na podstawie informacji zebranych z jej klasy, więc nie mogę się doczekać, aż zadzwoni.
inspect.getmro(cls)
do przetwarzania wszystkich klas bazowych w dekoratorze klas w celu obsługi dziedziczenia.inspect
na ratunek stackoverflow.com/a/1911287/202168Od Pythona 3.6 możesz tego użyć
object.__set_name__
w bardzo prosty sposób. Dokument stwierdza, że__set_name__
jest „wywoływany w momencie tworzenia właściciela klasy będącej właścicielem ”. Oto przykład:Zauważ, że jest wywoływany w czasie tworzenia klasy:
Jeśli chcesz dowiedzieć się więcej o tym, jak powstają zajęcia, a zwłaszcza kiedy
__set_name__
jest wywoływana, zapoznaj się z dokumentacją „Tworzenie obiektu klasy” .źródło
@class_decorator('test', foo='bar')
def decorator(*args, **kwds): class Descriptor: ...; return Descriptor
__set_name__
chociaż używam Pythona 3.6+ od dłuższego czasu.hello
to nie jest metoda, ale jest to obiekt typuclass_decorator
.if TYPE_CHECKING
aby zdefiniowaćclass_decorator
jako normalny dekorator zwracający prawidłowy typ.Jak zauważyli inni, klasa nie została utworzona w momencie wywołania dekoratora. Jednakże , możliwe jest opisanie przedmiotu funkcyjny parametrów dekorator, a następnie ponownie dekoracji funkcję metaklasą w
__new__
metodzie. Będziesz musiał uzyskać__dict__
bezpośredni dostęp do atrybutu funkcji , co najmniej dla mnie,func.foo = 1
spowodowało powstanie AttributeError.źródło
setattr
powinno być używane zamiast dostępu__dict__
Jak sugeruje Mark:
Ten kod pokazuje, jak to może działać przy użyciu automatycznego przetwarzania końcowego:
Wydajność daje:
Zwróć uwagę, że w tym przykładzie:
Mam nadzieję że to pomoże
źródło
Jak wskazał Ants, nie można uzyskać odwołania do klasy z poziomu tej klasy. Jeśli jednak chcesz rozróżniać różne klasy (a nie manipulować rzeczywistym obiektem typu klasy), możesz przekazać ciąg znaków dla każdej klasy. Możesz również przekazać dekoratorowi dowolne inne parametry, używając dekoratorów w stylu klasowym.
Wydruki:
Zobacz także stronę Bruce'a Eckela o dekoratorach.
źródło
@decorator('Bar')
. W przeciwieństwie do@Decorator('Bar')
.To, co robi flask-classy , to utworzenie tymczasowej pamięci podręcznej, którą przechowuje w metodzie, a następnie używa czegoś innego (fakt, że Flask zarejestruje klasy przy użyciu
register
metody klas), aby faktycznie opakować metodę.Możesz ponownie użyć tego wzorca, tym razem używając metaklasy, aby móc opakować metodę w czasie importu.
Na rzeczywistej klasie (możesz zrobić to samo, używając metaklasy):
Źródło: https://github.com/apiguy/flask-classy/blob/master/flask_classy.py
źródło
Problem polega na tym, że gdy wywoływany jest dekorator, klasa jeszcze nie istnieje. Spróbuj tego:
Ten program wyświetli:
Jak widzisz, będziesz musiał wymyślić inny sposób robienia tego, co chcesz.
źródło
Oto prosty przykład:
Wynik to:
źródło
To stare pytanie, ale trafiło na wenusjański. http://venusian.readthedocs.org/en/latest/
Wydaje się, że ma możliwość dekorowania metod i zapewnia dostęp zarówno do klasy, jak i do metody. Zwróć uwagę, że dzwonienie
setattr(ob, wrapped.__name__, decorated)
nie jest typowym sposobem używania wenusjańskiego i w pewnym sensie przeczy celowi.Tak czy inaczej ... poniższy przykład jest kompletny i powinien działać.
źródło
Funkcja nie wie, czy jest to metoda w punkcie definicji, kiedy działa kod dekoratora. Tylko wtedy, gdy uzyskuje się do niego dostęp za pośrednictwem identyfikatora klasy / instancji, może znać swoją klasę / instancję. Aby przezwyciężyć to ograniczenie, możesz dekorować za pomocą obiektu deskryptora, aby opóźnić faktyczny kod dekorujący do czasu dostępu / połączenia:
Pozwala to na dekorowanie pojedynczych (statycznych | klasowych) metod:
Teraz możesz użyć kodu dekoratora do introspekcji ...
... i do zmiany zachowania funkcji:
źródło
</sigh>
Jak wskazywały inne odpowiedzi, dekorator jest rzeczą związaną z funkcją, nie możesz uzyskać dostępu do klasy, do której należy ta metoda, ponieważ klasa ta nie została jeszcze utworzona. Jednak całkowicie w porządku jest użyć dekoratora do „zaznaczenia” funkcji, a następnie użyć technik metaklas, aby zająć się metodą później, ponieważ na
__new__
etapie klasa została utworzona za pomocą metaklasy.Oto prosty przykład:
Używamy
@field
do oznaczenia metody jako specjalnego pola i zajmujemy się nią w metaklasie.źródło
if inspect.isfunction(v) and getattr(k, "is_field", False):
tego powinno byćgetattr(v, "is_field", False)
.Będziesz mieć dostęp do klasy obiektu, dla którego wywoływana jest metoda w metodzie dekorowanej, którą Twój dekorator powinien zwrócić. Tak jak to:
Używając klasy ModelA, oto co to robi:
źródło
Chcę tylko dodać mój przykład, ponieważ zawiera on wszystkie rzeczy, o których mógłbym pomyśleć, aby uzyskać dostęp do klasy z metody dekorowanej. Używa deskryptora, jak sugeruje @tyrion. Dekorator może przyjąć argumenty i przekazać je do deskryptora. Może obsługiwać zarówno metodę w klasie, jak i funkcję bez klasy.
źródło