开发者

Accessing the outer scope in Python 2.6

开发者 https://www.devze.com 2023-02-05 20:41 出处:网络
Say, I have some scope with variables, and a function called in this scope wants to change some immutable variables:

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 variable开发者_如何学JAVAs 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.


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
0

精彩评论

暂无评论...
验证码 换一张
取 消