Re: Using 'apply' as a decorator, to define constants
Jonathan Gardner wrote: On Aug 21, 9:09 am, alex23 wuwe...@gmail.com wrote: On Aug 21, 11:36 pm, Jonathan Fine jf...@pytex.org wrote: class ColourThing(object): @apply def rgb(): def fset(self, rgb): self.r, self.g, self.b = rgb def fget(self): return (self.r, self.g, self.b) return property(**locals()) This is brilliant. I am going to use this more often. I've all but given up on property() since defining get_foo, get_bar, etc... has been a pain and polluted the namespace. I think we can do better, with a little work. And also solve the problem that 'apply' is no longer a builtin in Python3. Here's my suggestion: === import wibble # Informs reader we're doing something special here. class ColourThing(object): @wibble.property def rgb(): '''This is the docstring for the property.''' def fset(self, rgb): self.r, self.g, self.b = rgb def fget(self): return (self.r, self.g, self.b) return locals() === And here's wibble.property() === _property = property # Avoid collision. def property(fn): return _property(doc=fn.__doc__, **fn()) === We can add apply() to the wibble module. By the way, 'wibble' is a placeholder to the real name. Any suggestions? -- Jonathan -- http://mail.python.org/mailman/listinfo/python-list
Re: Using 'apply' as a decorator, to define constants
Why I've personally stopped using it: I've always had the impression that decorators were intended to provide a convenient and obvious way of augmenting functions. Having one that automatically executes the function at definition just runs counter to the behaviour I expect from a decorator. Especially when direct assignment... foo = foo () ...is a far more direct and clear way of expressing exactly what is happening. if you have to define it yourself, you could call it store_result or something else instead of apply. @store_result def tags(): return result Leonhard -- http://mail.python.org/mailman/listinfo/python-list
Re: Using 'apply' as a decorator, to define constants
On Sat, 22 Aug 2009 08:09:52 +0100, Jonathan Fine wrote: Jonathan Gardner wrote: On Aug 21, 9:09 am, alex23 wuwe...@gmail.com wrote: On Aug 21, 11:36 pm, Jonathan Fine jf...@pytex.org wrote: class ColourThing(object): @apply def rgb(): def fset(self, rgb): self.r, self.g, self.b = rgb def fget(self): return (self.r, self.g, self.b) return property(**locals()) This is brilliant. I am going to use this more often. I've all but given up on property() since defining get_foo, get_bar, etc... has been a pain and polluted the namespace. I think we can do better, with a little work. And also solve the problem that 'apply' is no longer a builtin in Python3. There's a standard idiom for that, using the property() built-in, for Python 2.6 or better. Here's an example including a getter, setter, deleter and doc string, with no namespace pollution, imports, or helper functions or deprecated built-ins: class ColourThing(object): @property def rgb(self): Get and set the (red, green, blue) colours. return (self.r, self.g, self.b) @rgb.setter def rgb(self, rgb): self.r, self.g, self.b = rgb @rgb.deleter def rgb(self): del self.r, self.g, self.b -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: Using 'apply' as a decorator, to define constants
On Sat, 22 Aug 2009 10:51:27 +0100, Jonathan Fine wrote: Steven D'Aprano wrote: There's a standard idiom for that, using the property() built-in, for Python 2.6 or better. Here's an example including a getter, setter, deleter and doc string, with no namespace pollution, imports, or helper functions or deprecated built-ins: class ColourThing(object): @property def rgb(self): Get and set the (red, green, blue) colours. return (self.r, self.g, self.b) @rgb.setter def rgb(self, rgb): self.r, self.g, self.b = rgb @rgb.deleter def rgb(self): del self.r, self.g, self.b Sorry, Steve, but I don't understand this. In fact, I don't even see how it can be made to work. Nevertheless, it does work, and it's not even magic. It's described (very briefly) in the docstring for property: help(property) will show it to you. More detail is here: http://docs.python.org/library/functions.html#property As for how it can work, it's not that difficult. All you need is for the setter and deleter methods to add an appropriate fset and fdel method to the property, then return it. Here's a toy example which may demonstrate the process (although unlike property, fget, fset and fdel don't have any special meanings): class ToyProperty(object): def __init__(self, fget, fset=None, fdel=None, fdoc=None): if fdoc is None: fdoc = fget.__doc__ self.fget = fget self.fset = fset self.fdel = fdel def getter(self, fget): self.fget = fget return self def setter(self, fset): self.fset = fset return self def deleter(self, fdel): self.fdel = fdel return self Unless an exception is raised, @wibble def wobble(): pass will make an assignment to wobble, namely the return value of wibble. So in your example above, there will be /three/ assignments to rgb. Yes. A tiny inefficiency, which only occurs when the class is created. If you care about that, then (1) use the full form of property() where you supply the fget, fset and fdel arguments all at once, and (2) you really need to get out into the fresh air more *wink* Unless you do some complicated introspection (and perhaps not even then) surely they will clobber each other. So what? The process is no weirder than: x = ['fget'] x = x + ['fset'] x = x + ['fdel'] -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: Using 'apply' as a decorator, to define constants
Steven D'Aprano wrote: On Sat, 22 Aug 2009 10:51:27 +0100, Jonathan Fine wrote: Steven D'Aprano wrote: There's a standard idiom for that, using the property() built-in, for Python 2.6 or better. Here's an example including a getter, setter, deleter and doc string, with no namespace pollution, imports, or helper functions or deprecated built-ins: class ColourThing(object): @property def rgb(self): Get and set the (red, green, blue) colours. return (self.r, self.g, self.b) @rgb.setter def rgb(self, rgb): self.r, self.g, self.b = rgb @rgb.deleter def rgb(self): del self.r, self.g, self.b Sorry, Steve, but I don't understand this. In fact, I don't even see how it can be made to work. Nevertheless, it does work, and it's not even magic. It's described (very briefly) in the docstring for property: help(property) will show it to you. More detail is here: http://docs.python.org/library/functions.html#property My apologies. I wasn't up to date with my Python versions: | Changed in version 2.6: The getter, setter, and deleter | attributes were added. I was still thinking Python2.5 (or perhaps earlier?). I still don't like it. All those repetitions of 'rgb'. -- Jonathan -- http://mail.python.org/mailman/listinfo/python-list
Re: Using 'apply' as a decorator, to define constants
21-08-2009 o 18:09:02 alex23 wuwe...@gmail.com wrote: Unfortunately, apply() has been removed as a built-in in 3.x. You can always implement it yourself :) def apply(function, args=(), keywords={}): return function(*args, **keywords) -- Jan Kaliszewski (zuo) z...@chopin.edu.pl -- http://mail.python.org/mailman/listinfo/python-list
Re: Using 'apply' as a decorator, to define constants
On Aug 21, 11:36 pm, Jonathan Fine jf...@pytex.org wrote: It might seem odd to use 'apply' as a decorator, but it can make sense. Yes, it's an idiom I've used myself for property declarations, but one I find myself using less often: class ColourThing(object): @apply def rgb(): def fset(self, rgb): self.r, self.g, self.b = rgb def fget(self): return (self.r, self.g, self.b) return property(**locals()) Unfortunately, apply() has been removed as a built-in in 3.x. I'm not sure if it has been relocated to a module somewhere, there's no mention of such in the docs. Without using 'apply' as a decorator one alternative is def tmp(): value = [] # complicated code return value tags = tmp() del tmp You can save yourself the tidy up by using the same name for the function the label: def tags(): value = [] # ... return value tags = tags() Like all uses of decorators, it is simply syntactic sugar. It allows you to see, up front, what is going to happen. I think, once I get used to it, I'll get to like it. The question is, is it really that useful, or is it just a slight aesthetic variation? Given that apply(f, args, kwargs) is identical to f(*args, **kwargs), it's understandable that's apply() isn't seen as worth keeping in the language. Why I've personally stopped using it: I've always had the impression that decorators were intended to provide a convenient and obvious way of augmenting functions. Having one that automatically executes the function at definition just runs counter to the behaviour I expect from a decorator. Especially when direct assignment... foo = foo () ...is a far more direct and clear way of expressing exactly what is happening. But that's all IMO, if you feel it makes your code cleaner and don't plan on moving to 3.x any time soon (come on in! the water's great!), go for it :) -- http://mail.python.org/mailman/listinfo/python-list
Re: Using 'apply' as a decorator, to define constants
alex23 wrote: Unfortunately, apply() has been removed as a built-in in 3.x. I'm not sure if it has been relocated to a module somewhere, there's no mention of such in the docs. The old use of apply() You can save yourself the tidy up by using the same name for the function the label: def tags(): value = [] # ... return value tags = tags() I don't like that because there's no hint at def tags(): that this is /not/ the value of tags. Like all uses of decorators, it is simply syntactic sugar. It allows you to see, up front, what is going to happen. I think, once I get used to it, I'll get to like it. The question is, is it really that useful, or is it just a slight aesthetic variation? Given that apply(f, args, kwargs) is identical to f(*args, **kwargs), it's understandable that's apply() isn't seen as worth keeping in the language. Yes, I agree with that, completely. Why I've personally stopped using it: I've always had the impression that decorators were intended to provide a convenient and obvious way of augmenting functions. Yes, that was the intended use case. Having one that automatically executes the function at definition just runs counter to the behaviour I expect from a decorator. I'd expect the name of the decorator to explain what is going on. If apply() were a well known part of the language, that would be fine. Especially when direct assignment... foo = foo () ...is a far more direct and clear way of expressing exactly what is happening. Actually, I think the decorator approach is clearer. But that's just my opinion, and not with the benefit of a lot of experience. But that's all IMO, if you feel it makes your code cleaner and don't plan on moving to 3.x any time soon (come on in! the water's great!), go for it :) Thank you for your comments, Alex. And particularly for telling me that apply() is no longer a builtin for Python 3. -- Jonathan -- http://mail.python.org/mailman/listinfo/python-list
Re: Using 'apply' as a decorator, to define constants
On Aug 21, 6:36 am, Jonathan Fine jf...@pytex.org wrote: �...@apply def tags(): value = [] # complicated code return value Is this different from: tags = [] # complicated code I can see the argument that you are cleaning up a lot of intermediary variables upon return, though. -- http://mail.python.org/mailman/listinfo/python-list
Re: Using 'apply' as a decorator, to define constants
On Aug 21, 9:09 am, alex23 wuwe...@gmail.com wrote: On Aug 21, 11:36 pm, Jonathan Fine jf...@pytex.org wrote: class ColourThing(object): @apply def rgb(): def fset(self, rgb): self.r, self.g, self.b = rgb def fget(self): return (self.r, self.g, self.b) return property(**locals()) This is brilliant. I am going to use this more often. I've all but given up on property() since defining get_foo, get_bar, etc... has been a pain and polluted the namespace. Unfortunately, apply() has been removed as a built-in in 3.x. I'm not sure if it has been relocated to a module somewhere, there's no mention of such in the docs. apply = lambda f: f() It's one of those functions that is easier to define than import. Why I've personally stopped using it: I've always had the impression that decorators were intended to provide a convenient and obvious way of augmenting functions. Having one that automatically executes the function at definition just runs counter to the behaviour I expect from a decorator. Especially when direct assignment... foo = foo () ...is a far more direct and clear way of expressing exactly what is happening. If anyone reads the decorator and doesn't think this thing below is defined as the result of this decorator function then they don't understand decorators at all. -- http://mail.python.org/mailman/listinfo/python-list
Re: Using 'apply' as a decorator, to define constants
Jonathan Gardner jgard...@jonathangardner.net wrote: This is brilliant. I am going to use this more often. I've all but given up on property() since defining get_foo, get_bar, etc... has been a pain and polluted the namespace. Unfortunately I can't remember who I first learned it from - it was definitely in a post to this group - otherwise all credit would be their's. It's one of those functions that is easier to define than import. And so obvious now :) If anyone reads the decorator and doesn't think this thing below is defined as the result of this decorator function then they don't understand decorators at all. Well, it's not so much a question of the reader's intelligence as that Python already has a readily identifiable assignment operator. Having a second mechanism for assignment with no real similarity to the first just adds cognitive friction to reading the code...not because the reader doesn't understand what is happening, but because it's not obvious _why_ this second form would have been chosen. Nothing that couldn't be mitigated with a comment, I guess. # @apply used to prevent having to repeat references That would work for me. -- http://mail.python.org/mailman/listinfo/python-list
Re: Using 'apply' as a decorator, to define constants
On Fri, 21 Aug 2009 15:17:40 -0700, Jonathan Gardner wrote: Unfortunately, apply() has been removed as a built-in in 3.x. I'm not sure if it has been relocated to a module somewhere, there's no mention of such in the docs. apply = lambda f: f() It's one of those functions that is easier to define than import. apply = lambda f: f() __builtin__.apply(len, 'a') 1 apply(len, 'a') Traceback (most recent call last): File stdin, line 1, in module TypeError: lambda() takes exactly 1 argument (2 given) It's a little bit more difficult to define it *correctly*. Here's a working version of apply: def apply(object, *args, **kwargs): apply(object[, args[, kwargs]]) - value Call a callable object with positional and keyword arguments. apply(max, 'one', 'two', 'three', 'four', key=len) 'three' return object(*args, **kwargs) Note that this: * actually does what apply() is supposed to do; * defines the function name, useful for tracebacks; * has a docstring, useful for interactive use and documentation; * includes an example suitable for automated testing with doctest. -- Steven -- http://mail.python.org/mailman/listinfo/python-list