Accessing the outer scope in Python 2.6

2019-06-18 10:33发布

问题:

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:

  1. Use globals. By the way, func.__globals__ is a mutable dictionary ;)
  2. Store variables in a dict/class-instance/any other mutable container
  3. Give variables as arguments & get them back as a tuple: a,b,c = innerfunc(a,b,c)
  4. Inject other function's bytecode. This is possible with byteplay python module.

回答1:

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").



回答2:

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


回答3:

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()


回答4:

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


回答5:

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.



标签: python scope