Share a variable between two files? - python

What is a mechanism in Python by which I can do the following:
file1.py:
def getStatus():
print status
file2.py:
status = 5
getStatus() # 5
status = 1
getStatus() # 1
The function and the variable are in two different files and I'd like to avoid the use of a global.

You can share variables without making them global by putting them in a module. Anybody who imports the module gets the same module object, so its contents are shared; changes made at one location show up in all the others.
notglobal.py:
status = 0
get.py:
import notglobal
def getStatus():
return notglobal.status
Testing:
>>> import notglobal
>>> import get
>>> notglobal.status = 5
>>> get.getStatus()
5
>>> notglobal.status = 1
>>> get.getStatus()
1

Related

Refactor: "Extract Method" error and unexpected outcome

I'm experiencing weird refactoring behavior.
With this line of code:
variable = 1 + 2 + 3
When I try to extract a variable, by highlighting "1 + 2", then right click -> choose "extract variable" option, i get this outcome:
newvariable74 = 1 + 2
a = newvariable74 2 + 3
I have other issues with refactoring. I get different results when testing the rope examples from the docs
For example, this code:
def f():
a_var = 1
# INFO: I'm printing `a_var`
print 'a_var = %s' % a_var
...after renaming 'a_var' to 'new_var', the new code should look like this:
def f():
new_var = 1
# INFO: I'm printing `new_var`
print 'new_var = %s' % new_var
but instead, I get this:
def f():
new_var = 1
# INFO: I'm printing `a_var`
print ('a_var = %s' % new_var)
notice how the content of the string doesn't change.
Some info:
I use Python 3.8.2 64-bit
Visual Studio Code: 1.47.1
Linux Mint 20
Linux Kernel 5.4.0-40-generic
Currently, the refactoring function of vscode variables and methods is provided by Python extension, but its refactoring does not support renaming function.
For variable refactoring in vscode, you could try adding parentheses to it to make it recognized.
variable = (1 + 2) + 3
If you want to rename all 'a_var' to 'new_var' in vscode, you could try using Ctrl+F2.It will change all 'a_var' that appear in the current file.
When I use 'F2', it only changes the variables in the current file, 'new'_ Var =% s' will not be recognized.
You can refer to:Refactoring

Sharing variables across modules

I have a program- main.py that generates values for a few parameters depending on the user provided inputs. I need to share these variables with other modules- aux.py. To do that I did the following (simplified code below) -
This the main.py file:
# these three variables are dynamically calculated depending on the user provided input
a = 12
b = 13
c = 14
def declare_global():
global a, b, c
declare_global()
import aux
aux.print_all()
This is the aux.py file
def print_all():
a = globals()['a']
b = globals()['b']
c = globals()['c']
print(a)
print(b)
print(b)
Running the main.py file results in the following error
Traceback (most recent call last): File
"/Users/new/Library/Preferences/PyCharmCE2018.3/scratches/global_experiment/main.py",
line 13, in
aux.print_all() File "/Users/new/Library/Preferences/PyCharmCE2018.3/scratches/global_experiment/aux.py",
line 2, in print_all
a = globals()['a'] KeyError: 'a'
There is a very similar post addressing the same issue here but the posts there suggest adding all global variables to a new file and then importing the created file. But I cannot do that as I'll have no prior information as to what values these variables will take.
So, how do I share variables across modules?
EDIT
I lost some complexity of the actual program in order to make a minimalistic example. The reason I cannot pass the variables a,b,c to the print_all function is because in the actual program, the variables a,b,c are not serializable. They are spark dataframe objects. And one of the modules I use there (which here I am representing by print_all) serializes all its inputs I end up with an error (spark dataframes aren't serializable). Using a few workarounds I have arrived here where I use global variables and no inputs to the functions.
a = 12
b = 13
c = 14
import aux
aux.print_all(a, b, c)
Then your aux file will become:
def print_all(a, b, c):
a = globals()['a']
b = globals()['b']
c = globals()['c']
print(a)
print(b)
print(b)

Python: cannot import name x for importing module

** EDIT: Copy-pasting my actual file to ease confusion. The code snippet below is in a file named train_fm.py:
def eval_fm(x,b,w,V):
# evaluate a degree 2 FM. x is p X B
# V is p x k
# some python code that computes yhat
return(yhat);
Now in my main file: I say the following
from train_fm import eval_fm
and I get the error:
ImportError: cannot import name f1
When I type
from train_fm import train_fm
I do not get an error.
OLD QUESTION BELOW :
def train_fm(x,y,lb,lw,lv,k,a,b,w,V):
# some code
yhat = eval_fm(x,b,w,V);
# OUTPUTS
return(b,w,V);
I have a file called f2.py, where I define 2 functions (note that one of the functions has the same name as the file)
def f1():
some stuff;
return(stuff)
def f2():
more stuff;
y = f1();
return(y)
In my main file, I do
from aaa import f1
from aaa import f2
but when I run the first of the 2 commands above, I get
ImportError: cannot import name f1
Any idea what is causing this? The second function gets imported fine.

Python dynamic import and changing a variable

Lets say I have the following config file:
config.py:
x = 2
y = x * 2
I would like to import this in the file main.py, preferably using load_source command, but I also want to be able to change the value of x at the time of import such that the change in x propagates to the other variables in the config.py. For example, I want the following code, prints 6 and not 4.
main.py:
import imp
config = imp.load_source('', 'config.py')
config.x = 3
print config.y
What is the best way to do that? I know I can write functions in config.py to do this for me, but I prefer the config to be simple variable definitions only.
Put the code into a class:
class Config(object):
def __init__(self, x=2):
self.x = x
self.y = x * 2
Then, in your main program:
c = Config(3)
print c.y

call python with system() in R to run a python script emulating the python console

I want to pass a chunk of Python code to Python in R with something like system('python ...'), and I'm wondering if there is an easy way to emulate the python console in this case. For example, suppose the code is "print 'hello world'", how can I get the output like this in R?
>>> print 'hello world'
hello world
This only shows the output:
> system("python -c 'print \"hello world\"'")
hello world
Thanks!
BTW, I asked in r-help but have not got a response yet (if I do, I'll post the answer here).
Do you mean something like this?
export NUM=10
R -q -e "rnorm($NUM)"
You might also like to check out littler - http://dirk.eddelbuettel.com/code/littler.html
UPDATED
Following your comment below, I think I am beginning to understand your question better. You are asking about running python inside the R shell.
So here's an example:-
# code in a file named myfirstpythonfile.py
a = 1
b = 19
c = 3
mylist = [a, b, c]
for item in mylist:
print item
In your R shell, therefore, do this:
> system('python myfirstpythonfile.py')
1
19
3
Essentially, you can simply call python /path/to/your/python/file.py to execute a block of python code.
In my case, I can simply call python myfirstpythonfile.py assuming that I launched my R shell in the same directory (path) my python file resides.
FURTHER UPDATED
And if you really want to print out the source code, here's a brute force method that might be possible. In your R shell:-
> system('python -c "import sys; sys.stdout.write(file(\'myfirstpythonfile.py\', \'r\').read());"; python myfirstpythonfile.py')
a = 1
b = 19
c = 3
mylist = [a, b, c]
for item in mylist:
print item
1
19
3
AND FURTHER FURTHER UPDATED :-)
So if the purpose is to print the python code before the execution of a code, we can use the python trace module (reference: http://docs.python.org/library/trace.html). In command line, we use the -m option to call a python module and we specify the options for that python module following it.
So for my example above, it would be:-
$ python -m trace --trace myfirstpythonfile.py
--- modulename: myfirstpythonfile, funcname: <module>
myfirstpythonfile.py(1): a = 1
myfirstpythonfile.py(2): b = 19
myfirstpythonfile.py(3): c = 3
myfirstpythonfile.py(4): mylist = [a, b, c]
myfirstpythonfile.py(5): for item in mylist:
myfirstpythonfile.py(6): print item
1
myfirstpythonfile.py(5): for item in mylist:
myfirstpythonfile.py(6): print item
19
myfirstpythonfile.py(5): for item in mylist:
myfirstpythonfile.py(6): print item
3
myfirstpythonfile.py(5): for item in mylist:
--- modulename: trace, funcname: _unsettrace
trace.py(80): sys.settrace(None)
Which as we can see, traces the exact line of python code, executes the result immediately after and outputs it into stdout.
The system command has an option called intern = FALSE. Make this TRUE and Whatever output was just visible before, will be stored in a variable.
Now run your system command with this option and you should get your output directly in your variable. Like this
tmp <- system("python -c 'print \"hello world\"'",intern=T)
My work around for this problem is defining my own functions that paste in parameters, write out a temporary .py file, and them execute the python file via a system call. Here is an example that calls ArcGIS's Euclidean Distance function:
py.EucDistance = function(poly_path,poly_name,snap_raster,out_raster_path_name,maximum_distance,mask){
py_path = 'G:/Faculty/Mann/EucDistance_temp.py'
poly_path_name = paste(poly_path,poly_name, sep='')
fileConn<-file(paste(py_path))
writeLines(c(
paste('import arcpy'),
paste('from arcpy import env'),
paste('from arcpy.sa import *'),
paste('arcpy.CheckOutExtension("spatial")'),
paste('out_raster_path_name = "',out_raster_path_name,'"',sep=""),
paste('snap_raster = "',snap_raster,'"',sep=""),
paste('cellsize =arcpy.GetRasterProperties_management(snap_raster,"CELLSIZEX")'),
paste('mask = "',mask,'"',sep=""),
paste('maximum_distance = "',maximum_distance,'"',sep=""),
paste('sr = arcpy.Describe(snap_raster).spatialReference'),
paste('arcpy.env.overwriteOutput = True'),
paste('arcpy.env.snapRaster = "',snap_raster,'"',sep=""),
paste('arcpy.env.mask = mask'),
paste('arcpy.env.scratchWorkspace ="G:/Faculty/Mann/Historic_BCM/Aggregated1080/Scratch.gdb"'),
paste('arcpy.env.outputCoordinateSystem = sr'),
# get spatial reference for raster and force output to that
paste('sr = arcpy.Describe(snap_raster).spatialReference'),
paste('py_projection = sr.exportToString()'),
paste('arcpy.env.extent = snap_raster'),
paste('poly_name = "',poly_name,'"',sep=""),
paste('poly_path_name = "',poly_path_name,'"',sep=""),
paste('holder = EucDistance(poly_path_name, maximum_distance, cellsize, "")'),
paste('holder = SetNull(holder < -9999, holder)'),
paste('holder.save(out_raster_path_name) ')
), fileConn, sep = "\n")
close(fileConn)
system(paste('C:\\Python27\\ArcGIS10.1\\python.exe', py_path))
}

Categories