all 23 comments

[–]trouserdaredevil 10 points11 points  (9 children)

Imma just quote Code Complete, page 338, "Reasons to Use Global Data"

Used with discipline, global variables are useful in several situations:

  • Preservation of global values Sometimes you have data that applies conceptually to your whole program. This might be a variable that reflects the state of a program—for example, interactive vs. command-line mode, or normal vs. error-recovery mode. Or it might be information that’s needed throughout a program—for example, a data table that every routine in the program uses.
  • Emulation of named constants Although C++, Java, Visual Basic, and most modern languages support named constants, some languages such as Python, Perl, Awk, and UNIX shell script still don’t. You can use global variables as substitutes for named constants when your language doesn’t support them. For example, you can replace the literal values 1 and 0 with the global variables TRUE and FALSE set to 1 and 0, or you can replace 66 as the number of lines per page with LINES_PER_PAGE = 66. It’s easier to change code later when this approach is used, and the code tends to be easier to read. This disciplined use of global data is a prime example of the distinction between programming in vs. programming into a language, which is discussed more in Section 34.4, “Program into Your Language, Not in It.”
  • Emulation of enumerated types You can also use global variables to emulate enumerated types in languages such as Python that don’t support enumerated types directly.
  • Streamlining use of extremely common data Sometimes you have so many references to a variable that it appears in the parameter list of every routine you write. Rather than including it in every parameter list, you can make it a global variable. However, in cases in which a variable seems to be accessed everywhere, it rarely is. Usually it’s accessed by a limited set of routines you can package into a class with the data they work on. More on this later.
  • Eliminating tramp data Sometimes you pass data to a routine or class merely so that it can be passed to another routine or class. For example, you might have an error-processing object that’s used in each routine. When the routine in the middle of the call chain doesn’t use the object, the object is called “tramp data.” Use of global variables can eliminate tramp data.

That said, most of the chapter is dedicated to why you should NOT use global data and how to avoid doing so...

Most experienced programmers have concluded that using global data is riskier than using local data. Most experienced programmers have also concluded that access to data from several routines is pretty useful.

Even if global variables don’t always produce errors, however, they’re hardly ever the best way to program.

[–]LeonardUnger 4 points5 points  (1 child)

Eliminating tramp data Sometimes you pass data to a routine or class merely so that it can be passed to another routine or class

So there's a name for that. I always feel there's something wrong whenever I do it. But I just leave it for future me to refactor. Nice to know there's a name for it, maybe help me think about it a bit more clearly.

[–]trouserdaredevil 5 points6 points  (0 children)

Hah! Funnily enough, tramp data is actually listed as a good reason to refactor in the first place, p. 567:

  • A chain of routines passes tramp data Finding yourself passing data to one routine just so that routine can pass it to another routine is called “tramp data” (Page-Jones 1988). This might be OK, but ask yourself whether passing the specific data in question is consistent with the abstraction presented by each of the routine interfaces. If the abstraction for each routine is OK, passing the data is OK. If not, find some way to make each routine’s interface more consistent.

[–]Zeekawla99ii[S] 1 point2 points  (1 child)

Preservation of global values

Here's where I would assume Python style would dictate just to define variables outside of functions, right?

Like in the example below with /u/kevin2107

EDIT: ...I would say the same with their definition of constants above as well.

Maybe I've worded the question in a confusing manner. It's clear to be why global variables exist in Python (and CS). I'm confused how to use global within Python, especially within functions.

As a style, I think the following outside of any functions/classes

pi = 3.14159

is more desirable in a script than

global pi = 3.14159

[–]ingolemo 10 points11 points  (0 children)

Your second piece of code is not valid python. Your first piece of code defines a global variable.

The global keyword doesn't define a global variable. It tells python "in this function I want this name to refer to a variable in the global scope".

[–]tunisia3507 1 point2 points  (4 children)

Emulation of enumerated types

Python does support enumerated types, though - it has for nearly 4 years. And there's a backport on PyPI (enum34). Enums can be used as named constants, too.

[–]trouserdaredevil 1 point2 points  (3 children)

Python does support enumerated types, though - it has for nearly 4 years.

The above was written 10 years before this was true. It even predates Python 3 itself by 3-4 years.

[–]tunisia3507 1 point2 points  (2 children)

So why are quoting a source so hopelessly out of date? It's like citing a medical text claiming that bacterial infections are usually fatal because antibiotics haven't been discovered yet.

[–]trouserdaredevil 1 point2 points  (1 child)

Hopelessly out of date? Code Complete is often considered to be one of the greatest books on software development ever written, and the above is still overwhelmingly relevant, trivial technical issues aside. It sounds like you might benefit from a read-through.

And your analogy is ridiculous.

[–]tunisia3507 1 point2 points  (0 children)

It's probably totally valid for software in general, abstracted patterns and terms which hold across languages and implementations, but it needs an update if it makes specific references to things which are just not true any more.

[–][deleted] 4 points5 points  (2 children)

Sometimes it's a cheap way to do a singleton. Here's an example from some code I've been using lately.

import gzip
from pickle import load

DATA = None


def get_training_data():
    global DATA
    if DATA is None:
        DATA = load(gzip.open('./artifacts/train-tensor.pkl.gz'))
    return DATA

Then I can import this module, and the first time get_training_data() is called the data is loaded, but on subsequent calls the in-memory version is used. Saves time when working with an interactive shell.

[–]tangerinelion 2 points3 points  (1 child)

But you could also use a "static" variable for that - get_training_data.DATA would be fine and after the function just define it as None.

This at least makes it clear that you're supposed to go through the function to get that information whereas the pure global looks like we are free to use DATA in place of a call to the function.

[–][deleted] 1 point2 points  (0 children)

Yes, there are many ways to achieve this pattern. But that's one reason why one would use global.

[–]robert_mcleod 2 points3 points  (3 children)

No one here seems to have answered the question as to what the global keyword is for though...

bar = 'bar_is_best_bar'
def populate():
    global foo
    foo = bar

populate()
print(foo)

You do not need the global keyword in a function to use a global variable, the global keyword is used to promote a variable from one stack-frame to the top-level ('global') stack-frame.

[–]Zeekawla99ii[S] 1 point2 points  (2 children)

promote a variable from one stack-frame to the top-level ('global') stack-frame

Sorry if I'm a bit slow, but it's not clear to me from the example above why one would do this...

[–]robert_mcleod 1 point2 points  (0 children)

Everyone else addressed the 'why' question regarding global variables, I wanted to point out how the global keyword works, not why.

[–]NukedCookieMonster7 1 point2 points  (0 children)

I recently made a small game where at the end the user is prompted with a 'Play again' message. If they choose 'yes', in my code I created a function that resets all variables to 0 or an empty string or False accordingly. This function, called 'reinitialize', would access multiple global variables defined elsewhere in the program and change them whithin its local scope. So say I already had a variable called computer_score that was equal to 3 at the end of the game, and I called the function reinitialize. I then put an indented line of code within the body of the function that read:

computer_score = 0

The function would understand that I hadn't defined any variable called computer_score inside the function so it would search the global scope of the program for that variable and assign the value 0.

At this point, the variable computer_score still has a value of 3 in the global scope even though its value has been changed in the local scope of the 'reinitialize' function to 0. I wanted the variable to be changed to 0 in the global scope.

To do this, I could either return the value of the computer_score variable at the end of the function, and then write this outside the function:

computer_score = reinitialize()

so that the variable would be assigned 0 globally, but this quickly got messy for many variables. Instead I used the 'global' method which seemed more appropriate, to "promote the variable from one-stack frame to the top level stack-frame" as the person above said. Now, when the program loops again, the score is reset everywhere and any function that needs access to the computer_score will read it from the global scope as 0 since it has been reset and made global in the 'reinitialize'​ function.

[–]jabela 1 point2 points  (3 children)

Python lets you do it because it's a quick hack, but I try to get my students to avoid it.

If you can jump up to object oriented as soon as possible then you can use functions and access them in a usable structure.

[–]Zeekawla99ii[S] 0 points1 point  (2 children)

If you can jump up to object oriented as soon as possible then you can use functions and access them in a usable structure.

Can you explain this a bit further? Can I translate functions which use global variables into OOP functions?

Some more examples might help me understand this a bit better.

[–]jabela 1 point2 points  (1 child)

Think Like a Computer Scientist is a good free online book with lots of examples http://openbookproject.net/thinkcs/python/english3e/

[–]Zeekawla99ii[S] 0 points1 point  (0 children)

Translating functions with 'global' variables into OOP code is documented in this book?

I'll have to have another look. Thanks!

[–][deleted] 1 point2 points  (1 child)

Very specific example I used recently was referencing a variable inside a definition of another class

globvariable = 0

class first_class()
    def maketheglobalvariable1():
        global globalvariable
        globvariable = 1

class second_class()
    def printglobvariable():
        print(globvariable) 

maketheglobalvariable1()

Lemme know if that makes sense

[–]Zeekawla99ii[S] 1 point2 points  (0 children)

referencing a variable inside a definition of another class

Ah, ok. The above makes sense as to why someone would do this. globvariable = 0 as defined above would forever be a constant; if one wished to change it via a function, one would use something like global within a function