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.
Related
I have to share around 10 variables between functions, which are contained in the same .py file. The variables will be modified in almost every function. I know that global variables are evil, but unfortunately for now I have to keep few of them as global, while the rest I have been able to change the implementation and to pass them as an argument.
One way of doing this would be using the "global" keyword, but I have run into another option, that would be placing them in an empty module, and importing the module every time.
I am just a beginner in python, what would be the best way to do this?
EDIT: This is a rewriting of a code based almost completely on global variables. Almost all the functions are now in a class, the variables are used with self.name_var. However, since we are using multiprocess with Array, few variables have to remain globals.
Thanks,
Andrea
Just do not do it, put all the functions, if they are related, in a class and make the variables accessible with self. Using a different module is worst.
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.
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.
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).
I'm writing an application in Python, and I've got a number of universal variables (such as the reference to the main window, the user settings, and the list of active items in the UI) which have to be accessible from all parts of the program1. I only just realized I've named the module globals.py and I'm importing the object which contains those variables with a from globals import globals statement at the top of my files.
Obviously, this works, but I'm a little leery about naming my global object the same as the Python builtin. Unfortunately, I can't think of a much better naming convention for it. global and all are also Python builtins, universal seems imprecise, state isn't really the right idea. I'm leaning towards static or env, although both have a specific meaning in computer terms which suggests a different concept.
So, what (in Python) would you call the module which contains variables global to all your other modules?
1 I realize I could pass these (or the single object containing them) as a variable into every other function I call. This ends up being infeasible, not just because it makes the startup code and function signatures really ugly.
I would try to avoid such a global container module altogether, and instead put these variables into their own modules, which can then be imported from all parts of the system.
For example, the main window would probably go into a variable in main.py. User settings could go into usersettings.py which would provide functions to view and change the settings.
If another part of the system needs to access the user settings, that's a simple matter of:
from usersettings import get_setting, set_setting
...
# Do stuff with settings
A similar approach could probably be used for other stuff that needs to be globally accessible. This leads to clearer separation of concerns and more testable code, since you can test modules in isolation without depending on the globals module all the time.
I'd call it env. There's little risk that someone will confuse it with os.environ (especially if you organize your code so that you can call it myapp.environ).
I'd also make everything exposed by myapp.environ a property of a class, so that I can put breakpoints in the setter when the day comes that I need to.
`config` or `settings`
top? top_level?
from globals import Globals
This will fix the conflict and also follows PEP 8 recommendations.
Also, in other cases like this, Roget's Thesaurus is your friend. I always keep a copy nearby.
global is a keyword, not a built-in. 'globals' is not a keyword, but is a built-in function. It can be assigned to, but is bad practice. Code checkers like pylint and pychecker can catch these accidental assignments. How about config?