Ron_Adam wrote: > def decorator(d_arg): # (7) Get 'Goodbye' off stack > > def get_function(function): # (8) Get func object off stack > > def wrapper(f_arg): # (9) Get 'Hello' off stack > > new_arg = f_arg+'-'+d_arg > result = function(new_arg) # (10) Put new_arg on stack > # (11) Call func object > > return result # (14) Return result to wrapper > > return wrapper # (15) Return result to get_function > > return get_function # (16) Return result to caller of func > > @decorator('Goodbye') # (5) Put 'Goodbye' on stack > # (6) Do decorator > > def func(s): # (12) Get new_arg off stack > > return s # (13) Return s to result
There is actually nothing mysterious about decorators. It is nothing more than ordinary function composition, executed when the decorated function is defined. In case of Your definition it, the composition rules are: decorator("Goodbye")(func)(s) = get_function(func)(s) = wrapper(s), where wrapper stores "Goodbye" in the local d_arg. Or a bit more formally we state the composition principle: Args x Func -> Func, where decorator() is a function of Args, that returns a function Func -> Func. As Guido had shown recently in his Artima blog, Func need not be an instance of an ordinary function but can be a function-object like his MultiMethod : http://www.artima.com/weblogs/viewpost.jsp?thread=101605 It is also possible to extend this view by "chaining" decorators. decorator : Args(2) x (Args(1) x Func - > Func ) -> Func. To understand decorator chains it is very helpfull to accept the functional view instead of arguing in a procedural picture i.e. pushing and popping arguments onto and from the stack. Someone asked once for a solution of the following problem that is similar in character to Guidos multimethod but some more general. def mul(m1,m2): def default(m1,m2): return "default",1+m1*m2 def mul_dec(m1,m2): return "mul_dec",Decimal(str(m1))*Decimal(str(m2)) def mul_float(m1,m2): return "mul_float",m1*m2 return (default,mul_dec,mul_float) The function mul defines the inner functions default, mul_float and mul_dec. What we want is a unified access to this functions by means of mul. Guidos solution would decompose mul in three different versions of mul: @multimethod(int,float) def mul(m1,m2): return m1*m2 @multimethod(float,float) def mul(m1,m2): return m1*m2 @multimethod(Decimal,Decimal) def mul(m1,m2): return m1*m2 but it is hard to tell, what should be done if no argument tuple matches. An attempt like: @multimethod(object,object) def mul(m1,m2): return 1+m1*m2 would be useless, because there is no concrete match of argument types onto (object,object). So I introduced an "external switch" over argument tuples, using a decorator chain: @case(None,"default") @case((float,float),'mul_float') @case((int,float),'mul_float') @case((Decimal,Decimal),'mul_dec') def mul(m1,m2): def default(m1,m2): return "default",1+m1*m2 def mul_dec(m1,m2): return "mul_dec",Decimal(str(m1))*Decimal(str(m2)) def mul_float(m1,m2): return "mul_float",m1*m2 return (default,mul_dec,mul_float) Can You imagine how "case" works internally? Regards, Kay -- http://mail.python.org/mailman/listinfo/python-list