Make all variables in a Python function global
Asked Answered
A

5

30

Is there a simple way to make all variables in a function global?

I have 20 odd variables in a function and naming them global one by one doesn't make nice code... to me anyway :)

Albert answered 18/7, 2012 at 14:7 Comment(8)
An easy way to achieve this is to use some very old version of BASIC.Electrify
@SvenMarnach -- or fortran common blocks!Octavalent
@Albert -- All joking aside. Why do you want to do this? If you can tell us your reason behind wanting this, maybe we can suggest a better data structure.Octavalent
why i want this is because i want to use these variables in different functions in the same scriptAlbert
Create a class with 20 attributes, and your functions are its methods.Mansoor
Or just pass around a dictionary...Ghee
Of course it isn't nice in an application, but Python can be a handy thing to use for quick scripting tasks, and it is nice to be able to do hacky things like the OP asks when you just want to get something done fast. It would be a waste of time to write a proper class for such use cases.Elyn
I came here because I wanted to create a function to initialize a bunch of global constants, which IMHO is better than having the first 20 lines of main being assignments.Damages
S
71

Warning: Don't try this at home, you might burn it down.

There is no legitimate reason to do the following in the course of normal day-to-day programming. Please review the other answers to this question for more realistic alternatives.

I can barely imagine why you would want to do this, but here is a way to do it:

def f(a, b, c):
    d = 123
    e = 'crazy, but possible'
    globals().update(locals())

def g():
    print a, b, c, d ,e

>>> globals()
{'g': <function g at 0x875230>, 'f': <function f at 0x8751b8>, '__builtins__': <module '__builtin__' (built-in)>, '__package__': None, '__name__': '__main__', '__doc__': None}

>>> g()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in g
NameError: global name 'a' is not defined

>>> f(10, 20, 'blah')
>>> g()
10 20 blah 123 crazy, but possible

>>> globals()
{'a': 10, 'c': 'blah', 'b': 20, 'e': 'crazy, but possible', 'd': 123, 'g': <function g at 0x875230>, 'f': <function f at 0x8751b8>, '__builtins__': <module '__builtin__' (built-in)>, '__package__': None, '__name__': '__main__', '__doc__': None}
Symptomatology answered 18/7, 2012 at 14:29 Comment(9)
I think in "normal" code this really, really isn't a good idea. If you're doing some kind of crazy metaprogramming or messing with interpreter internals then it might be useful, but not for general application code :(Nostoc
@Ned Batchelder: As horrible as it is, this answers the OP's question. I agree with your comment here, but on the other hand, your answer denies that it is even possible - and clearly it actually is possible. He's asking to burn his house down; you're telling him that it's impossible... I hope he doesn't ask you how put out the fire :)Symptomatology
@mhawke: I hope you don't seriously believe that you are helping the OP by literally answering his question rather than pointing him to the right answer. If a co-worker asked you would this question, would you answer this way and then just go back to your own work? Or would you insist on helping him write good code?Retire
@Ned Batchelder: No, as I said I agree with your comment. I don't agree with that part of your answer which states that there is no way to do it, so I posted my answer after yours to show that it is indeed possible. Who am I (or you) to judge the purpose of the question or the level of experience of the OP? Of course there is probably no legitimate reason to do this, it's outrageous, but perhaps the OP is just curious. Anyway, I've updated my answer with a warning.Symptomatology
Although OP definitely shouldn't do this, it answered perfectly what I was wondering when I saw the title to this question.Medlar
Don't look at me funny but I can imagine places where this trick may be useful. For example in scientific computing if you just want to reuse an operation (thus throw it into a function) in a quick data munging script that you'll only use once. With NumPy and SciPy around Python gets used for lots of stuff that isn't software. Now, I've never done this, but I can't say we should pretend it can't be done lest some newb go wrong with it. I see nothing wrong with both showing how it can be done and saying it really usually shouldn't.Adaline
sometime when you write pilot of a long code including functions, there are some errors occurring inside functions, one could figure out these errors better if he knows what are the actual values of variables inside the functions which he wouldnt know if they are localMyrtia
@user3015703 - not really. The locals can be displayed/printed from within the function, or better yet, use a debugger instead.Symptomatology
Ugh, you are all so damn pure, celibate and self-righteous! Grow a pair! It's not like python even clutters up locals() with other random crap that might bite you in the ass. This is a great answer and very useful, thank-you. In invested some points to downvote every answer that dissed this question or this perfect answer.Mollee
N
14

The pythonic way to do this is either to keep the variables in local scope (i.e. define them within each function) and pass them between the functions as arguments / return values; or to keep your variables as attributes of an object or class making your "functions" methods in that class. Either way is OK, but the global keyword is designed specifically to put you off using it in the way you describe. Global variables are not just "bad style" but they make your code very difficult to maintain, as any invariants that your variables need to stick to need to be checked in every function.

Here is an example of good style (with functions):

def quads(a, b, c):
    x1 = (-1.0 * b + math.sqrt(b * b - 4.0 * a * c)) / (2.0 * a)
    x2 = (-1.0 * b - math.sqrt(b * b - 4.0 * a * c)) / (2.0 * a)
    return x1, x2

def pretty(a, b, c, x1, x2):
    eqn = "%fx^2 + %fx + %c" % (a, b, c)
    print "The first solution to the equation %s is: %f" % (eqn, x1)
    print "The second solution to the equation %s is: %f" % (eqn, x2)
    return

def main():
    a = 100
    b = 200
    c = 300
    x1, x2 = quads(a, b, c)
    pretty(a, b, c, x1, x2)
    return

if __name__ == '__main__':
    main()

Here is an example of good style (with OOP):

class Quadratic(object):

    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c
        self.x1 = None 
        self.x2 = None 
        self.solve() # Set x1 and x2 to correct values
        # To maintain the invariant between a, b, c and x1, x1
        # we should override __setattr__ or use descriptors or
        # properties so that self.solve() is called every time
        # a, b, or c are updated.
        return

    def solve(self):
        self.x1 = (-1.0 * self.b +
                   math.sqrt(self.b * self.b - 4.0 * self.a * self.c)) / (2.0 * self.a)
        self.x2 = (-1.0 * self.b - 
                   math.sqrt(self.b * self.b - 4.0 * self.a * self.c)) / 2.0 * self.a
        return 

    def pretty(self):
        eqn = "%fx^2 + %fx + %c" % (self.a, self.b, self.c)
        print "The first solution to the equation %s is: %f" % (eqn, self.x1)
        print "The second solution to the equation %s is: %f" % (eqn, self.x2)
        return

def main():
    quad = Quadratic(100, 200, 300)
    quad.pretty()
    return

if __name__ == '__main__':
    main()
Nostoc answered 18/7, 2012 at 16:19 Comment(0)
R
8

There's no way to declare them all as global, and you really don't want to. Those 20 variables probably should be turned into an object with 20 attributes instead.

Retire answered 18/7, 2012 at 14:24 Comment(7)
why i want this is because i want to use these variables in different functions in the same scriptAlbert
Exactly what an object is for. Or a closure, maybe.Ursel
I agree, but 20 seems like a lot. I wonder if these are all good attributes of a class or if some of them should just be local to certain methods and communicated by return values and arguments.Toomer
This may be a good advice, but good intentions do not make the "no way" statement correct. This should be edited.Melany
this isn't an answer. the ten upvotes don't make it an answer. use the question comments instead.Hayseed
@Ben. The question was, "Is there a simple way to..." The answer is, "No."Retire
-1, "answering" a question with "don't do that" isn't an answer. Answering with "You can, but shouldn't, so for educational purposes about learning how Python works, this illustrates how, and now here's what you really should do instead" is an answer.Yokoyokohama
I
5

The simplest solution is to have only a single global — or, better yet, to figure out how to pass it in to the function. Using it as a global would look like this (again, I am showing the simplest possible case, not necessarily the best use of Python):

class Info(object):  # or whatever you want to name the container
    """Holder for global information."""

info = Info()        # single instance we will use

def my_function():
    print "Here is some info:"
    print info.a, info.b, info.c

info.a = 3
info.b = 8
info.c = []

if __name__ == '__main__':
    my_function()

Again, I would probably pass info to the function instead. But since your question was about a global, it's shown here as a global.

Intention answered 19/7, 2012 at 1:3 Comment(0)
M
3

A niche example where I wanted to do this: use a function for importing.*

def temp():
    a = "stays local value"
    old_locs = locals().copy()
    b = "is global value"
    import math
    new_locs = locals()
    new_vars = {k: new_locs[k] for k in set(new_locs) - set(old_locs)
                if k != 'old_locs'}
    globals().update(new_vars)    
temp()
print(b)
print(math.sqrt(3))
print(a)

gives
is global value

1.7320508075688772

NameError: name 'a' is not defined

This way only the specific 20 or so variables would get update the global namespace and intermediate variable names in the function wouldn't.

*I needed to import from a .ipynb file, and the process for doing so depends if called from google Collaboratory, a desktop .ipynb, or a desktop .py file; this involved the use of magics which are treated as invalid syntax in situation which wouldn't call those branches, so by importing my import function I can escape that issue.

Multicellular answered 14/3, 2021 at 4:3 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.