Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why would people use globals() to define variables

Tags:

python

pylint

I've come across recently a number of places in our code which do things like this

...
globals()['machine'] = otherlib.Machine()
globals()['logger'] = otherlib.getLogger()
globals()['logfile'] = datetime.datetime.now().strftim('logfiles_%Y_%m_%d.log')

and I am more than a little confused as to why people would do that, rather than doing

global machine
machine = otherlib.Machine()

and so on.

Here is a slightly anonymised function which does this, in full:

def openlog(num)
    log_file = '/log_dir/thisprogram.' + num
    if os.path.exists(log_file):
        os.rename(log_file, log_file + '.old')

    try:
        globals()["log"] = open(log_file, 'w')
        return log
    except:
       print 'Unable to open ' + log_file
       sys.exit(1)

It confuses the hell out of pylint (0.25) as well me.

Is there any reason for coding it that way? There's minimal usage of eval in our code, and this isn't in a library

PS I checked Reason for globals() in python but it doesn't really answer as to why you'd use this for setting globals in a program

like image 327
Tom Tanner Avatar asked Jan 15 '14 17:01

Tom Tanner


2 Answers

Maybe the function uses a local variable with the same name as the global one, and the programmer didn't want to bother changing the variable name?

def foo(bar):
    global bar # SyntaxError
    bar = bar + 1

def foo(bar):
    globals()['bar'] = bar + 1 
foo(1)
print(bar) # prints 2

Another use case, albeit still a bit specious (and clearly not the case in the example function you gave), is for defining variable names dynamically. This is rarely, if ever, a good idea, but it does come up a lot in questions on this site, at least. For example:

>>> def new_variable():
...     name = input("Give your new variable a name! ")
...     value = input("Give your new variable a value! ")
...     globals()[name] = value
...
>>> new_variable()
Give your new variable a name! foo
Give your new variable a value! bar
>>> print(foo)
bar

Otherwise, I can think of only one reason to do this: perhaps some supervising entity requires that all global variables be set this way, e.g. "in order to make it really, really clear that these variables are global". Or maybe that same supervising entity has placed a blanket ban on the global keyword, or docks programmer pay for each line.

I'm not saying that any of these would be a good reason, but then again, I truly can't conceive of a good reason to define variables this way if not for scoping purposes (and even then, it seems questionable...).


Just in case, I did a timing check, to see if maybe the globals() call is faster than using the keyword. I'd expect the function call + dictionary access to be significantly slower, and it is.

>>> import timeit
>>> timeit.timeit('foo()', 'def foo():\n\tglobals()["bar"] = 1',number=10000000)
2.733132876863408
>>> timeit.timeit('foo()', 'def foo():\n\tglobal bar\n\tbar = 1',number=10000000)
1.6613818077011615

Given the code you posted and my timing results, I can think of no legitimate reason for the code you're looking at to be written like this. Looks like either misguided management requirement, or simple incompetence.

like image 194
Henry Keiter Avatar answered Oct 13 '22 21:10

Henry Keiter


Are the authors PHP converts? This is a valid code in PHP:

$GLOBALS['b'] = $GLOBALS['a'] + $GLOBALS['b'];

See this for more examples. If someone was used to this way of writing the code, maybe they just used the closest matching way of doing it in Python and didn't bother to check for alternatives.

You'd sometimes use a superglobal $GLOBAL variable to define something, because although global keyword exists in PHP, it will only import existing variables - it cannot create a new variable as far as I know.

like image 26
viraptor Avatar answered Oct 13 '22 21:10

viraptor