RE: Decorator help
Well, technically it's func.func_closure[0].cell_contents.__name__ but of course you cannot know that for the general case. Hah, I admit I lacked perseverance in looking at this in PyCharms debugger as I missed that. Much appreciated! jlc -- http://mail.python.org/mailman/listinfo/python-list
Re: Decorator help
On 4 July 2013 06:39, Peter Otten __pete...@web.de wrote: Joshua Landau wrote: On 3 July 2013 23:19, Joshua Landau joshua.landau...@gmail.com wrote: If you don't want to do that, you'd need to use introspection of a remarkably hacky sort. If you want that, well, it'll take a mo. After some effort I'm pretty confident that the hacky way is impossible. Well, technically it's func.func_closure[0].cell_contents.__name__ but of course you cannot know that for the general case. I didn't want to do something like that as it implies a lot of knowledge about the function -- which implies that there's no reason to do it hacky in the first place. I was using inspect.getclosurevars(func).nonlocals and that coerces to a dictionary first. It's the correct way of doing things. But you never know what name the function inside the wrapper is bound to, so I didn't accept that. Also, your method has undefined behaviour AFAIK -- the order of func_closure is compiler-dependant. If you want to do something like this, I recommend my method (but it doesn't work for the general case in the slightest): inspect.getclosurevars(func).nonlocals[func].__name__ If you can't assume the name it's stored in, but you can know the order of closure variables *then* use Peter's. But again, don't use either; it's impossible just as I said. -- http://mail.python.org/mailman/listinfo/python-list
Decorator help
I have a set of methods which take args that I decorate twice, def wrapped(func): def wrap(*args, **kwargs): try: val = func(*args, **kwargs) # some work except BaseException as error: log.exception(error) return [] return wrap def wrapped_again(length): def something(func): def wrapped_func(*args, **kwargs): values = func(*args, **kwargs) # do some work return values return wrapped_func return something So the methods wrapped are as follows: @wrapped_again(12) @wrapped def class_method(self, **kwargs): # Is it possible to get the name of the original method (class_method) from within wrapped_func inside wrapped_again? Thanks! jlc -- http://mail.python.org/mailman/listinfo/python-list
Re: Decorator help
On 3 July 2013 23:09, Joseph L. Casale jcas...@activenetwerx.com wrote: I have a set of methods which take args that I decorate twice, def wrapped(func): def wrap(*args, **kwargs): try: val = func(*args, **kwargs) # some work except BaseException as error: log.exception(error) return [] return wrap def wrapped_again(length): def something(func): def wrapped_func(*args, **kwargs): values = func(*args, **kwargs) # do some work return values return wrapped_func return something So the methods wrapped are as follows: @wrapped_again(12) @wrapped def class_method(self, **kwargs): # Is it possible to get the name of the original method (class_method) from within wrapped_func inside wrapped_again? Thanks! Normally you'd want to use functools.wraps; def wrapped(func): @functools.wraps def wrap(*args, **kwargs): ... return wrap def wrapped_again(length): @functools.wraps def something(func): ... return something @wrapped_again(12) @wrapped def class_method(self, **kwargs): And then the name is carried, as with docstrings. If you don't want to do that, you'd need to use introspection of a remarkably hacky sort. If you want that, well, it'll take a mo. -- http://mail.python.org/mailman/listinfo/python-list
Re: Decorator help
On 3 July 2013 23:19, Joshua Landau joshua.landau...@gmail.com wrote: If you don't want to do that, you'd need to use introspection of a remarkably hacky sort. If you want that, well, it'll take a mo. After some effort I'm pretty confident that the hacky way is impossible. -- http://mail.python.org/mailman/listinfo/python-list
RE: Decorator help
If you don't want to do that, you'd need to use introspection of a remarkably hacky sort. If you want that, well, it'll take a mo. After some effort I'm pretty confident that the hacky way is impossible. Hah, I fired it in PyCharm's debugger and spent a wack time myself, thanks for the confirmation, I'll give functools a shot. Thanks a lot, jlc -- http://mail.python.org/mailman/listinfo/python-list
Re: Decorator help
Joshua Landau wrote: On 3 July 2013 23:19, Joshua Landau joshua.landau...@gmail.com wrote: If you don't want to do that, you'd need to use introspection of a remarkably hacky sort. If you want that, well, it'll take a mo. After some effort I'm pretty confident that the hacky way is impossible. Well, technically it's func.func_closure[0].cell_contents.__name__ but of course you cannot know that for the general case. -- http://mail.python.org/mailman/listinfo/python-list
RE: Decorator help
When you say class vars, do you mean variables which hold classes? You guessed correctly, and thanks for pointing out the ambiguity in my references. The one doesn't follow from the other. Writing decorators as classes is fairly unusual. Normally, they will be regular functions. I see, this I didn't know. I'll stick to this guideline now. A more complicated case is where you need to do some pre-processing, and you *don't* want that calculation repeated every time the method is called. Decorators are fantastic for that case too, but here you cannot access instance attributes, since the instance doesn't exist yet. But you can access *class attributes*, as more-or-less ordinary local variables *inside* the class definition. Here's a working sketch of the sort of thing you can do. Copy and paste the following into a Python interactive session, and then see if you can follow what is being done when. Is your mind boggled yet? :-) Steven, That was some of the coolest stuff I have seen a while. I had to wait until I had enough time to actually run this through and utilize it my own work. I haven't enjoyed Python this much since I first started using it. Can't thank you enough for the time and thorough example, that imparted loads of insight. jlc -- http://mail.python.org/mailman/listinfo/python-list
Re: Decorator help
Jason Swails於 2013年3月28日星期四UTC+8上午4時33分08秒寫道: On Wed, Mar 27, 2013 at 3:49 PM, Joseph L. Casale jca...@activenetwerx.com wrote: I have a class which sets up some class vars, then several methods that are passed in data and do work referencing the class vars. I want to decorate these methods, the decorator needs access to the class vars, so I thought about making the decorator its own class and allowing it to accept args. I was hoping to do all the work on in_data from within the decorator, which requires access to several MyClass vars. Not clear on the syntax/usage with this approach here, any guidance would be greatly appreciated! My guess is that you don't quite 'get' decorators yet (since I remember similar types of questions when trying to learn them myself). Decorators execute when the class type itself is being built (e.g., when a module is first imported at runtime). So decorators will never take instance variables as arguments (nor should they, since no instance can possibly exist when they execute). Bear in mind, a decorator should take a callable as an argument (and any number of 'static' parameters you want to assign it), and return another callable. I provide an example decorator using the format the I typically adopt below (where the decorator is a simple function, not a class): def my_decorator(fcn): I might add default parameters here if I am programming in python to save the troubles of subclassing similar decorators. But that is only the stylish problem in python. I might need to translate the decorator part into cython or c/c++ in the future. Decorator for a function def new_fcn(self, *args, **kwargs): This is the new function that we will return. # You can access any instance variables here returnval = fcn(self, *args, **kwargs) # Do anything else here with instance variables return returnval # or any other return value you want return new_fcn Notice here I define a new_fcn callable function that takes self and an arbitrary argument/keyword-argument list, and I return this function (which does not get called) to replace the function I passed in. You can use instance variables inside new_fcn since new_fcn is called by instances of MyClass. This is a very simple type of decorator, but hopefully helps illustrate what decorators are. There is a particularly good thread on SO with information about decorators here: http://stackoverflow.com/questions/739654/understanding-python-decorators Hope this helps, Jason -- http://mail.python.org/mailman/listinfo/python-list
Decorator help
I have a class which sets up some class vars, then several methods that are passed in data and do work referencing the class vars. I want to decorate these methods, the decorator needs access to the class vars, so I thought about making the decorator its own class and allowing it to accept args. I was hoping to do all the work on in_data from within the decorator, which requires access to several MyClass vars. Not clear on the syntax/usage with this approach here, any guidance would be greatly appreciated! Class MyDecorator(object): def __init__(self, arg1, arg2): self.arg1 = arg1 self.arg2 = arg2 ... Class MyClass(object): def __init__(self): self.var_a = @MyDecorator(...) def meth_one(self, in_data): ... Thanks! jlc -- http://mail.python.org/mailman/listinfo/python-list
Re: Decorator help
On 27 March 2013 19:49, Joseph L. Casale jcas...@activenetwerx.com wrote: I have a class which sets up some class vars, then several methods that are passed in data and do work referencing the class vars. I want to decorate these methods, the decorator needs access to the class vars, so I thought about making the decorator its own class and allowing it to accept args. I was hoping to do all the work on in_data from within the decorator, which requires access to several MyClass vars. Not clear on the syntax/usage with this approach here, any guidance would be greatly appreciated! Class MyDecorator(object): def __init__(self, arg1, arg2): self.arg1 = arg1 self.arg2 = arg2 ... Class MyClass(object): def __init__(self): self.var_a = @MyDecorator(...) def meth_one(self, in_data): ... I don't really understand what you are trying to do. It would be easier if you had some code that tried to do something (even if it doesn't quite work). -- Arnaud -- http://mail.python.org/mailman/listinfo/python-list
Re: Decorator help
On Wed, Mar 27, 2013 at 3:49 PM, Joseph L. Casale jcas...@activenetwerx.com wrote: I have a class which sets up some class vars, then several methods that are passed in data and do work referencing the class vars. I want to decorate these methods, the decorator needs access to the class vars, so I thought about making the decorator its own class and allowing it to accept args. I was hoping to do all the work on in_data from within the decorator, which requires access to several MyClass vars. Not clear on the syntax/usage with this approach here, any guidance would be greatly appreciated! My guess is that you don't quite 'get' decorators yet (since I remember similar types of questions when trying to learn them myself). Decorators execute when the class type itself is being built (e.g., when a module is first imported at runtime). So decorators will never take instance variables as arguments (nor should they, since no instance can possibly exist when they execute). Bear in mind, a decorator should take a callable as an argument (and any number of 'static' parameters you want to assign it), and return another callable. I provide an example decorator using the format the I typically adopt below (where the decorator is a simple function, not a class): def my_decorator(fcn): Decorator for a function def new_fcn(self, *args, **kwargs): This is the new function that we will return. # You can access any instance variables here returnval = fcn(self, *args, **kwargs) # Do anything else here with instance variables return returnval # or any other return value you want return new_fcn Notice here I define a new_fcn callable function that takes self and an arbitrary argument/keyword-argument list, and I return this function (which does not get called) to replace the function I passed in. You can use instance variables inside new_fcn since new_fcn is called by instances of MyClass. This is a very simple type of decorator, but hopefully helps illustrate what decorators are. There is a particularly good thread on SO with information about decorators here: http://stackoverflow.com/questions/739654/understanding-python-decorators Hope this helps, Jason -- http://mail.python.org/mailman/listinfo/python-list
RE: Decorator help
So decorators will never take instance variables as arguments (nor should they, since no instance can possibly exist when they execute). Right, I never thought of it that way, my only use of them has been trivial, in non class scenarios so far. Bear in mind, a decorator should take a callable as an argument (and any number of 'static' parameters you want to assign it), and return another callable. Got it, and thanks for the detail as well! jlc -- http://mail.python.org/mailman/listinfo/python-list
Re: Decorator help
On Wed, 27 Mar 2013 19:49:54 +, Joseph L. Casale wrote: I have a class which sets up some class vars, then several methods that are passed in data and do work referencing the class vars. When you say class vars, do you mean variables which hold classes? Like string vars are variables which hold strings, and int vars are variables that hold ints? Classes (also known as types) are first-class objects in Python (no pun intended), unlike Java, and so you can store them in lists, returns them from functions, and bind them in variables. for aclass in list_of_classes: do_something_with(aclass) Consequently, when people talk about class variables, it is ambiguous, which is why we prefer to use class attribute to refer to attributes on the class. For example: class Parrot(object): breed = Norwegian Blue # this is a class attribute def __init__(self, name=Polly): self.name = name # this is an instance attribute def speak(self): s = %s the %s says, 'Hello sailor!' print(s % (self.name, self.breed)) Class attributes are attached to the class object itself, and are shared between all instances. Instance attributes are attached to the instance, where they over-ride any class attribute of the same name, and are not shared. In the following I am going to assume that you actually are talking about attributes, rather than an actual variable holding a class. I want to decorate these methods, the decorator needs access to the class vars, so I thought about making the decorator its own class and allowing it to accept args. The one doesn't follow from the other. Writing decorators as classes is fairly unusual. Normally, they will be regular functions. If your decorator needs to store so much state that it needs to be a class, you're probably trying to do too much from a single decorator. There's more that you need to describe, such as what it is that the decorator actually does, and whether it does it once, when the decorator is called, or repeatedly, when the decorated method is called. The second case is the easiest. Suppose you have a class like this, with many methods which have code in common. Here's a toy example: def MyClass(object): x = class attribute def __init__(self, y): self.y = y def spam(self): do_stuff(self.x) do_stuff(self.y) print(spam spam spam spam) def ham(self): do_stuff(self.x) do_stuff(self.y) return ham, a growing boy's best friend def eggs(self, food=bacon): do_stuff(self.x) do_stuff(self.y) return green eggs and %s % food A simple decorator function can simplify the common code: import functools def decorate(func): @functools.wraps(func) def inner(self, *args, **kwargs): # call the common, repeated, code do_stuff(self.x) do_stuff(self.y) # call the function being wrapped return func(self, *args, **kwargs) return inner def MyClass(object): x = class attribute def __init__(self, y): self.y = y @decorate def spam(self): print(spam spam spam spam) @decorate def ham(self): return ham, a growing boy's best friend @decorate def eggs(self, food=bacon): return green eggs and %s % food Notice that because the decorator doesn't do any work until the decorated function is called, there is no difficulty in accessing attributes regardless of whether they are attached to the class or the instance. They won't be looked up until self is known. A more complicated case is where you need to do some pre-processing, and you *don't* want that calculation repeated every time the method is called. Decorators are fantastic for that case too, but here you cannot access instance attributes, since the instance doesn't exist yet. But you can access *class attributes*, as more-or-less ordinary local variables *inside* the class definition. Here's a working sketch of the sort of thing you can do. Copy and paste the following into a Python interactive session, and then see if you can follow what is being done when. # === cut === import functools def decorator_factory(a, b): # This is a factory function that returns a decorator. # First we do so pre-processing. This gets called only once (per # usage of the decorator). value = a*10 + b - 1 print(precalculation of value = %s % value) def decorator(func): print(decorator called on method '%s' % func.__name__) @functools.wraps(func) def inner(self, fe, fi, fo): return func(self, fe, fi, fo, fum=value) return inner # return the decorator return decorator class MyClass(object): spam = 42 ham = 23 @decorator_factory(spam, ham) def my_method(self, fe, fi, fo, fum): print(fe, fi, fo, fum) x = MyClass() x.my_method(1, 2, 3) # === end cut == Is
Re: Decorator help
On Wed, Mar 27, 2013 at 7:29 PM, Steven D'Aprano steve+comp.lang.pyt...@pearwood.info wrote: The one doesn't follow from the other. Writing decorators as classes is fairly unusual. Normally, they will be regular functions. If your decorator needs to store so much state that it needs to be a class, you're probably trying to do too much from a single decorator. There's more that you need to describe, such as what it is that the decorator actually does, and whether it does it once, when the decorator is called, or repeatedly, when the decorated method is called. The second case is the easiest. Suppose you have a class like this, with many methods which have code in common. Here's a toy example: def MyClass(object): x = class attribute def __init__(self, y): self.y = y In the spirit of nit-picking, I'll point out that Steven meant to use the 'class' keyword instead of 'def' for MyClass. def MyClass(object): x = class attribute def __init__(self, y): self.y = y And here as well. It's potentially worth pointing out that this code will actually compile. It will even run, assuming you provide MyClass with a single argument. But it will always return None :). As per usual, the response was thorough and helpful -- I appreciate responses like these and how they've helped improve my command of Python. All the best, Jason -- http://mail.python.org/mailman/listinfo/python-list
Re: Decorator help
On Wed, 27 Mar 2013 22:38:11 -0400, Jason Swails wrote: The second case is the easiest. Suppose you have a class like this, with many methods which have code in common. Here's a toy example: def MyClass(object): x = class attribute def __init__(self, y): self.y = y In the spirit of nit-picking, I'll point out that Steven meant to use the 'class' keyword instead of 'def' for MyClass. /face-palm So I did. Thanks for picking the nit. -- Steven -- http://mail.python.org/mailman/listinfo/python-list