Accessing a Python global variable across files - python

I have three python files in a project:
'''lib.py
library file that first defines and also accesses a boolean flag'''
vflag = False
...
def lib_method()
global vflag
if not vflag:
do_something_here
'''app.py
main application that sets the boolean flag defined in lib.py'''
import lib
lib.vflag = method_that_sets_or_resets_vflag()
'''processor.py
does some processing and needs to access the bool flag'''
from lib import *
...
def processor_method()
global vflag
...
if vflag:
do_something_here
I am able to set/ reset the flag at app.py, but processor method is not able to get the correct value for this boolean variable.
It only gets whatever is set at the beginning of lib.py(not what is set by app.py). The requirement is to access the value set at runtime by app.py, NOT the value to which it was initialized by lib.py
I am importing the lib file in different ways at app.py and processor.py. Does that make a difference ?
It may be a fundamental mistake, so I will appreciate if some one can point me to a specific knowledge base.
Also, it is messing with my understanding of global variables. If I define a variable to be 'global', does that mean the variable stays to be a global variable in all the files that import this variable(or the file containing the variable definition)

When you use from lib import * in processor.py, you are getting a snapshot of what's going on in lib.py at that moment. The lib.py file is executed, and all of the functions and variables are copied and stored in the namespace of processor.py. You are not storing references to the original vflag from lib.py - you're storing an entirely new copy. So if you change vflag in lib.py, then processor.py will never know about it.
The better practice is to always use import lib, and just access the variable with lib.vflag. You don't even need to use the global keyword.

The best practice for this situation would be to pass vflag into the functions you need as a parameter and to not use global variables.

Related

Python when are imported files evaluated?

I hope the question phrasing is meaningful. What I am wanting to do is change a flat variable's value in a file, and have the files which have imported that file see the updated value. It appears that I can do this. For example:
#settings.py
VARIABLE = 1
def change_variable():
global VARIABLE
VARIABLE = 2
and
#main.py
import settings
print(settings.VARIABLE)
settings.change_variable()
print(settings.VARIABLE)
which outputs:
1
2
As desired. Although I was a little surprised since I thought maybe the value of settings.VARIABLE would be fixed after settings was imported. I would like to know whether I can rely on this behaviour. My question is thus also, when in general will the values from an imported file be "updated" or "re-evaluated" from the perspective of the importing file? How does it work behind the scenes?
I could of course just make a class. But I don't like the idea of settings, or any config, being an object. I prefer it flat. But I want the option to change the settings after import based on user cli input.
Once the file settings.py is imported, python is done looking at the file. It now has a module loaded in memory, and if it is imported somewhere else, that module will be loaded there. The file is never looked at again after the first import.
Your function changed the value of VARIABLE in that module. You can depend on it being your new value unless you change it again.

Python 3: Importing file containing variables to be used as constants

I want to use a config.py file in which I will be declaring some constants to be used in mainFile.py.
I'll be defining these "constant variables" using Capital letters.
I want to make it easier to configure the mainFile.py parameters by defining the constants only in config.py.
Ofcourse, in mainFile.py, the values of these constant are by no means altered.
So, my question is :
If in mainFile.py I use "From config.py import *", are the "constant variables" defined in config.py used as global variables in mainFile.py?
E.g. inn functions defined within mainFile.py, do I need to re-define these variables as global in order to use them?
You can simply write import config, and all of your constants will be accessible to your code in mainFile.py.
There are two options:
As already pointed out by #Josh, in config.py you name your variables, such as m=10, t=52, and so on. Then on mainFile.py you import config and access your variables as config.m that will result in 10. Like:
y = config.m
y = 10
The second option is a bit longer. You create a function such as
def m():
m = 10
return m
Then on mainFile.py you import config and access the variable as config.m() that will yield 10. Like
z = config.m()
z = 10
global is required if you are modifying the imported variable in some case and you need to reflect that value on all other places where the variable is being accessed.
since you are just reading the value of the imported variable here, global is no required. also inside functions if any variable is read first it searches on local scope then on global scope. So no global required inside function for reading purpose.

How do you declare a global constant in Python?

I have some heavy calculations that I want to do when my program starts, and then I want to save the result (a big bumpy matrix) in memory so that I can use it again and again. My program contains multiple files and classes, and I would like to be able to access this variable from anywhere, and if possible define it as constant.
How do you define a global constant in Python?
You can just declare a variable on the module level and use it in the module as a global variable. An you can also import it to other modules.
#mymodule.py
GLOBAL_VAR = 'Magic String' #or matrix...
def myfunc():
print(GLOBAL_VAR)
Or in other modules:
from mymodule import GLOBAL_VAR
I do not think the marked as good answer solves the op question. The global keyword in Python is used to modify a global variable in a local context (as explained here). This means that if the op modifies SOME_CONSTANT within myfunc the change will affect also outside the function scope (globally).
Not using the global keyword at the begining of myfunc is closer to the sense of global constant than the one suggested. Despite there are no means to render a value constant or immutable in Python.
There is no way to declare a constant in Python. You can just use
SOME_CONSTANT = [...]
If the file name where it is declared is file1.py, then you can access to it from other files in the following way:
import file1
print file1.SOME_CONSTANT
Assuming that both files are in the same directory.
I am not sure what you mean by 'global constant'; because there are no constants in Python (there is no "data protection", all variables are accessible).
You can implement a singleton pattern, but you will have to regenerate this at runtime each time.
Your other option will be to store the results in an external store (like say, redis) which is accessible from all processes.
Depending on how big your data set is, storing it externally in a fast K/V like redis might offer a performance boost as well.
You would still have to transform and load it though, since redis would not know what a numpy array is (although it has many complex types that you can exploit).

How can I figure out in my module if the main program uses a specific variable?

I know this does not sound Pythonic, but bear with me for a second.
I am writing a module that depends on some external closed-source module. That module needs to get instantiated to be used (using module.create()).
My module attempts to figure out if my user already loaded that module (easy to do), but then needs to figure out if the module was instantiated. I understand that checking out the type() of each variable can tell me this, but I am not sure how I can get the names of variables defined by the main program. The reason for this is that when one instantiates the model, they also set a bunch of parameters that I do not want to overwrite for any reason.
My attempts so far involved using sys._getframe().f_globals and iterating through the elements, but in my testing it doesn't work. If I instantiate the module as modInst and then call the function in my module, it fails to show the modInst variable. Is there another solution to this? Sample code provided below.
import sys
if moduleName not in sys.modules:
import moduleName
modInst = moduleName.create()
else:
globalVars = sys._getframe().f_globals
for key, value in globalVars:
if value == "Module Name Instance":
return key
return moduleName.create()
EDIT: Sample code included.
Looks like your code assumes that the .create() function was called, if at all, by the immediate/direct caller of your function (which you show only partially, making it pretty hard to be sure about what's going on) and the results placed in a global variable (of the module where the caller of your function resides). It all seems pretty fragile. Doesn't that third-party module have some global variables of its own that are affected by whether the module's create has been called or not? I imagine it would -- where else is it keeping the state-changes resulting from executing the create -- and I would explore that.
To address a specific issue you raise,
I am not sure how I can get the names
of variables defined by the main
program
that's easy -- the main program is found, as a module, in sys.modules['__main__'], so just use vars(sys.modules['__main__']) to get the global dictionary of the main program (the variable names are the keys in that dictionary, along of course with names of functions, classes, etc -- the module, like any other module, has exactly one top-level/global namespace, not one for variables, a separate one for functions, etc).
Suppose the external closed-sourced module is called extmod.
Create my_extmod.py:
import extmod
INSTANTIATED=False
def create(*args,**kw):
global INSTANTIATED
INSTANTIATED=True
return extmod.create(*args,**kw)
Then require your users to import my_extmod instead of extmod directly.
To test if the create function has been called, just check the value of extmod.INSTANTIATED.
Edit: If you open up an IPython session and type import extmod, then type
extmod.[TAB], then you'll see all the top-level variables in the extmod namespace. This might help you find some parameter that changes when extmod.create is called.
Barring that, and barring the possibility of training users to import my_extmod, then perhaps you could use something like the function below. find_extmod_instance searches through all modules in sys.modules.
def find_instance(cls):
for modname in sys.modules:
module=sys.modules[modname]
for value in vars(module).values():
if isinstance(value,cls):
return value
x=find_instance(extmod.ExtmodClass) or extmod.create()

How to make a cross-module variable?

The __debug__ variable is handy in part because it affects every module. If I want to create another variable that works the same way, how would I do it?
The variable (let's be original and call it 'foo') doesn't have to be truly global, in the sense that if I change foo in one module, it is updated in others. I'd be fine if I could set foo before importing other modules and then they would see the same value for it.
If you need a global cross-module variable maybe just simple global module-level variable will suffice.
a.py:
var = 1
b.py:
import a
print a.var
import c
print a.var
c.py:
import a
a.var = 2
Test:
$ python b.py
# -> 1 2
Real-world example: Django's global_settings.py (though in Django apps settings are used by importing the object django.conf.settings).
I don't endorse this solution in any way, shape or form. But if you add a variable to the __builtin__ module, it will be accessible as if a global from any other module that includes __builtin__ -- which is all of them, by default.
a.py contains
print foo
b.py contains
import __builtin__
__builtin__.foo = 1
import a
The result is that "1" is printed.
Edit: The __builtin__ module is available as the local symbol __builtins__ -- that's the reason for the discrepancy between two of these answers. Also note that __builtin__ has been renamed to builtins in python3.
I believe that there are plenty of circumstances in which it does make sense and it simplifies programming to have some globals that are known across several (tightly coupled) modules. In this spirit, I would like to elaborate a bit on the idea of having a module of globals which is imported by those modules which need to reference them.
When there is only one such module, I name it "g". In it, I assign default values for every variable I intend to treat as global. In each module that uses any of them, I do not use "from g import var", as this only results in a local variable which is initialized from g only at the time of the import. I make most references in the form g.var, and the "g." serves as a constant reminder that I am dealing with a variable that is potentially accessible to other modules.
If the value of such a global variable is to be used frequently in some function in a module, then that function can make a local copy: var = g.var. However, it is important to realize that assignments to var are local, and global g.var cannot be updated without referencing g.var explicitly in an assignment.
Note that you can also have multiple such globals modules shared by different subsets of your modules to keep things a little more tightly controlled. The reason I use short names for my globals modules is to avoid cluttering up the code too much with occurrences of them. With only a little experience, they become mnemonic enough with only 1 or 2 characters.
It is still possible to make an assignment to, say, g.x when x was not already defined in g, and a different module can then access g.x. However, even though the interpreter permits it, this approach is not so transparent, and I do avoid it. There is still the possibility of accidentally creating a new variable in g as a result of a typo in the variable name for an assignment. Sometimes an examination of dir(g) is useful to discover any surprise names that may have arisen by such accident.
Define a module ( call it "globalbaz" ) and have the variables defined inside it. All the modules using this "pseudoglobal" should import the "globalbaz" module, and refer to it using "globalbaz.var_name"
This works regardless of the place of the change, you can change the variable before or after the import. The imported module will use the latest value. (I tested this in a toy example)
For clarification, globalbaz.py looks just like this:
var_name = "my_useful_string"
You can pass the globals of one module to onother:
In Module A:
import module_b
my_var=2
module_b.do_something_with_my_globals(globals())
print my_var
In Module B:
def do_something_with_my_globals(glob): # glob is simply a dict.
glob["my_var"]=3
Global variables are usually a bad idea, but you can do this by assigning to __builtins__:
__builtins__.foo = 'something'
print foo
Also, modules themselves are variables that you can access from any module. So if you define a module called my_globals.py:
# my_globals.py
foo = 'something'
Then you can use that from anywhere as well:
import my_globals
print my_globals.foo
Using modules rather than modifying __builtins__ is generally a cleaner way to do globals of this sort.
You can already do this with module-level variables. Modules are the same no matter what module they're being imported from. So you can make the variable a module-level variable in whatever module it makes sense to put it in, and access it or assign to it from other modules. It would be better to call a function to set the variable's value, or to make it a property of some singleton object. That way if you end up needing to run some code when the variable's changed, you can do so without breaking your module's external interface.
It's not usually a great way to do things — using globals seldom is — but I think this is the cleanest way to do it.
I wanted to post an answer that there is a case where the variable won't be found.
Cyclical imports may break the module behavior.
For example:
first.py
import second
var = 1
second.py
import first
print(first.var) # will throw an error because the order of execution happens before var gets declared.
main.py
import first
On this is example it should be obvious, but in a large code-base, this can be really confusing.
I wondered if it would be possible to avoid some of the disadvantages of using global variables (see e.g. http://wiki.c2.com/?GlobalVariablesAreBad) by using a class namespace rather than a global/module namespace to pass values of variables. The following code indicates that the two methods are essentially identical. There is a slight advantage in using class namespaces as explained below.
The following code fragments also show that attributes or variables may be dynamically created and deleted in both global/module namespaces and class namespaces.
wall.py
# Note no definition of global variables
class router:
""" Empty class """
I call this module 'wall' since it is used to bounce variables off of. It will act as a space to temporarily define global variables and class-wide attributes of the empty class 'router'.
source.py
import wall
def sourcefn():
msg = 'Hello world!'
wall.msg = msg
wall.router.msg = msg
This module imports wall and defines a single function sourcefn which defines a message and emits it by two different mechanisms, one via globals and one via the router function. Note that the variables wall.msg and wall.router.message are defined here for the first time in their respective namespaces.
dest.py
import wall
def destfn():
if hasattr(wall, 'msg'):
print 'global: ' + wall.msg
del wall.msg
else:
print 'global: ' + 'no message'
if hasattr(wall.router, 'msg'):
print 'router: ' + wall.router.msg
del wall.router.msg
else:
print 'router: ' + 'no message'
This module defines a function destfn which uses the two different mechanisms to receive the messages emitted by source. It allows for the possibility that the variable 'msg' may not exist. destfn also deletes the variables once they have been displayed.
main.py
import source, dest
source.sourcefn()
dest.destfn() # variables deleted after this call
dest.destfn()
This module calls the previously defined functions in sequence. After the first call to dest.destfn the variables wall.msg and wall.router.msg no longer exist.
The output from the program is:
global: Hello world!
router: Hello world!
global: no message
router: no message
The above code fragments show that the module/global and the class/class variable mechanisms are essentially identical.
If a lot of variables are to be shared, namespace pollution can be managed either by using several wall-type modules, e.g. wall1, wall2 etc. or by defining several router-type classes in a single file. The latter is slightly tidier, so perhaps represents a marginal advantage for use of the class-variable mechanism.
This sounds like modifying the __builtin__ name space. To do it:
import __builtin__
__builtin__.foo = 'some-value'
Do not use the __builtins__ directly (notice the extra "s") - apparently this can be a dictionary or a module. Thanks to ΤΖΩΤΖΙΟΥ for pointing this out, more can be found here.
Now foo is available for use everywhere.
I don't recommend doing this generally, but the use of this is up to the programmer.
Assigning to it must be done as above, just setting foo = 'some-other-value' will only set it in the current namespace.
I use this for a couple built-in primitive functions that I felt were really missing. One example is a find function that has the same usage semantics as filter, map, reduce.
def builtin_find(f, x, d=None):
for i in x:
if f(i):
return i
return d
import __builtin__
__builtin__.find = builtin_find
Once this is run (for instance, by importing near your entry point) all your modules can use find() as though, obviously, it was built in.
find(lambda i: i < 0, [1, 3, 0, -5, -10]) # Yields -5, the first negative.
Note: You can do this, of course, with filter and another line to test for zero length, or with reduce in one sort of weird line, but I always felt it was weird.
I could achieve cross-module modifiable (or mutable) variables by using a dictionary:
# in myapp.__init__
Timeouts = {} # cross-modules global mutable variables for testing purpose
Timeouts['WAIT_APP_UP_IN_SECONDS'] = 60
# in myapp.mod1
from myapp import Timeouts
def wait_app_up(project_name, port):
# wait for app until Timeouts['WAIT_APP_UP_IN_SECONDS']
# ...
# in myapp.test.test_mod1
from myapp import Timeouts
def test_wait_app_up_fail(self):
timeout_bak = Timeouts['WAIT_APP_UP_IN_SECONDS']
Timeouts['WAIT_APP_UP_IN_SECONDS'] = 3
with self.assertRaises(hlp.TimeoutException) as cm:
wait_app_up(PROJECT_NAME, PROJECT_PORT)
self.assertEqual("Timeout while waiting for App to start", str(cm.exception))
Timeouts['WAIT_JENKINS_UP_TIMEOUT_IN_SECONDS'] = timeout_bak
When launching test_wait_app_up_fail, the actual timeout duration is 3 seconds.

Categories

Resources