Say, I have some scope with variables, and a function called in this scope wants to change some immutable variables:
def outer(): s = 'qwerty' n = 123 modify() def modify(): s = 'abcd' n = 456
Is it possible somehow to access the outer scope? Something like nonlocal
variables from Py3k.
Sure I can do s,n = modify(s,n)
in this case, but what if I need some generic 'injection' which executes there and must be able to reassign to arbitrary variables?
I have performance in mind, so, if possible, eval
& stack frame inspection is not welcome :)
UPD: It's impossible. Period. However, there are some options how to access variables in the outer scope:
- Use globals. By the way,
func.__globals__
is a mutable dictionary ;) - Store variables in a dict/class-instance/any other mutable container
- Give variable开发者_如何学JAVAs as arguments & get them back as a tuple:
a,b,c = innerfunc(a,b,c)
- Inject other function's bytecode. This is possible with
byteplay
python module.
Define the variables outside of the functions and use the global
keyword.
s, n = "", 0
def outer():
global n, s
n = 123
s = 'qwerty'
modify()
def modify():
global n, s
s = 'abcd'
n = 456
Sometimes I run across code like this. A nested function modifies a mutable object instead of assigning to a nonlocal
:
def outer():
s = [4]
def inner():
s[0] = 5
inner()
This is not how nonlocal
works. It doesn't provide dynamic scoping (which is just a huge PITA waiting to happen and even more rarely useful than your average "evil" feature). It just fixes up lexical scoping.
Anyway, you can't do what you have in mind (and I would say that this is a good thing). There's not even a dirty but easy hack (and while we're at it: such hacks are not discouraged because they generally perform a bit worse!). Just forget about it and solve the real problem properly (you didn't name it, so we can't say anything on this).
The closest you could get is defining some object that carries everything you want to share and pass that around explicitly (e.g. make a class and use self
, as suggested in another answer). But that's relatively cumbersome to do everywhere, and still hackery (albeit better than dynamic scoping, because "explicit is better than implicit").
Your options are to use global variables,
s = None
n = None
def outer(self):
global s
global n
s = 'qwerty'
n = 123
modify()
def modify(self):
global s
global n
s = 'abcd'
n = 456
or define those as methods and use a class or instance variable.
class Foo(object):
def __init__(self):
self.s = None
self.n = None
def outer(self):
self.s = 'qwerty'
self.n = 123
self.modify()
def modify(self):
self.s = 'abcd'
self.n = 456
You can probably also do this (not saying it is right);
define a function that returns an array with rows like so
["a = qwerty","n = 123"]
Then do in the scope you need the vars
for row in array:
eval(row)
this is pretty darn hacky though.
def a():
i = 1
def b():
# i = 2
def c():
nonlocal i
i = 3
c()
print('b:', i)
b()
print('a:', i)
a()
nonlocal
will search in upper level scope, and go upper if not found
> python3 t.py
b: 3
a: 1
comment i = 2
> python3 t.py
b: 3
a: 3
精彩评论