Re: Decorator Base Class: Needs improvement.
On Wed, 06 Apr 2005 02:31:05 GMT, Ron_Adam [EMAIL PROTECTED] wrote: On Tue, 05 Apr 2005 19:38:38 -0400, Steve Holden [EMAIL PROTECTED] wrote: So what you are saying is that you would like to be able to use arbitrarily complex expressions after the :at sign, as long as they return a decorator? If so, you've been pronounced :-) regards Steve No not at all, I never said that. But.. ;-) If we get into what I would like, as in my personal wish list, that's a whole other topic. g I would have preferred the @ symbol to be used as an inline assert introducer. Which would have allowed us to put debug code anywhere we need. Such as @print total @. Then I can switch on and off debugging statements by setting __debug__ to True or False where ever I need it. And as far as decorators go. I would of preferred a keyword, possibly wrap, with a colon after it. Something like this. I don't understand your seeming fixation with wrappers and wrapping. That's not the only use for decorators. See Raymond Hettinger's optimizing decorators in the cookbook for instance. Decorators are something like metaclasses for functions, with much more general possibilities than wrapping, IMO. def function_name(x): return x wrap function_name: wrapper1() wrapper2() wrapper3() A wrap command could more directly accomplish the wrapping, so that def statements within def statements aren't needed. (Unless you want'ed too for some reason.) I think you'll have to show some convincing use cases showing a clear advantage over current decoration coding if you want converts ;-) And as far as arbitrary complex expressions go.. Actually I think that it's quite possible to do as it is. ;-) Yes and no. You can always write @deco and refer to an arbitrarily complex callable deco ..., but the actual @-line expression has to abide by the language grammar, and that does not allow arbitrary expressions. But it does provide enough rope. E.g. see my most recent reply to El Pitonero. But this is just a few of my current thoughts which may very well change. It's an ever changing list. g I can see that ;-) Regards, Bengt Richter -- http://mail.python.org/mailman/listinfo/python-list
Re: Decorator Base Class: Needs improvement.
Bengt Richter wrote: On 5 Apr 2005 19:28:55 -0700, El Pitonero [EMAIL PROTECTED] wrote: Scott David Daniels wrote: Ron_Adam wrote: ... def tweakdoc(name): def decorator(function): function.__doc__ = 'Tweak(%s) %r' % (name, function.__doc__) return function return decorator What is confusing us about what you write is that you are referring to tweakdoc as a decorator, when it is a function returning a decorator. Decorator factory would be a shorter name for a function returning a decorator. True, but tweakdoc doesn't have to be a function, so IMO we need a better name for the @-line, unless you want to use many various specific names like factory. E.g., There are two things: (1) The tweadoc object in the example, which no doubt can be called a decorator factory. (2) The @-line, which you called a decorator expression and that's fine with me. My preference would be something like the decorator header. A more clear statement would be something like: a decorator header expression or the expression in the decorator header, though your proposed decorator expression would be clear enough, too. I was addressing (1). You jumped in with (2), which I was aware of and was not dissenting. -- http://mail.python.org/mailman/listinfo/python-list
Re: Decorator Base Class: Needs improvement.
Bengt Richter wrote: @deco.one def foo(): pass Ok, now what do you call this @-line? Freaky decorator factory invocation? Decoratoriferous expression? ;-) This one has a certain je ne sais quoi ;-), but I'd call deco.one the decorator function (since it _must_ evaluate to a function), and if it needs more clarity, of your non-oderiferous proposals, I'd take: Decorator expression for short? --Scott David Daniels [EMAIL PROTECTED] -- http://mail.python.org/mailman/listinfo/python-list
Re: Decorator Base Class: Needs improvement.
On Wed, 06 Apr 2005 08:10:22 GMT, [EMAIL PROTECTED] (Bengt Richter) wrote: I don't understand your seeming fixation with wrappers and wrapping. Fixated implies, I'm stuck on a single thing, but I'm not. I am learning as I go, and exploring some possibilities as well. :-) That's not the only use for decorators. See Raymond Hettinger's optimizing decorators in the cookbook for instance. Thanks, I'll look for it. Is it in the new edition? I haven't picked it up yet. Decorators are something like metaclasses for functions, with much more general possibilities than wrapping, IMO. I'm not sure I see the metaclass relation. What more general things can be done with Decorators, that can't be done with a wrapper? Wrapping, and the @decorator expressions, interest me because I see a lot of potential in it's use, and so I'm trying to learn them, and at the same time, there are things about the @ expression that seems (to me), that it's not the most practical way to do what it was intended for. On the plus side, it's kind of cute with the little curly thing propped up on top of the function. It's a neat trick that it does what it does with a minimal amount of changes to the language by taking advantage of pythons existing function perimeter and object passing properties. It saves a bit of typing because we don't have to retype the function name a few times. (Several people have referred to it as 'sugar', and now I am starting to agree with that opinion.) On the minus side, it's not intuitive to use. It is attached to the function definitions so they are limited, they can't be easily unwrapped and rewrapped without redefining the function also. The recursive nature of stacked @ statements is not visible. So my opinion of @ as a whole is currently: -1 I think you'll have to show some convincing use cases showing a clear advantage over current decoration coding if you want converts ;-) What about the following? :-) # Using this simple wrapper class: class wrapper(object): def __call__(self,x): # preprocess x x*=2 # Make a change so we can see it result = self.function(x) # postprocuess result return result # A function to apply the wrapper: def wrap(function,wrapper): w = wrapper() w.function = function return w # The function def fn(x): return x print fn(5) # Before # Wrapit. fn = wrap(fn,wrapper) print fn(5) # After # Unwrap it. fn = fn.function print fn(5) # And back again #prints #5 #10 #5 It has several advantages over @ expression. It doesn't need the triple nested defines to get the function name and argument list, the wrapper is simpler, It can be placed on a function and then removed, when and where it's needed, instead of at the point where the function is defined. The following behaves more closely to the existing @ expression in that it has the same nesting behavior for stacked wrappers. I'm looking into a way to do sequential non-nested stacked wrappers at this point, where the output of one goes to the input of the next. That can't be done currently with the @ decorator expression. This stacks a list of 10 wrappers on 10 different functions and reverses the order of the stack every other function. In this case they are all the same, but they could all be differnt. Cheers, Ron #---start--- class wrapper(object): def __call__(self,*x): # preprocess x = [x[0]+1,] print 'preprocess', x[0], self.args # call function result = self.function(*x) # postprocess result +=1 print 'postprocess', result, self.args return result def wrap(f,w,shape='forward'): if shape=='reverse': w.reverse() for ww in w: nw = wrapper() try: nw.args = ww[1] except TypeError: wf = ww[0] nw.function = f f = nw return f # Make a list of ten wrappers with an id number as an additional # wrapper perimeter. w = [] for n in xrange(10): w.append((wrapper,n)) # Wrap 10 functions, 10 times, in reversing order. def func0(x): return x def func1(x): return x def func2(x): return x def func3(x): return x def func4(x): return x def func5(x): return x def func6(x): return x def func7(x): return x def func8(x): return x def func9(x): return x func0 = wrap(func0,w) func1 = wrap(func1,w,'reverse') func2 = wrap(func2,w) func3 = wrap(func3,w,'reverse') func4 = wrap(func4,w) func5 = wrap(func5,w,'reverse') func6 = wrap(func6,w) func7 = wrap(func7,w,'reverse') func8 = wrap(func8,w) func9 = wrap(func9,w,'reverse') print func0(0) print func1(0) print func2(0) print func3(0) print func4(0) print func5(0) print func6(0) print func7(0) print func8(0) print func9(0) #--end-- -- http://mail.python.org/mailman/listinfo/python-list
Re: Decorator Base Class: Needs improvement.
Ron_Adam wrote: On Wed, 06 Apr 2005 08:10:22 GMT, [EMAIL PROTECTED] (Bengt Richter) wrote: I don't understand your seeming fixation with wrappers and wrapping. Fixated implies, I'm stuck on a single thing, but I'm not. I am learning as I go, and exploring some possibilities as well. :-) That's not the only use for decorators. See Raymond Hettinger's optimizing decorators in the cookbook for instance. Thanks, I'll look for it. Is it in the new edition? I haven't picked it up yet. Decorators are something like metaclasses for functions, with much more general possibilities than wrapping, IMO. I'm not sure I see the metaclass relation. What more general things can be done with Decorators, that can't be done with a wrapper? Wrapping, and the @decorator expressions, interest me because I see a lot of potential in it's use, and so I'm trying to learn them, and at the same time, there are things about the @ expression that seems (to me), that it's not the most practical way to do what it was intended for. On the plus side, it's kind of cute with the little curly thing propped up on top of the function. It's a neat trick that it does what it does with a minimal amount of changes to the language by taking advantage of pythons existing function perimeter and object passing properties. It saves a bit of typing because we don't have to retype the function name a few times. (Several people have referred to it as 'sugar', and now I am starting to agree with that opinion.) On the minus side, it's not intuitive to use. It is attached to the function definitions so they are limited, they can't be easily unwrapped and rewrapped without redefining the function also. The recursive nature of stacked @ statements is not visible. So my opinion of @ as a whole is currently: -1 I think you'll have to show some convincing use cases showing a clear advantage over current decoration coding if you want converts ;-) What about the following? :-) # Using this simple wrapper class: class wrapper(object): def __call__(self,x): # preprocess x x*=2 # Make a change so we can see it result = self.function(x) # postprocuess result return result # A function to apply the wrapper: def wrap(function,wrapper): w = wrapper() w.function = function return w # The function def fn(x): return x print fn(5) # Before # Wrapit. fn = wrap(fn,wrapper) print fn(5) # After # Unwrap it. fn = fn.function print fn(5) # And back again #prints #5 #10 #5 It has several advantages over @ expression. It doesn't need the triple nested defines to get the function name and argument list, the wrapper is simpler, It can be placed on a function and then removed, when and where it's needed, instead of at the point where the function is defined. The following behaves more closely to the existing @ expression in that it has the same nesting behavior for stacked wrappers. I'm looking into a way to do sequential non-nested stacked wrappers at this point, where the output of one goes to the input of the next. That can't be done currently with the @ decorator expression. This stacks a list of 10 wrappers on 10 different functions and reverses the order of the stack every other function. In this case they are all the same, but they could all be differnt. Cheers, Ron #---start--- class wrapper(object): def __call__(self,*x): # preprocess x = [x[0]+1,] print 'preprocess', x[0], self.args # call function result = self.function(*x) # postprocess result +=1 print 'postprocess', result, self.args return result def wrap(f,w,shape='forward'): if shape=='reverse': w.reverse() for ww in w: nw = wrapper() try: nw.args = ww[1] except TypeError: wf = ww[0] nw.function = f f = nw return f # Make a list of ten wrappers with an id number as an additional # wrapper perimeter. w = [] for n in xrange(10): w.append((wrapper,n)) # Wrap 10 functions, 10 times, in reversing order. def func0(x): return x def func1(x): return x def func2(x): return x def func3(x): return x def func4(x): return x def func5(x): return x def func6(x): return x def func7(x): return x def func8(x): return x def func9(x): return x func0 = wrap(func0,w) func1 = wrap(func1,w,'reverse') func2 = wrap(func2,w) func3 = wrap(func3,w,'reverse') func4 = wrap(func4,w) func5 = wrap(func5,w,'reverse') func6 = wrap(func6,w) func7 = wrap(func7,w,'reverse') func8 = wrap(func8,w) func9 = wrap(func9,w,'reverse') print func0(0) print func1(0) print func2(0) print func3(0) print func4(0) print func5(0) print func6(0) print func7(0) print func8(0) print func9(0) #--end-- I find I am still left asking the question why would anyone want to do that?. The difference between a use case and an example is that a use case should demonstrate the solution of
Re: Decorator Base Class: Needs improvement.
Guess I am listening to language funny today. Steve Holden wrote: By the way, we pass *parameters* to functions, *perimeters* surround things. But we do pass parameters *around*, which may be the source of the confusion. :-) -Scott David Daniels [EMAIL PROTECTED] -- http://mail.python.org/mailman/listinfo/python-list
Re: Decorator Base Class: Needs improvement.
I find I am still left asking the question why would anyone want to do that?. You didn't say which part you were referring too. As far as wrapping the same exact wrapper more than once. You probably wouldn't do that. It's just easier to test the use of multiple wrappers that way. As far as reversing the stack of wrappers, that could matter. Because the wrappers are nested, the inputs are done in forward order, and the results are sent back out in reverse order. If you are applying several different graphic filters to an image display function, the order makes a difference, so depending on weather you are modifying the input values, or the returned values, you may need to reverse the wrappers before applying them. The difference between a use case and an example is that a use case should demonstrate the solution of a problem that someone might reasonably be wanting to solve, rather than a way of creating an abstract program structure for which there is no easily observable requirement. It was an example that demonstrates a basic capabilities of an alternative approach, but it is also one solution to certain sub-problems, simpler function wrapping, and adding and removing wrappers at locations other than the function definitions. It's probably not a new approach either. I can understand it if you are merely pursuing this topic because of your fascination with the capabilities of Python, but I don't have the feeling that there are legion Python programmers out there waiting impatiently to be able to build wrapped functions. Yes, I am pursuing the topic because I enjoy experimenting, and because I enjoy programming with Python, and I have an interest in using it in solving real problems. So the answer is all of the above. ;-) Cheers, Ron -- http://mail.python.org/mailman/listinfo/python-list
Re: Decorator Base Class: Needs improvement.
Ron_Adam wrote: Ok, that post may have a few(dozen?) problems in it. I got glitched by idles not clearing variables between runs, so it worked for me because it was getting values from a previous run. This should work better, fixed a few things, too. The decorators can now take more than one argument. The function and arguments lists initialize correctly now. Ron: I've followed your attempts to understand decorators with interest, and have seen you engage in conversation with many luminaries of the Python community, so I hesitate at this point to interject my own remarks. In a spirit of helpfulness, however, I have to ask whether your understanding of decorators is different from mine because you don't understand them or because I don't. You have several times mentioned the possibility of a decorator taking more than one argument, but in my understanding of decorators this just wouldn't make sense. A decorator should (shouldn't it) take precisely one argument (a function or a method) and return precisely one value (a decorated function or method). It doesn't work with functions with more than one variable. It seems tuples don't unpack when given to a function as an argument. Any way to force it? class Decorator(object): [...] Perhaps we need to get back to basics? Do you understand what I mean when I say a decorator should take one function as its argument and it should return a function? regards Steve -- Steve Holden+1 703 861 4237 +1 800 494 3119 Holden Web LLC http://www.holdenweb.com/ Python Web Programming http://pydish.holdenweb.com/ -- http://mail.python.org/mailman/listinfo/python-list
Re: Decorator Base Class: Needs improvement.
Steve Holden wrote: You have several times mentioned the possibility of a decorator taking more than one argument, but in my understanding of decorators this just wouldn't make sense. A decorator should (shouldn't it) take precisely one argument (a function or a method) and return precisely one value (a decorated function or method). Yes. I think this sould be fixed into the minds of the people exacly this way You state it: When writing @decorator(x,y) def f(): not the so called decorator function but decorator(x,y) is the decorating function and decorator(x,y) is nothing but a callable object that takes f as parameter. A little correcture of Your statement: it is NOT nessacary that a function or method will be returned from a decorator. def decorator(x,y): def inner(func): return x+y return inner @decorator(1,2) def f():pass f 3 This is perfectly valid allthough not very usefull ;) Regards, Kay -- http://mail.python.org/mailman/listinfo/python-list
Re: Decorator Base Class: Needs improvement.
On 5 Apr 2005 00:54:25 -0700, Kay Schluehr [EMAIL PROTECTED] wrote: Steve Holden wrote: You have several times mentioned the possibility of a decorator taking more than one argument, but in my understanding of decorators this just wouldn't make sense. A decorator should (shouldn't it) take precisely one argument (a function or a method) and return precisely one value (a decorated function or method). I agree from an English language point of view. I.e., a verber is something that does the verbing, so a decorator ought to be the thing that does the decorating, which is the function/callable(s) resulting on stack from the evaluation of the @-line. In the case of a single @deco name, the evaluation is trivial, and the difference between the @-expression and the resulting callable might be overlooked. Full-fledged general expressions after the '@' are for some reason disallowed, but it is handy to allow attribute access and calling in the syntax, so the relevant Grammar rules are: From the 2.4 Grammar, the key part seems to be decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE decorators: decorator+ funcdef: [decorators] 'def' NAME parameters ':' suite and further on dotted_name: NAME ('.' NAME)* So the Python Grammar's name for the @-expression is just plain decorator which conflicts with my English-based reading of the word ;-/ So it appears the intent is to call the entire @-line the decorator and I guess to have a name for what evaluating the @-line returns on the stack, we could call it the decorating callable since it is what takes the function parameter as its first parameter and decorates the function and returns the decorated function. But I don't like it, English-wise. I would rather call the @-line the decorator expression and what it evaluates to the decorator. Can we change the grammar with s/decorator/decorator_expr/ ? Yes. I think this sould be fixed into the minds of the people exacly this way You state it: I think we may be agreeing in principle but with different words ;-) When writing @decorator(x,y) def f(): not the so called decorator function but decorator(x,y) is the ^--(the result of evaluating) decorating function and decorator(x,y) is nothing but a callable object ^--(the result of evaluating) that takes f as parameter. A little correcture of Your statement: it is NOT nessacary that a function or method will be returned from a decorator. Yes, in fact it could even perversely be colluding with a known succeeding decorator callable to pass info strangely, doing strange things, e.g., trick = ['spam', 'eggs'] def choose_name(tup): ... nx, f = tup ... f.func_name = trick[nx] ... return f ... def namedeco(nx=1): ... return lambda f, nx=nx:(nx, f) ... @choose_name ... @namedeco() ... def foo(): pass ... foo function eggs at 0x02EE8E64 @choose_name ... @namedeco(0) ... def foo(): pass ... foo function spam at 0x02EE8DF4 I.e., namedeco evaluates to the lambda as decorator function, and that passes a perverse (nx, f) tuple on to choose_name, instead of a normal f. def decorator(x,y): def inner(func): return x+y return inner @decorator(1,2) def f():pass f 3 This is perfectly valid allthough not very usefull ;) Perhaps even less useful, the final decorator can return something arbitrary, as only the name in the def matters at that point in the execution (as a binding target name), so: def dumbdeco(f): return 'something dumb' ... @dumbdeco ... def foo(): pass ... foo 'something dumb' Hm, maybe some use ... def keydeco(name): ... return lambda f: (name, f) ... @keydeco('pooh_foo') ... def foo(): pass ... @keydeco('tigger_bar') ... def bar(): pass ... dict([foo, bar]) {'pooh_foo': function foo at 0x02EE8DBC, 'tigger_bar': function bar at 0x02EE8DF4} ... nah ;-) Anyway, I think a different name for what comes after the @ and the callable that that (very limited) expression is supposed to return would clarify things. My conceptual model is @decorator_expression # = decorator def decorating_target(...): ... Regards, Bengt Richter -- http://mail.python.org/mailman/listinfo/python-list
Re: Decorator Base Class: Needs improvement.
Bengt Richter wrote: From the 2.4 Grammar, the key part seems to be decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE decorators: decorator+ funcdef: [decorators] 'def' NAME parameters ':' suite and further on dotted_name: NAME ('.' NAME)* So the Python Grammar's name for the @-expression is just plain decorator which conflicts with my English-based reading of the word ;-/ What about playing with the words decorator/decoration? The allegoric meaning of the decorator def deco(f): pass would be: f is vanishing under decoration - all is vanity. In the example deco would be both a decorator and a decoration. In other examples deco were a decorator and deco(x,y) the decoration. Regards, Kay -- http://mail.python.org/mailman/listinfo/python-list
Re: Decorator Base Class: Needs improvement.
Bengt Richter wrote: From the 2.4 Grammar, the key part seems to be decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE decorators: decorator+ funcdef: [decorators] 'def' NAME parameters ':' suite and further on dotted_name: NAME ('.' NAME)* So the Python Grammar's name for the @-expression is just plain decorator which conflicts with my English-based reading of the word ;-/ What about playing with the words decorator/decoration? The allegoric meaning of the decorator def deco(f): pass would be: f is vanishing under decoration - all is vanity. In the example deco would be both a decorator and a decoration. In other cases deco were a decorator and deco(x,y) the decoration. Regards, Kay -- http://mail.python.org/mailman/listinfo/python-list
Re: Decorator Base Class: Needs improvement.
On Tue, 05 Apr 2005 02:55:35 -0400, Steve Holden [EMAIL PROTECTED] wrote: Ron_Adam wrote: Ok, that post may have a few(dozen?) problems in it. I got glitched by idles not clearing variables between runs, so it worked for me because it was getting values from a previous run. This should work better, fixed a few things, too. The decorators can now take more than one argument. The function and arguments lists initialize correctly now. Ron: I've followed your attempts to understand decorators with interest, and have seen you engage in conversation with many luminaries of the Python community, so I hesitate at this point to interject my own remarks. I don't mind. It might help me communicate my ideas better. In a spirit of helpfulness, however, I have to ask whether your understanding of decorators is different from mine because you don't understand them or because I don't. Or it's just a communication problem, and we both understand. Communicating is not my strongest point. But I am always willing to clarify something I say. You have several times mentioned the possibility of a decorator taking more than one argument, but in my understanding of decorators this just wouldn't make sense. A decorator should (shouldn't it) take precisely one argument (a function or a method) and return precisely one value (a decorated function or method). It doesn't work with functions with more than one variable. It seems tuples don't unpack when given to a function as an argument. Any way to force it? What I was referring to is the case: @decorator(x,y,z) As being a decorator expression with more than one argument. and not: @decorator(x)(y) This would give a syntax error if you tried it. @d1(1)(2) SyntaxError: invalid syntax The problem I had with tuple unpacking had nothing to do with decorators. I was referring to a function within the class, and I needed to be consistent with my use of tuples as arguments to functions and the use of the '*' indicator. Do you understand what I mean when I say a decorator should take one function as its argument and it should return a function? regards Steve Hope this clarifies things a bit. Cheers, Ron -- http://mail.python.org/mailman/listinfo/python-list
Re: Decorator Base Class: Needs improvement.
Ron_Adam wrote: What I was referring to is the case: @decorator(x,y,z) As being a decorator expression with more than one argument. But, we generally say this is a call to a function named decorator that returns a decorator. If you called it: @make_decorator(x,y) def . We'd be sure we were all on the same page. How about this as an example: def tweakdoc(name): def decorator(function): function.__doc__ = 'Tweak(%s) %r' % (name, function.__doc__) return function return decorator What is confusing us about what you write is that you are referring to tweakdoc as a decorator, when it is a function returning a decorator. and not: @decorator(x)(y) This is only prevented by syntax (probably a good idea, otherwise we would see some very complicated expressions before function declarations). --Scott David Daniels [EMAIL PROTECTED] -- http://mail.python.org/mailman/listinfo/python-list
Re: Decorator Base Class: Needs improvement.
On Tue, 05 Apr 2005 14:32:59 -0700, Scott David Daniels [EMAIL PROTECTED] wrote: Ron_Adam wrote: What I was referring to is the case: @decorator(x,y,z) As being a decorator expression with more than one argument. But, we generally say this is a call to a function named decorator that returns a decorator. If you called it: @make_decorator(x,y) def . We'd be sure we were all on the same page. Good point, I agree. :) Or alternatively @call_decorator(x,y) Using either one would be good practice. How about this as an example: def tweakdoc(name): def decorator(function): function.__doc__ = 'Tweak(%s) %r' % (name, function.__doc__) return function return decorator What is confusing us about what you write is that you are referring to tweakdoc as a decorator, when it is a function returning a decorator. Bengt Richter is also pointing out there is an inconsistency in Pythons documents in the use of decorator. I've been trying to start referring to the @___ as the decorator-exression, but that still doesn't quite describe what it does either. Decorarator-caller might be better. Then the decorator-function as the part that defines the decorated-function. Another alternative is to call the entire process what it is, function-wrapping. Then the @ statement would be the wrapper-caller, which calls the wrapper-function, which defines the wrapped-function. That's much more descriptive to me. If we do that then we could agree to use decorator as a general term to describe a function as decorated. Meaning it is wrapped and get away from the decorator/decoratoree discussions. But I think that the terminology has been hashed out quite a bit before, so I don't expect it to change. I'll just have to try to be clearer in how I discuss it. and not: @decorator(x)(y) This is only prevented by syntax (probably a good idea, otherwise we would see some very complicated expressions before function declarations). --Scott David Daniels [EMAIL PROTECTED] And this isn't allowed either, although it represents more closely the nesting that takes place when decorator-expressions are stacked. @make_deco1 @make_deco2 @make_deco3 def function1(n): n+=1 return n This is allowed, but its not pretty. @make_deco1 @make_deco2 @make_deco3 def function1(n): n+=1 return n Cheers, Ron -- http://mail.python.org/mailman/listinfo/python-list
Re: Decorator Base Class: Needs improvement.
Ron_Adam wrote: On Tue, 05 Apr 2005 02:55:35 -0400, Steve Holden [EMAIL PROTECTED] wrote: Ron_Adam wrote: Ok, that post may have a few(dozen?) problems in it. I got glitched by idles not clearing variables between runs, so it worked for me because it was getting values from a previous run. This should work better, fixed a few things, too. The decorators can now take more than one argument. The function and arguments lists initialize correctly now. Ron: I've followed your attempts to understand decorators with interest, and have seen you engage in conversation with many luminaries of the Python community, so I hesitate at this point to interject my own remarks. I don't mind. It might help me communicate my ideas better. In a spirit of helpfulness, however, I have to ask whether your understanding of decorators is different from mine because you don't understand them or because I don't. Or it's just a communication problem, and we both understand. Communicating is not my strongest point. But I am always willing to clarify something I say. You have several times mentioned the possibility of a decorator taking more than one argument, but in my understanding of decorators this just wouldn't make sense. A decorator should (shouldn't it) take precisely one argument (a function or a method) and return precisely one value (a decorated function or method). It doesn't work with functions with more than one variable. It seems tuples don't unpack when given to a function as an argument. Any way to force it? What I was referring to is the case: @decorator(x,y,z) As being a decorator expression with more than one argument. and not: @decorator(x)(y) This would give a syntax error if you tried it. @d1(1)(2) SyntaxError: invalid syntax The problem I had with tuple unpacking had nothing to do with decorators. I was referring to a function within the class, and I needed to be consistent with my use of tuples as arguments to functions and the use of the '*' indicator. Do you understand what I mean when I say a decorator should take one function as its argument and it should return a function? regards Steve Hope this clarifies things a bit. Cheers, Ron So what you are saying is that you would like to be able to use arbitrarily complex expressions after the :at sign, as long as they return a decorator? If so, you've been pronounced :-) regards Steve -- Steve Holden+1 703 861 4237 +1 800 494 3119 Holden Web LLC http://www.holdenweb.com/ Python Web Programming http://pydish.holdenweb.com/ -- http://mail.python.org/mailman/listinfo/python-list
Re: Decorator Base Class: Needs improvement.
On Wed, 06 Apr 2005 16:33:24 +1200, Greg Ewing [EMAIL PROTECTED] wrote: Ron_Adam wrote: I would have preferred the @ symbol to be used as an inline assert introducer. Which would have allowed us to put debug code anywhere we need. Such as @print total @. Don't lose heart, there are still two unused characters left, $ and ?. ? might even be more mnemonic for this purpose, as ?print foo =, foo has a nice hint of WT?%$%$ is going on at this point? to it. LOL, yes, it does. :-) -- http://mail.python.org/mailman/listinfo/python-list
Decorator Base Class: Needs improvement.
Hi, Thanks again for all the helping me understand the details of decorators. I put together a class to create decorators that could make them a lot easier to use. It still has a few glitches in it that needs to be addressed. (1) The test for the 'function' object needs to not test for a string but an object type instead. (2) If the same decorator instance is stacked, it will get locked in a loop. But stacking different instances created from the same decorator object works fine. (3) It has trouble if a decorator has more than one argument. But I think all of these things can be fixed. Would this be something that could go in the builtins library? (After any issues are fixed first of course.) When these are stacked, they process all the prepossess's first, call the decorator, then process all the postprocess's. It just worked out that way, which was a nice surprise and makes this work a bit different than the standard decorators. Cheers, Ron #---start--- class Decorator(object): Decorator - A class to make decorators with. self.function - name of function decorated. self.arglist - arguments of decorator self.preprocess - over ride to preprocess function arguments. self.postprocess - over ride to postprocess function return value. Example use: class mydecorator(Decorate): def self.preprocess(self, args): # process args return args def self.postprocess(self, results): # process results return results deco = mydecorator() @deco def function(args): # function body return args function = None arglist = [] def __call__(self, arg): self.arglist.append(arg) def _wrapper( args): pre_args = self.preprocess(args) result = self.function(pre_args) return self.postprocess(result) if 'function' in str(arg): self.arglist = self.arglist[:-1] self.function = arg return _wrapper return self def preprocess(self, args): return args def postprocess(self, result): return result class mydecorator(Decorater): def preprocess(self, args): args = 2*args return args def postprocess(self, args): args = args.upper() args = args + str(self.arglist[0]) return args deco = mydecorator() @deco('xyz') def foo(text): return text print foo('abc') #---end--- -- http://mail.python.org/mailman/listinfo/python-list
Re: Decorator Base Class: Needs improvement.
Ok, that post may have a few(dozen?) problems in it. I got glitched by idles not clearing variables between runs, so it worked for me because it was getting values from a previous run. This should work better, fixed a few things, too. The decorators can now take more than one argument. The function and arguments lists initialize correctly now. It doesn't work with functions with more than one variable. It seems tuples don't unpack when given to a function as an argument. Any way to force it? class Decorator(object): Decorator - A base class to make decorators with. self.function - name of function decorated. self.arglist - arguments of decorator self.preprocess - over ride to preprocess function arguments. self.postprocess - over ride to postprocess function return value. Example use: class mydecorator(Decorate): def self.preprocess(self, args): # process args return args def self.postprocess(self, results): # process results return results deco = mydecorator() @deco def function(args): # function body return args def __init__(self): self.function = None self.arglist = [] def __call__(self, *arg): if len(arg) == 1: arg = arg[0] self.arglist.append(arg) def _wrapper( *args): if len(args) == 1: args = args[0] pre_args = self.preprocess(args) result = self.function(pre_args) return self.postprocess(result) if 'function' in str(arg): self.arglist = self.arglist[:-1] self.function = arg return _wrapper return self def preprocess(self, args): return args def postprocess(self, result): return result #---3--- class mydecorator(Decorator): def preprocess(self, args): args = 2*args return args def postprocess(self, args): args = args.upper() args = args + str(self.arglist[0]) return args deco = mydecorator() @deco('xyz') def foo(text): return text print foo('abc') #---2--- class decorator2(Decorator): def preprocess(self, args): return args+sum(self.arglist[0]) def postprocess(self, args): return args deco2 = decorator2() @deco2(1,2) def foo(a): return a print foo(1) # This one doesn't work yet. #---3--- class decorator3(Decorator): pass deco3 = decorator3() @deco3 def foo(a,b): return a,b print foo(1,3) -- http://mail.python.org/mailman/listinfo/python-list