Accessing the outer scope in Python 2.6

11,023

Solution 1

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

Solution 2

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

Solution 3

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

Solution 4

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.

Share:
11,023
kolypto
Author by

kolypto

Enthusiastic Python/JS back-end developer. Loves exceptional projects and challenging tasks. Architects chaos into well-structured formations. Friendly and business-minded. Loves people. Always smiles :) CV and Contacts

Updated on July 29, 2022

Comments

  • kolypto
    kolypto almost 2 years

    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.
  • Admin
    Admin over 13 years
    Replace and with xor for this to work. Rewrite from scratch for good advice.
  • gotgenes
    gotgenes over 13 years
    He means "define them outside, or use global, but not both".
  • Admin
    Admin over 13 years
    If you defined the variables in global scope and declared them global (as opposed to doing either), then it would, strictly speaking, work - but of course that's not a proper solution. (Edit: Just noticed I mixed things up... should be "replace xor with and" - iFail)
  • gotgenes
    gotgenes over 13 years
    That's interesting. Ugly, but interesting.
  • joeforker
    joeforker over 13 years
    You can type outer.s = 4, but that will assign an attribute to the outer() function. It is not the same as assigning to the local variable called s.
  • Ord
    Ord over 11 years
    I think you mean exec(row); eval is for expressions only
  • kolypto
    kolypto almost 4 years
    The question is about Python 2.6 ;)