Can I use a decorator to mutate the local scope of a function in Python?

Echoing Hop's answer Don't do it Seriously, don't do this. Lisp and Ruby are more appropriate languages for writing your own custom syntax. Use one of those.

Or find a cleaner way to do this If you must, you want dynamic scoped variables, not lexically scoped Python doesn't have dynamically scoped variables, but you can simulate it. Here's an example that simulates it by creating a global binding, but restores the previous value on exit: codepad.org/6vAY8Leh def adds_dynamic_z_decorator(f): def replacement(*arg,**karg): # create a new 'z' binding in globals, saving previous if 'z' in globals(): oldZ = (globals()'z',) else: oldZ = None try: globals()'z' = None #invoke the original function res = f(*arg, **karg) finally: #restore any old bindings if oldZ: globals()'z' = oldZ0 else: del(globals()'z') return res return replacement @adds_dynamic_z_decorator def func(x,y): print z def other_recurse(x): global z print 'x=%s, z=%s' %(x,z) recurse(x+1) print 'x=%s, z=%s' %(x,z) @adds_dynamic_z_decorator def recurse(x=0): global z z = x if x.

Echoing Hop's answer Don't do it. Seriously, don't do this. Lisp and Ruby are more appropriate languages for writing your own custom syntax.

Use one of those. Or find a cleaner way to do this If you must, you want dynamic scoped variables, not lexically scoped. Python doesn't have dynamically scoped variables, but you can simulate it.

Here's an example that simulates it by creating a global binding, but restores the previous value on exit: codepad.org/6vAY8Leh def adds_dynamic_z_decorator(f): def replacement(*arg,**karg): # create a new 'z' binding in globals, saving previous if 'z' in globals(): oldZ = (globals()'z',) else: oldZ = None try: globals()'z' = None #invoke the original function res = f(*arg, **karg) finally: #restore any old bindings if oldZ: globals()'z' = oldZ0 else: del(globals()'z') return res return replacement @adds_dynamic_z_decorator def func(x,y): print z def other_recurse(x): global z print 'x=%s, z=%s' %(x,z) recurse(x+1) print 'x=%s, z=%s' %(x,z) @adds_dynamic_z_decorator def recurse(x=0): global z z = x if x.

Thanks - this would do what I wanted; but I certainly won't be using it. But at least my curiosity is satisfied now! I'd still like a way to get at some sort of avoiding my copy/paste issue, but I'm not sure how yet - I'll play around some more.

– Toby White Feb 26 '09 at 21:48 Interesting but I wonder will using this break anything in Python? – smci Sep 20 at 22:15.

I don't know about the local scope, but you could provide an alternative global name space temporarily. Something like: import types def my_decorator(fn): def decorated(*args,**kw): my_globals={} my_globals. Update(globals()) my_globals'z'='value of z' call_fn=types.

FunctionType(fn. Func_code,my_globals) return call_fn(*args,**kw) return decorated @my_decorator def func(x, y): print z func(0,1) Which should print "value of z.

Though obviously this might be a bit much like "magic". – John Montgomery Feb 26 '09 at 16:27 wouldn't this freeze the state of my_globals to the state of globals at the time func is defined? – hop Feb 26 '09 at 16:28 not that it matters much... – hop Feb 26 '09 at 16:29 Nope, my_globals gets re-created each time decorated gets called (which the actual function returned by the decorated).

That should mean that you always have the latest globals. – John Montgomery Feb 26 '09 at 16:33 1 hey - it was that way when I found it ;^) – John Montgomery Feb 26 '09 at 16:47.

A) don't do it. B) seriously, why would you do that? C) you could declare z as global within your decorator, so z will not be in globals() until after the decorator has been called for the first time, so the assert won't bark.

D) why?

1: If you want a function that has a "memory" or "cache", define a callable object, use the call_ method. – S. Lott Feb 26 '09 at 16:27 Seriously, why would you want to?

You want Common Lisp and it's ability to extend the language. Or maybe Ruby can do this. Python is good for many things, but not this.

– Aaron Feb 26 '09 at 18:53 If you reload that code after global z is declared, the assert will break right? – smci Sep 20 at 22:17.

I could probably get a similar effect from using the class infrastructure as well, but I wanted to see if it was doable with raw functions. Well, Python is an object-oriented language. You should do this in a class, in my opinion.

Making a nice class interface would surely simplify your problem. This isn't what decorators were made for.

I'll first echo the "please don't", but that's your choice. Here's a solution for you: assert 'z' not in globals () class my_dec: def __init__ (self, f): self. F = f def __call__ (self,x,y): z = x+y self.

F(x,y,z) @my_dec def func (x,y,z): print z func (1,3) It does require z in the formal parameters, but not the actual.

Explicit is better than implicit. Is this good enough? Def provide_value(f): f.

Foo = "Bar" return f @provide_value def g(x): print g. Foo (If you really want evil, assigning to f. Func_globals seems fun.).

That's where I started, roughly - but if I do this across ten functions, (each of which has a different name) then my foo is named g. Foo, h. Foo, i.

Foo, ... in each function. I just want to talk about foo. – Toby White Feb 27 '09 at 9:39.

Others have given a few ways of making a working decorator, many have advised against doing so because it's so stylistically different from normal python behavior that it'll really confuse anyone trying to understand the code. If you're needing to recalculate things a lot, would it make sense to group them together in an object? Compute z1...zN in the constructor, then the functions that use these values can access the pre-computed answers as part of the instance.

They're not all reachable from some outermost foo scope). So which y would you get the value of? The value of y in foo just isn't a well-defined concept unless you're talking about within the scope of foo.

Given Python's flexibility, I'm pretty sure it's possible to do stack frame introspection and find a stack frame for foo when there is one currently live and pull out the values of its local variables at that time. This would be pretty hard (if not impossible) to do with a decorator, because (unless foo is a generator) the decorator can only add wrapper code "around" foo, which means the code controlled by the decorator runs before and after foo runs, so you only get control when foo's stack frame doesn't exist. I'm not going to give specific pointers on exactly how to do this, because I don't know how to do it.

It sounds like it's almost certainly a bad idea though, unless you're writing a debugger.

I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.

Related Questions