(python) Should my variable be local or global? (best practice) - python

When declaring a constant that is only used one function, should that variable be declared locally since it is only used by that function, or globally since it is never going to change?
IE which is better:
CONSTANT = (1, 3, 5, 8)
##SOME OTHER CODE HERE
def function1(arg):
if arg in CONSTANT:
do something
or:
def function1(arg):
CONSTANT = (1, 3, 5, 8)
if arg in CONSTANT:
do something
I know there isn't a lot of difference between these two, but I just wanted to know which of the two practices is preferred since I'm just starting out and want to form good habits.

I would keep it local. You can always just move it global in the future if you need to, or share it between functions by making them methods in a class and turning the constant into a class variable. In these situations, generally speaking, the more local, the better, and best is to hide implementation information within your functions, as in your second example. It doesn't make a huge difference here, but as your projects get bigger, maintainability and modularity will be sustained.

I would put them global because:
Your variables are constants
In Python, global scope is encapsulated in the module namespace, meaning that your variable is in fact only global inside the module.
If you call your function a lot of times, and put your constants local to it, it would reallocate them each time your call the function.
Then you can share your constants between different functions.
However, if you move to Object Oriented Programming, then I would put the constants as class variables.

I would say that what is best depends on the situation.
If execution time is not an issue, then having the constant be loaded into a new variable each time does not waste much time. This has the obvious advantage of showing explicitly where in your code the constant is used.
Otherwise, a global is fine, but I would only do this for optimization purposes. If I think of it, optimization is the only reason why I ever asked myself the same question as you.
There might be other good reasons to use a global:
if the user of your program often needs to change its value in the code and you don't want to parse program arguments,
if other programs need to access it,
etc.
In conclusion, I would say: do what you feel is best, but try to encapsulate things as much as reasonably possible where they belong (locals are to be preferred to globals).

Related

Returning a variable vs making that variable global [duplicate]

I'm trying to find out why the use of global is considered to be bad practice in python (and in programming in general). Can somebody explain? Links with more info would also be appreciated.
This has nothing to do with Python; global variables are bad in any programming language.
However, global constants are not conceptually the same as global variables; global constants are perfectly harmless. In Python the distinction between the two is purely by convention: CONSTANTS_ARE_CAPITALIZED and globals_are_not.
The reason global variables are bad is that they enable functions to have hidden (non-obvious, surprising, hard to detect, hard to diagnose) side effects, leading to an increase in complexity, potentially leading to Spaghetti code.
However, sane use of global state is acceptable (as is local state and mutability) even in functional programming, either for algorithm optimization, reduced complexity, caching and memoization, or the practicality of porting structures originating in a predominantly imperative codebase.
All in all, your question can be answered in many ways, so your best bet is to just google "why are global variables bad". Some examples:
Global Variables Are Bad - Wiki Wiki Web
Why is Global State so Evil? - Software Engineering Stack Exchange
Are global variables bad?
If you want to go deeper and find out why side effects are all about, and many other enlightening things, you should learn Functional Programming:
Side effect (computer science) - Wikipedia
Why are side-effects considered evil in functional programming? - Software Engineering Stack Exchange
Functional programming - Wikipedia
Yes, in theory, globals (and "state" in general) are evil. In practice, if you look into your python's packages directory you'll find that most modules there start with a bunch of global declarations. Obviously, people have no problem with them.
Specifically to python, globals' visibility is limited to a module, therefore there are no "true" globals that affect the whole program - that makes them a way less harmful. Another point: there are no const, so when you need a constant you have to use a global.
In my practice, if I happen to modify a global in a function, I always declare it with global, even if there technically no need for that, as in:
cache = {}
def foo(args):
global cache
cache[args] = ...
This makes globals' manipulations easier to track down.
A personal opinion on the topic is that having global variables being used in a function logic means that some other code can alter the logic and the expected output of that function which will make debugging very hard (especially in big projects) and will make testing harder as well.
Furthermore, if you consider other people reading your code (open-source community, colleagues etc) they will have a hard time trying to understand where the global variable is being set, where has been changed and what to expect from this global variable as opposed to an isolated function that its functionality can be determined by reading the function definition itself.
(Probably) Violating Pure Function definition
I believe that a clean and (nearly) bug-free code should have functions that are as pure as possible (see pure functions). A pure function is the one that has the following conditions:
The function always evaluates the same result value given the same argument value(s). The function result value cannot depend on any hidden information or state that may change while program execution proceeds or between different executions of the program, nor can it depend on any external input from I/O devices (usually—see below).
Evaluation of the result does not cause any semantically observable side effect or output, such as mutation of mutable objects or output to I/O devices.
Having global variables is violating at least one of the above if not both as an external code can probably cause unexpected results.
Another clear definition of pure functions: "Pure function is a function that takes all of its inputs as explicit arguments and produces all of its outputs as explicit results." [1]. Having global variables violates the idea of pure functions since an input and maybe one of the outputs (the global variable) is not explicitly being given or returned.
(Probably) Violating Unit testing F.I.R.S.T principle
Further on that, if you consider unit-testing and the F.I.R.S.T principle (Fast tests, Independent tests, Repeatable, Self-Validating and Timely) will probably violate the Independent tests principle (which means that tests don't depend on each other).
Having a global variable (not always) but in most of the cases (at least of what I have seen so far) is to prepare and pass results to other functions. This violates this principle as well. If the global variable has been used in that way (i.e the global variable used in function X has to be set in a function Y first) it means that to unit test function X you have to run test/run function Y first.
Globals as constants
On the other hand and as other people have already mentioned, if the global variable is used as a "constant" variable can be slightly better since the language does not support constants. However, I always prefer working with classes and having the "constants" as a class member and not use a global variable at all. If you have a code that two different classes require to share a global variable then you probably need to refactor your solution and make your classes independent.
I don't believe that globals shouldn't be used. But if they are used the authors should consider some principles (the ones mentioned above perhaps and other software engineering principles and good practices) for a cleaner and nearly bug-free code.
They are essential, the screen being a good example. However, in a multithreaded environment or with many developers involved, in practice often the question arises: who did (erraneously) set or clear it? Depending on the architecture, analysis can be costly and be required often. While reading the global var can be ok, writing to it must be controlled, for example by a single thread or threadsafe class. Hence, global vars arise the fear of high development costs possible by the consequences for which themselves are considered evil. Therefore in general, it's good practice to keep the number of global vars low.

Use function globally or locally?

In Python I have several functions that use the location of the user's directory as a way of determining where to put files.
I currently use a "global" variable for all the functions to use.
home = os.path.expanduser('~')
I'm wondering if this is good coding practice.
The upside of this is that the program only needs to execute this code only once.
I could also have each function call os.path.expanduser each time it is called.
Which is the more pythonic one? Or is there a pythonicer way?
There's nothing wrong with globals. It's a consequence of how you designed your program. You wrote a few functions and put them in a module, and globals are a way to share data between individual functions in a module.
For example, had you decided to go with an object oriented design, then one could argue that globals should be avoided and shared data should be encapsulated. But you didn't do that, so globals are fine.
It is ok to use global constants. At the end all the first-level function and classes defined in the same module are also "global" in this sense.
Using gobal variables becomes messy when different components of the system start re-assigning their values or mutate their content. In this case it's an obvious antipattern and can lead to a debugging hell.

restrict scopes of local variables in python

When there is a long function, how to limit the scope of variables within only a section of the function? I know in many languages one can do this with {}. How to do this in python?
I am aware that a separate function for just that section will encapsulate variables to its local namespace. But for a long, linear function, many people argue that it does not make sense to write many functions (and thus names) that are only called once.
Generally speaking, you can't. Python only creates scopes for modules (files, generally), classes, and functions; variables can have a more limited lifetime only in a few special cases, like the target_list in a list comprehension in Python 3. There's no block-level scope like in Perl.
So, your possible workarounds are:
Create single-use functions or classes. The function would have to be called, whereas the class would never have to be named again after its definition, because class definitions are executed immediately.
del variables when you're done with them.
Fun fact: coming to terms with this limitation of Python is what finally got us to get rid of let in Hy, because there's no way to make it work as one would expect. Update 5 years later: yet another version of let is implemented, and the way it works is by implementing our own entire system for tracking the scopes of variables, and enforcing it by issuing compile-time errors and adding nonlocal and global when needed. I guess there are no shortcuts here.

Quick inquiry about global variables in python

Do you have to write, for example, global var right before defining what var is or can you just kind of list all the global variables that you are going to use somewhere high up and then define them later on?
Generally accepted "best practice" - the quotes because it is often considered that global variables are not a good idea - is to have all your globals initialised near the top of the file, usually just after the imports, then to use the global statement in functions that change them.
The convention is to have all your globals ALL_UPPERCASE which makes a lot of sense as it does make it easier to spot when you are inadvertently masking them by assigning a local variable of the same name, (without the global statement).
Note that globals that are not intended to be accessed outside of the file should start with an underscore so that they are not imported by default.
It is also a reasonably good idea to always have any global statement(s) at the start of any functions that write to them - just after the docstring - for a similar reason.
To summarise - if you have to have them you can put them anywhere but you probably shouldn't for reasons of readability and maintainability.
In Python, you don't need to declare variables before using them. This includes globals.
If you are interested in sort of "reserving" the name early, you might want to assign them to None. Python is a highly dynamic language though, and your "reservations" could easily be clobbered by other code.

Should I use class as a container for global variable

I were making a simple game in pygame and I realized I need a bunch of markers, counts and all sorts of global staff. So I decided to define a class and use it like this:
class Staff():
def __init__(self):
self.modes={'menu':True,'spawning':False,'sprite_change':False}
self.timer=pygame.time.Clock()
self.tick_count=0
and in my game loop I just give one variable to all my functions:
def main_loop():
staff=Staff()
while not done:
update_positions(staff)
clear_background(staff)
draw_sprites(staff)
I know this method is working and quite convenient (for me), but I wonder how's this going to affect speed of my game, may be I'm doing something horrible?
Many thanks for answering.
Please, do yourself a favour and rethink your design.
Firstly you might think that is easier for you to use global variables. You can pass around values and you can access them from every function without passing it to them using parameters. But when it comes to debugging or finding errors or just looking into your code after a while global variables are turning into a nightmare. Because you easily forget where these variables will take impact on other functions or classes. So, do yourself a favour and rethink your design.
A good place for your "global" variables could be for example the main class or function. Where it all begins. I guess there is a loop where some things will be repeated permanently. from there you can pass it to the specific classes or functions. I don't know your architecture, but it is seldom useful to have global variables at all.
While I don't know python at all, globals in general are a bad idea. I suggest the Singleton pattern. While it's not the greatest idea either, it's certainly better than globals:
Python and the Singleton Pattern
Other than that, your approach seems fine to me.

Categories