Access a global object by its name than module - python-3.x

I have a module where I read a config file and store it into a variable.
Eg: myconfig.py looks like:
cfg = {}
def load(file_path):
global cfg
cfg = cfg_file_todict(file_path)
This load() function is called in a main() function (i.e. at beginning of the process).
I observe that the cfg variable cannot be imported directly, but it has to accessed via the module name.
I.e., say I have a file a.py where:
import myconfig
print(myconfig.cfg) # This prints the config properly across modules
But if I have:
from myconfig import cfg
print(cfg) # This prints None
Is there some way where even the second type of import can still retain the original variable? Or is there some other alternative to this?

#You can use a global variable within other functions by declaring it as global within each function that assigns a value to it:
globvar = 0
def set_globvar_to_one():
global globvar # Needed to modify global copy of globvar
globvar = 1
def print_globvar():
print(globvar) # No need for global declaration to read value of globvar
set_globvar_to_one()
print_globvar() # Prints 1

Related

How to get the var declared in test1.py into test2.py, perform some operation on var in test2.py and get the updated value of var in test1.py?

Assigning value to global var
For Example:
test1.py:
global var
var= 0
def func1():
print("The updated value of var is :"+var)
#after the updated value perform some operation on var
var=var*2
def func3():
global var
print("The final value of var is :"+var)
test2.py:
from test1 import *
def func2():
global var
print("The initial value of var is :"+var)
var = 2+3
func1()
I intend to have the the following values of var:
the initial val of var in func1 of test2.py: 0
The updated value of var in func2 of test1.py: 5
The final value of var in func3 of test1.py: 10
The first thing i notice in your code is the
global var
on the first line. In python this is not needed. Any variable declared in the global scope is automatically global. You'd only need the global keyword inside of a function wanting to modify a global variable.
Another thing which you need to know about python is that a global var is only global for that specific file. It does not transfer over to other modules.
So now: how do you do what you want to do.
The only real way to keep this kind of state across modules i think, is to use some sort of container. Ill use a class but i'm sure things like a dict or a list would work fine. This way you also don't mess up the global scope as much, you can do this for multiple variables in one container, and you don't need the global keywords. This is the case because by importing test1 from test2, you would set var to 0 again as the whole test1 module is executed again. By is resolved by putting this shared container in a third module imported from both test1 and test2. I called this module "shared". The code would look like this:
test1.py:
from test2 import func2
from shared import SharedContainer
def func1():
print("The updated value of var is: {}".format(SharedContainer.var))
# after the updated value perform some operation on var
SharedContainer.var = SharedContainer.var*2
def func3():
print("The final value of var is: {}".format(SharedContainer.var))
if __name__ == "__main__":
func2()
func3()
test2.py
from shared import SharedContainer
def func2():
from test1 import func1
print("The initial value of var is: {}".format(SharedContainer.var))
SharedContainer.var = 2+3
func1()
shared.py
class SharedContainer:
var = 0
Hope it helps :)

How to import variable values from a file that is running?

I am running a python file, say file1, and in that, I am importing another python file, say file2, and calling one of its functions. Now, the file2 needs the value of a variable which is defined in file 1. Also, before importing file2 in file1, the value of the variable was changed during the run-time. How do I make the file file2, access the current value of the variable from file 1?
The content of file1 is:
variable = None
if __name__ == '__main__':
variable = 123
from file2 import func1
func1()
The content of file2 is:
from file1 import variable as var
def func1():
print(var)
When I run the file1, I want the function func1 in file2 to print 123. But it prints None. One way I can tackle this is by saving the content of the variable in some ordinary file when it is modified, and then retrieving it when needed. But the application in which I am using this code, the size of the variable is massive, like around 300 MB. So, I believe it won't be efficient enough to write the content of the variable in a text file, every time it is modified. How do I do this? (Any suggestions are welcome)
The main script is run with the name __main__, not by its module name. This is also how the if __name__ == '__main__' check works. Importing it by its regular name creates a separate module with the regular content.
If you want to access its attributes, import it as __main__:
from __main__ import variable as var
def func1():
print(var)
Note that importing __main__ is fragile. On top of duplicating the module, you may end up importing a different module if your program structure changes. If you want to exchange global data, use well-defined module names:
# constants.py
variable = None
# file1.py
if __name__ == '__main__':
import constants
constants.variable = 123
from file2 import func1
func1()
# file2.py
from constants import variable as var
def func1():
print(var)
Mandatory disclaimer: Ideally, functions do not rely on global variables. Use parameters for passing variables into functions:
# constants.py
variable = None
# file1.py
if __name__ == '__main__':
from file2 import func1
func1(123)
# file2.py
from constants import variable
def func1(var=variable):
print(var)

Set a variable from a class within a different file

I have 2 files:
fileA.py
and
fileB.py
I am trying to set (change) a variable from fileA from a function within fileB. The variable I'm trying to change is inside of a class (I believe the variable is a Class variable). I tried importing fileA inside of fileB but got errors.
# fileA:
...
class SomeDialog(QDialog):
my_var = 0
...
# fileB:
...
from fileA import SomeDialog as sd
def my_func():
sd.my_var = 5
...
Any help?
According to the error you got, you probably have circular import somewhere. It is not related to what you are trying to do with your classes.
See ImportError: Cannot import name X for more details
If that's the case, the only way to solve it is to change your file structures.
Your class should look like this:
class SomeDialog(QDialog):
def __init__(self):
self.my_var = 0
Then you can access the my_var like this:
SomeDialog.my_var
Class variables are defined within a class but outside any of the class's methods. Class variables are not used. class variables have the same value across all class instances
A.py
from B import SomeDialog as sd
def my_func():
print sd.my_var
sd.my_var = 5
return sd
_my_func = my_func()
print _my_func.my_var
B.py
class SomeDialog(object):
my_var = 0
#output
0
5

NameError when running in `main` module

I am attempting to grab all the .md files recursively within files.To complish it,I define a recursive function which run in a main module.
The code:
import os
def walk(dirname):
for name in os.listdir(dirname):
path = os.path.join(dirname, name)
if os.path.isfile(path):
if '.md' in path:
path_list.append(path)
else:
walk(path)
return path_list
def main():
dir = '/Users/Documents/Diary'
path_list = []
path = walk(dir)
if __name__ == '__main__':
main()
When running, it reports:
NameError: name 'path_list' is not defined
However, if running without of main(), it works:
In [80]: path_list = []
...: def walk(dirname):
...: for name in os.listdir(dirname):
...: path = os.path.join(dirname, name)
...: if os.path.isfile(path):
...: if '.md' in path:
...: path_list.append(path)
...: else:
...: walk(path)
...: return path_list
output:
dir = '/Users/Documents/Diary'
walk(dir)
Out[81]:
['/Users/Documents/Diary/py4.1.If_statements.md',
'/Users/Documents/Diary/pyName_and_object:.md',
...]
I have no idea what's the bug.
Your second option declares path_list as a global variable, so it is known in all functions.
You could also declare it in the walk() function, the only place where it is needed. But, as commented, since that function is called recursively, that would reset the list every time, instead of aggregating the results.
See more at "Notes on Python variable scope".
Global variables are accessible inside and outside of functions.
Local variables are only accessible inside the function.
If I set a variable in a function with the same name as a global variable, I am actually creating a new local variable.
The problem here is that of scope of object.
When you make a main() function, you are declaring path_list in the local scope of main(). Hence it is not available to walk() function.
You have to pass path_list as an argument to walk or declare it globally as you did latter to make it available. As of current, path_list is out of scope of walk().
You need to declare path_list in the walk function, as it is the function that is operating on it. You get an error because you don't have any path_list pre-declared in that function.
Moreover, you don't need to define any path_list in the main function because it does not operate on it an doesn't need it.
When you declare it globally, it is available to all the functions, even the walk function. It uses that global variable and you don't get any error.

Using the globals argument of timeit.timeit

I am attempting to run timeit.timeit in the following class:
from contextlib import suppress
from pathlib import Path
import subprocess
from timeit import timeit
class BackupVolume():
'''
Backup a file system on a volume using tar
'''
targetFile = "bd.tar.gz"
srcPath = Path("/BulkData")
excludes = ["--exclude=VirtualBox VMs/*", # Exclude all the VM stuff
"--exclude=*.tar*"] # Exclude this tar file
#classmethod
def backupData(cls, targetPath="~"): # pylint: disable=invalid-name
'''
Runs tar to backup the data in /BulkData so we can reorganize that
volume. Deletes any old copy of the backup repository.
Parameters:
:param str targetPath: Where the backup should be created.
'''
# pylint: disable=invalid-name
tarFile\
= Path(Path(targetPath /
cls.targetFile).resolve())
with suppress(FileNotFoundError):
tarFile.unlink()
timeit('subprocess.run(["tar", "-cf", tarFile.as_posix(),'
'cls.excludes[0], cls.excludes[1], cls.srcPath.as_posix()])',
number=1, globals=something)
The problem I have is that inside timeit() it cannot interpret subprocess. I believe that the globals argument to timeit() should help but I have no idea how to specify the module namespace. Can someone show me how?
I think in your case globals = globals() in the timeit call would work.
Explanation
The globals argument specifies a namespace in which to execute the code. Due to your import of the subprocess module (outside the function, even outside the class) you can use globals(). In doing so you have access to a dictionary of the current module, you can find more info in the documentation.
Super simple example
In this example I'll expose 3 different scenarios.
Need to access globals
Need to access locals
Custom namespace
Code to follow the example:
import subprocess
from timeit import timeit
import math
class ExampleClass():
def performance_glob(self):
return timeit("subprocess.run('ls')", number = 1, globals = globals())
def performance_loc(self):
a = 69
b = 42
return timeit("a * b", number = 1, globals = locals())
def performance_mix(self):
a = 69
return timeit("math.sqrt(a)", number = 1, globals = {'math': math, 'a': a})
In performance_glob you are timing something that needs a global import, the module subprocess. If you don't pass the globals namespace you'll get an error message like this NameError: name 'subprocess' is not defined
On the contrary, if you pass globals() to the function that depends on local values performance_loc the needed variables for the timeit execution a and b won't be in the scope. That's why you can use locals()
The last one is a general scenario where you need both the local vars in the function and general imports. If you keep in mind that the parameter globals can be specified as a dictionary, you just need to provide the necessary keys, you can customize it.

Resources