Created
June 12, 2017 11:07
-
-
Save dundee/c429f02d842ba82283de31aa05b05691 to your computer and use it in GitHub Desktop.
Decorator for both functions and methods using descriptor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from functools import wraps | |
class DomainObject: | |
# nejaky domenovy objekt, ktery vyzaduje hodne parametru | |
def __init__(self, root, args, context, info): | |
pass | |
def process(self): | |
return 'OK' | |
# dekorator ktery nam pomuze vytvorit DomainObject | |
# a bude fungovat jak pro metody tak i funkce | |
class DomainArgs: | |
def __init__(self, func): | |
self.func = func | |
wraps(func)(self) | |
def __call__(self, root, args, context, info): | |
helper = DomainObject(root, args, context, info) | |
return self.func(helper) | |
# Vytvorime deskriptor, ktery simuluje chovani metod a funkci v Pythonu: | |
# kazda funkce je v pythonu deskriptor (ma metodu __get__), takze kdyz funkci | |
# dame na tridu, tak se pred zavolanim funkce zavola nejdriv jeji metoda __get__, ktera vrati | |
# boundnutou verzi funkce. | |
def __get__(self, instance, owner): | |
# vytvorim boudnutou metodu | |
# boundnuti dela neco jako functools.partial, tedy preda self a vrati funkci pro dalsi volani | |
mapped = self.func.__get__(instance, owner) | |
# vratim sam sebe, pricemz do konstruktoru predam jako func tu boundnutou metodu | |
return self.__class__(mapped) | |
class ViewResolver: | |
# metoda, ve ktere chceme vytvorit DomainObject, ale nechceme vypisovat vsechny parametry, ktere potrebuje | |
# proto si nechame vytvorit objekt dekoratorem DomainArgs a ten nam preda objekt jako parametr helper | |
@DomainArgs | |
def resolve_method(self, helper): | |
response = helper.process() | |
return f"Method: {response}" | |
# to stejne musi fungovat i pro funkci | |
@DomainArgs | |
def resolve_method(helper): | |
response = helper.process() | |
return f"Method: {response}" | |
res = ViewResolver().resolve_method('/', [], {}, None) | |
print(res) | |
res = resolve_method('/', [], {}, None) | |
print(res) | |
# volani metody Trida().metoda('y') se tedy da prepsat jako: | |
# Trida.metoda(Trida(), 'y') | |
# a nebo prave pomoci deskriptoru na: Trida.metoda.__get__(Trida())('y') | |
# coz je to co dela interne Python pro metody | |
# Trida.metoda.__get__(Trida()) vraci <bound method Trida.metoda...> | |
# coz je to stejne, co uvidim, kdyz vytvorim instanci Trida a zkusim pristoupit na metodu na te instanci | |
# Proto u instancnich metod neni videt zvenku uz self, neni to uz ta puvodni "funkce", ale boundnuta metoda, kterou vratil deskriptor. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment