Decorator with parameters - python

Can you explain me how the following decorator works:
def set_ev_cls(ev_cls, dispatchers=None):
def _set_ev_cls_dec(handler):
if 'callers' not in dir(handler):
handler.callers = {}
for e in _listify(ev_cls):
handler.callers[e] = _Caller(_listify(dispatchers), e.__module__)
return handler
return _set_ev_cls_dec
#set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
def _switch_features_handler(self, ev):
datapath = ev.msg.datapath
....
Please, don't go into details on what's going on inside the function. I'm interested in how the decorator with parameters wrap methods here. By the way, it's a code snippet from Ryu (event registration mechanism).
Thank you in advance

First, a decorator is just a function that gets called with a function. In particular, the following are (almost) the same thing:
#spam
def eggs(arg): pass
def eggs(arg): pass
eggs = spam(eggs)
So, what happens when the decorator takes parameters? Same thing:
#spam(arg2)
def eggs(arg): pass
def eggs(arg): pass
eggs = spam(arg2)(eggs)
Now, notice that the function _set_ev_cls_dec, which is ultimately returned and used in place of _switch_features_handler, is a local function, defined inside the decorator. That means it can be a closure over variables from the outer function—including the parameters of the outer function. So, it can use the handler argument at call time, plus the ev_cls and dispatchers arguments that it got at decoration time.
So:
set_ev_cls_dev creates a local function and returns a closure around its ev_cls and dispatchers arguments, and returns that function.
That closure gets called with _switch_features_handler as its parameter, and it modifies and returns that parameter by adding a callers attribute, which is a dict of _Caller objects built from that closed-over dispatchers parameter and keyed off that closed-over ev_cls parameter.

Explain how it works without detailing what's going on inside? That kind of sounds like "explain without explaining," but here's a rough walkthrough:
Think of set_ev_cls as a factory for decorators. It's there to catch the arguments at the time the decorator is invoked:
#set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
And return a function, _set_ev_cls_dec that has its variables bound to:
ev_cls = ofp_event.EventOFPSwitchFeatures
dispatchers = CONFIG_DISPATCHER
Or put another way, you now have a 'customized' or 'parametrized' dispatcher that's logically equivalent to:
def custom_decorator(handler):
if 'callers' not in dir(handler):
handler.callers = {}
for e in _listify(ofp_event.EventOFPSwitchFeatures):
handler.callers[e] = _Caller(_listify(CONFIG_DISPATCHER), e.__module__)
return handler
(If you captured the values of ofp_event.EventOFPSwitchFeatures and CONFIG_DISPATCHER at the moment the #set_ev_cls(...) was called).
The custom_decorator of step 1 is applied to _switch_features_handleras a more traditional unparameterized decorator.

Related

how can a python decorator change calls in decorated function?

I can't figure out how to do this, and frankly, I don't know if it's possible.
I want to write a decorator that changes the way a function is called. It's easiest to see with example code:
def my_print(*args, **kwargs):
print(args[0].upper())
#reroute_decorator('print', my_print)
def my_func():
print('normally this print function is just a print function...')
print('but since my_func is decorated with a special reroute_decorator...')
print('it is replaced with a different function, and its args sent there.')
my_func()
# NORMALLY THIS PRINT FUNCTION IS JUST A PRINT FUNCTION...
# BUT SINCE MY_FUNC IS DECORATED WITH A SPECIAL REROUTE_DECORATOR...
# IT IS REPLACED WITH A DIFFERENT FUNCTION, AND ITS ARGS SENT THERE.
Is a decorator with this kind of functionality even possible in python?
Now, I don't really need this if it's too complex, I just can't figure out how to do it in a simple way.
Is this kind of a problem trivial? Or is it really complex?
You can create a new function with an updated globals dictionary so that to that function it appears that the global was bound to the desired value.
Note that this is weaker than actual dynamic scope as any functions called by the function will see the original bindings and not the modified one.
See namespaced_function referenced in How does Python's types.FunctionType create dynamic Functions?
To elaborate on #Dan D.'s answer, you would create a new function object to replace the original, something like this:
from types import FunctionType
def reroute_decorator(**kwargs):
def actual_decorator(func):
globals = func.__globals__.copy()
globals.update(kwargs)
new_func = FunctionType(
func.__code__, globals, name=func.__name__,
argdefs=func.__defaults__, closure=func.__closure__)
new_func.__dict__.update(func.__dict__)
return new_func
return actual_decorator
The only catch here is that the updated function object is the only one that will see whatever kwargs you passed in, since they will be spoofed into globals. Additionally, any modifications you make to the module after calling the decorator function will not be visible to the decorated function, but that should not be an issue. You can go a layer deeper and create a proxy dictionary that would allow you to interact normally with the original, except for keys you explicitly defined, like print, but that's a bit out of scope here.
I've updated your print implementation to be a bit more general, and made the input to the decorator function more pythonic (less MATLABy):
def my_print(*args, **kwargs):
print(*(str(x).upper() for x in args), **kwargs)
#reroute_decorator(print=my_print)
def my_func():
print('normally this print function is just a print function...')
print('but since my_func is decorated with a special reroute_decorator...')
print('it is replaced with a different function, and its args sent there.')
Which results in:
>>> my_func()
NORMALLY THIS PRINT FUNCTION IS JUST A PRINT FUNCTION...
BUT SINCE MY_FUNC IS DECORATED WITH A SPECIAL REROUTE_DECORATOR...
IT IS REPLACED WITH A DIFFERENT FUNCTION, AND ITS ARGS SENT THERE.

Define variables for a Python function that is implemented outside of the current scope

I was wondering why the following works:
def wrapper():
def wrap(p=10):
def f():
print(p)
f()
return wrap
f2 = wrapper()
f2()
But this doesn't:
def f():
print(p)
def enhance(f):
def wrap(p=10):
f()
return wrap
f2 = enhance(f)
f2() # NameError: name 'p' is not defined
Is there a way I can modify the second scenario so that variable p is defined? I was playing around with function decorators but couldn't figure it out how to expose the variables to the function I'm passing into the decorators.
I think I understand what you are really asking. You're taking about decorators, not variable scope. You say you can't figure out how to "expose the variables to the function I'm passing to the decorators." In your case 2, the function you are passing to enhance doesn't have any variables (arguments). Suppose we give it an argument, like this:
def f(p):
print(p)
def enhance(f):
def wrap(p=10):
f(p) # pass the argument to f
return wrap
f2 = enhance(f)
f2()
Now you have a function, named enhance, which can be used as a decorator. The function to be decorated takes one argument. The decorator will replace this function with a new function, which can be called with one or zero arguments. If called with no arguments it will get the value "10" as a default.
Decorators replace one function with another function. In general it isn't the decorator's job to supply the arguments, except in the case of default arguments as you are trying to do. The arguments come from the code that calls the function.
because in example 2 you’re referencing p that is not defined in one function and used as a parameter in the other function each of which is defined in their own scope.
in example 1 a function defined within the scope of another ie a nested function, has access to the outer functions scope (and therefore its variables)

Python wrappers - Confusion about variable scope

I thought I would be clever and write a wrapper that called the session variables (many are present) and add that to the (django) views requiring session variables. However I seem to not be understanding the scope of the variables, or am writing this incorrectly.
The wrapper I have is:
def s_vars(func_to_decorate):
#wraps(func_to_decorate)
def wrapper(request, *args, **kwargs):
#add all the session variables to kwargs and accessible for the decorated function.
user_obj = request.user
datepicker = request.session['datepicker']
date_format = request.session['date_format']
.........
country = request.session['country']
metric = request.session['metric']
qrydtm = request.session.get("qrydtm",date.today())
result = func_to_decorate(request, *args, **kwargs)
#any post view checks to be done go here
#return to the function to be decorated.
return result
return wrapper
Then for the view I have something like:
#s_vars
def main(request, template_name='placeholder.html'):
return render_to_response(template_name, RequestContext(request,{
'user':user_obj
}))
But this leads to the error that user_obj is not accessible inside the method "main". My understanding was that this is an inner function and therefore the variables in the list under the "wrapper" method would be accessible to this inner function "main". What am I missing here?
The syntax
#spam
def ham():
pass
is precisely equivalent to the syntax
def ham():
pass
ham = spam(ham)
Does that clarify why what you are doing doesn't work?
If you want to pass stuffto a function from a decorator, the usual idiom is to send extra arguments to the function. This can be a little icky, because it means that the argspec that looks right is actually not.
Nested functions only take scoped variables from the scope where they are defined, and the binding takes place at compile time.
You cannot add scoped variables later on, and certainly not with a simple wrapper.
At the point where the inner function is called, it is just called by the outer scope function, not defined in it.
That distinction (also made by interpreter vs runtime) is definitely important in scoping. Take a look at the dis (disassembly) of the s_vars wrapper (or a reduced simple example of the same behaviour). The code is not reinterpreted for different values (it is just a value here) of func_to_decorate.
If you want to make a list of variables available to the inner function, perhaps an object passed in would make more sense. The wrapper could ensure that the external API is without it.

python: alternative to anonymous functions

Python doesn't support complicated anonymous functions. What's a good alternative? For example:
class Calculation:
def __init__(self, func):
self.func = func
def __call__(self, data):
try:
# check if the value has already been calculated
# if it has, it would be cached under key = self.func
return data[self.func]
except KeyError:
pass # first-time call; calculate and cache the values
data[self.func] = self.func(data)
return data[self.func]
# with a simple function, which can be represented using lambda, this works great
f1 = Calculation(lambda data : data['a'] * data['b'])
# with a complicated function, I can do this:
def f2_aux:
# some complicated calculation, which isn't suitable for a lambda one-liner
f2 = Calculation(f2_aux)
Is this a reasonable design to begin with?
If so, is there a way to avoid the ugliness of f*_aux for each f* that I define in the module?
UPDATE:
Example of use:
d = {'a' : 3, 'b' : 6}
# computes 3 * 6
# stores 18 in d under a key <function <lambda> at ...>
# returns 18
f1(d)
# retrieves 18 from d[<function <lambda> at ...>]
# returns 18, without having to recalculate it
f1(d)
UPDATE:
Just for my understanding, I added a version that uses the inner function.
def memoize(func):
def new_func(data):
try:
# check if the value has already been calculated
# if it has, it would be cached under key = self.func
return data[func]
except KeyError:
pass # first-time call; calculate and cache the values
data[func] = func(data)
return data[func]
return new_func
#memoize
def f1(data):
return data['a'] * data['b']
You don't need anonymous functions. Also, memoization has been done better than this, there's probably no reason for you to roll your own.
But to answer the question: You can use your class as a decorator.
#Calculation
def f2():
...
This simply defined the function, wraps it in Calculation and stored the result of that as f2.
The decorator syntax is defined to be equivalent to:
_decorator = Calculation # a fresh identifier
# not needed here, but in other cases (think properties) it's useful
def f2():
...
f2 = _decorator(f2)
The alternative to an anonymous function is a non-anonymous function. An anonymous function is only anonymous in the context where it was defined. But it is not truly anonymous, because then you could not use it.
In Python you make anonymous functions with the lambda statement. You can for example do this:
output = mysort(input, lambda x: x.lastname)
The lambda will create a function, but that function has no name in the local space, and it's own name for itself is just '<lambda>'. But if we look at mysort, it would have to be defined something like this:
def mysort(input, getterfunc):
blahblahblah
As we see here, in this context the function isn't anonymous at all. It has a name, getterfunc. From the viewpoint of this function it does not matter if the function passed in are anonymous or not. This works just as well, and is exactly equivalent in all significant ways:
def get_lastname(x):
return x.lastname
output = mysort(input, get_lastname)
Sure, it uses more code, but it is not slower or anything like that. In Python, therefore anonymous functions are nothing but syntactic sugar for ordinary functions.
A truly anonymous function would be
lambda x: x.lastname
But as we don't assign the resulting function to anything, we do not get a name for the function, and then we can't use it. All truly anonymous functions are unusable.
For that reason, if you need a function that can't be a lambda, make it an ordinary function. It can never be anonymous in any meaningful way, so why bother making it anonymous at all? Lambdas are useful when you want a small one-line function and you don't want to waste space by defining a full function. That they are anonymous are irrelevant.
A closure can be a succinct alternative to writing a class such as the one in your example. The technique involves putting a def inside another def. The inner function can have access to the variable in the enclosing function. In Python 3, the nonlocal keyword gives you write access to that variable. In Python 2, you need to use a mutable value for the nonlocal variable in order to be able to update it from the inner function.
About the question regarding anonymous functions, the language intentionally pushes you back to use def for anything more complicated than a lambda can handle.

"self" inside plain function?

I've got a bunch of functions (outside of any class) where I've set attributes on them, like funcname.fields = 'xxx'. I was hoping I could then access these variables from inside the function with self.fields, but of course it tells me:
global name 'self' is not defined
So... what can I do? Is there some magic variable I can access? Like __this__.fields?
A few people have asked "why?". You will probably disagree with my reasoning, but I have a set of functions that all must share the same signature (accept only one argument). For the most part, this one argument is enough to do the required computation. However, in a few limited cases, some additional information is needed. Rather than forcing every function to accept a long list of mostly unused variables, I've decided to just set them on the function so that they can easily be ignored.
Although, it occurs to me now that you could just use **kwargs as the last argument if you don't care about the additional args. Oh well...
Edit: Actually, some of the functions I didn't write, and would rather not modify to accept the extra args. By "passing in" the additional args as attributes, my code can work both with my custom functions that take advantage of the extra args, and with third party code that don't require the extra args.
Thanks for the speedy answers :)
self isn't a keyword in python, its just a normal variable name. When creating instance methods, you can name the first parameter whatever you want, self is just a convention.
You should almost always prefer passing arguments to functions over setting properties for input, but if you must, you can do so using the actual functions name to access variables within it:
def a:
if a.foo:
#blah
a.foo = false
a()
see python function attributes - uses and abuses for when this comes in handy. :D
def foo():
print(foo.fields)
foo.fields=[1,2,3]
foo()
# [1, 2, 3]
There is nothing wrong with adding attributes to functions. Many memoizers use this to cache results in the function itself.
For example, notice the use of func.cache:
from decorator import decorator
#decorator
def memoize(func, *args, **kw):
# Author: Michele Simoniato
# Source: http://pypi.python.org/pypi/decorator
if not hasattr(func, 'cache'):
func.cache = {}
if kw: # frozenset is used to ensure hashability
key = args, frozenset(kw.iteritems())
else:
key = args
cache = func.cache # attribute added by memoize
if key in cache:
return cache[key]
else:
cache[key] = result = func(*args, **kw)
return result
You can't do that "function accessing its own attributes" correctly for all situations - see for details here how can python function access its own attributes? - but here is a quick demonstration:
>>> def f(): return f.x
...
>>> f.x = 7
>>> f()
7
>>> g = f
>>> g()
7
>>> del f
>>> g()
Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
File "<interactive input>", line 1, in f
NameError: global name 'f' is not defined
Basically most methods directly or indirectly rely on accessing the function object through lookup by name in globals; and if original function name is deleted, this stops working. There are other kludgey ways of accomplishing this, like defining class, or factory - but thanks to your explanation it is clear you don't really need that.
Just do the mentioned keyword catch-all argument, like so:
def fn1(oneArg):
// do the due
def fn2(oneArg, **kw):
if 'option1' in kw:
print 'called with option1=', kw['option1']
//do the rest
fn2(42)
fn2(42, option1='something')
Not sure what you mean in your comment of handling TypeError - that won't arise when using **kw. This approach works very well for some python system functions - check min(), max(), sort(). Recently sorted(dct,key=dct.get,reverse=True) came very handy to me in CodeGolf challenge :)
Example:
>>> def x(): pass
>>> x
<function x at 0x100451050>
>>> x.hello = "World"
>>> x.hello
"World"
You can set attributes on functions, as these are just plain objects, but I actually never saw something like this in real code.
Plus. self is not a keyword, just another variable name, which happens to be the particular instance of the class. self is passed implicitly, but received explicitly.
if you want globally set parameters for a callable 'thing' you could always create a class and implement the __call__ method?
There is no special way, within a function's body, to refer to the function object whose code is executing. Simplest is just to use funcname.field (with funcname being the function's name within the namespace it's in, which you indicate is the case -- it would be harder otherwise).
This isn't something you should do. I can't think of any way to do what you're asking except some walking around on the call stack and some weird introspection -- which isn't something that should happen in production code.
That said, I think this actually does what you asked:
import inspect
_code_to_func = dict()
def enable_function_self(f):
_code_to_func[f.func_code] = f
return f
def get_function_self():
f = inspect.currentframe()
code_obj = f.f_back.f_code
return _code_to_func[code_obj]
#enable_function_self
def foo():
me = get_function_self()
print me
foo()
While I agree with the the rest that this is probably not good design, the question did intrigue me. Here's my first solution, which I may update once I get decorators working. As it stands, it relies pretty heavily on being able to read the stack, which may not be possible in all implementations (something about sys._getframe() not necessarily being present...)
import sys, inspect
def cute():
this = sys.modules[__name__].__dict__.get(inspect.stack()[0][3])
print "My face is..." + this.face
cute.face = "very cute"
cute()
What do you think? :3
You could use the following (hideously ugly) code:
class Generic_Object(object):
pass
def foo(a1, a2, self=Generic_Object()):
self.args=(a1,a2)
print "len(self.args):", len(self.args)
return None
... as you can see it would allow you to use "self" as you described. You can't use an "object()" directly because you can't "monkey patch(*)" values into an object() instance. However, normal subclasses of object (such as the Generic_Object() I've shown here) can be "monkey patched"
If you wanted to always call your function with a reference to some object as the first argument that would be possible. You could put the defaulted argument first, followed by a *args and optional **kwargs parameters (through which any other arguments or dictionaries of options could be passed during calls to this function).
This is, as I said hideously ugly. Please don't ever publish any code like this or share it with anyone in the Python community. I'm only showing it here as a sort of strange educational exercise.
An instance method is like a function in Python. However, it exists within the namespace of a class (thus it must be accessed via an instance ... myobject.foo() for example) and it is called with a reference to "self" (analagous to the "this" pointer in C++) as the first argument. Also there's a method resolution process which causes the interpreter to search the namespace of the instance, then it's class, and then each of the parent classes and so on ... up through the inheritance tree.
An unbound function is called with whatever arguments you pass to it. There can't bee any sort of automatically pre-pended object/instance reference to the argument list. Thus, writing a function with an initial argument named "self" is meaningless. (It's legal because Python doesn't place any special meaning on the name "self." But meaningless because callers to your function would have to manually supply some sort of object reference to the argument list and it's not at all clear what that should be. Just some bizarre "Generic_Object" which then floats around in the global variable space?).
I hope that clarifies things a bit. It sounds like you're suffering from some very fundamental misconceptions about how Python and other object-oriented systems work.
("Monkey patching" is a term used to describe the direct manipulation of an objects attributes -- or "instance variables" by code that is not part of the class hierarchy of which the object is an instance).
As another alternative, you can make the functions into bound class methods like so:
class _FooImpl(object):
a = "Hello "
#classmethod
def foo(cls, param):
return cls.a + param
foo = _FooImpl.foo
# later...
print foo("World") # yes, Hello World
# and if you have to change an attribute:
foo.im_self.a = "Goodbye "
If you want functions to share attribute namespaecs, you just make them part of the same class. If not, give each its own class.
What exactly are you hoping "self" would point to, if the function is defined outside of any class? If your function needs some global information to execute properly, you need to send this information to the function in the form of an argument.
If you want your function to be context aware, you need to declare it within the scope of an object.

Categories