1

How to access a variable x that is local for a function main() from another function sub() that is called inside main()?

The MEW below throws an error NameError: global name 'x' is not defined when the script is run.

If I add global x, l in main() there are no errors anymore, but I do not want to make these variables global as such.

MWE:

def sub():
    print "x from main: {}".format(x)
    print "l from main: {}".format(l)


def main():
    x = 5
    l = [1,2,3,4,5]
    print "z from top: {}".format(z)
    sub()


if __name__ == "__main__":
    z = 'SOME'
    main()

Edit1 I am editing an existing code and prefer not to change arity of functions

1
  • 1
    Pass them as arguments to the function. Commented Feb 14, 2019 at 0:19

2 Answers 2

3

Passing the parameters as arguments gets what you want done.

def sub(x, l):
    print "x from main: {}".format(x)
    print "l from main: {}".format(l)


def main(z):
    x = 5
    l = [1,2,3,4,5]
    print "z from top: {}".format(z)
    sub(x, l)


if __name__ == "__main__":
    z = 'SOME'
    main(z)

This prints:

z from top: SOME
x from main: 5
l from main: [1, 2, 3, 4, 5]

If you don't want to use this approach, I guess you could follow this answer's approach, although seems convoluted for a case like this.

import inspect

z = 'SOME'

def sub():
    frame = inspect.currentframe()
    locales = None
    try: locales = frame.f_back.f_locals
    finally: del frame
    if locales:
        for k, v in locales.items():
            print("{} from main: {}".format(k, v))


def main():
    x = 5
    l = [1,2,3,4,5]
    print("z from top: {}".format(z))
    sub()

main(z)

Maybe this would be cleaner if you could turn this into a context manager.

You could also use *args and *kwargs

def function(*args, **kwargs):
    if args:
        for a in args:
            print "value: {} was passed in args".format(a)
    if kwargs:
        for k, v in kwargs.items():
            print "key {} was passed with value: {} in kwargs".format(k, v)


def caller():
    x = 5
    l = [1,2,3,4,5]
    function(x, l = l)

caller()
#value: 5 was passed in args
#key l was passed with value: [1, 2, 3, 4, 5] in kwargs

From here you can assign values to locals

within function

locals['x'] = args[0]
locals['l'] = kwargs[l]

OR use dict.get this way you can set defaults:

l = kwargs.get('l', None)
Sign up to request clarification or add additional context in comments.

3 Comments

I am editing already existing code and I prefer not to change arity of functions.
Edited my answer
Added another option
1

The best way to do what you'd like, also requires the least amount of changes. Just change the way you're declaring the variables; by adding the function name before the variable name, you're able to access the variable from anywhere in your code.

def sub():
    print "x from main: {}".format(main.x)
    print "l from main: {}".format(main.l)

def main():
    main.x = 5
    main.l = [1,2,3,4,5]
    print "z from top: {}".format(z)
    sub()

if __name__ == "__main__":
    z = 'SOME'
    main()

This will print:

z from top: SOME
x from main: 5
l from main: [1, 2, 3, 4, 5]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.