Here's a fun one. Create a file foo.py with the following contents:
OPTIONS = {'x': 0}
def get_option(key):
from foo import OPTIONS
return OPTIONS[key]
if __name__ == '__main__':
OPTIONS['x'] = 1
print("OPTIONS['x'] is %d" % OPTIONS['x'])
print("get_option('x') is %d" % get_option('x'))
Running python foo.py gives the following output:
OPTIONS['x'] is 1
get_option('x') is 0
I would have expected the result to be 1 in both cases. Why is it 0 in the second case?
You are getting this because from foo import OPTIONS line in get_options() function loads a new local OPTIONS variable in a memory whose value is {'x':0}. But if you remove/comment that line, then you got your expected result, this is because as OPTIONS variable in get_options() is now a global variable, not a local.
OPTIONS = {'x': 0}
def get_option(key):
# from foo import OPTIONS
return OPTIONS[key]
if __name__ == '__main__':
OPTIONS['x'] = 1
print("OPTIONS['x'] is %d" % OPTIONS['x'])
print("get_option('x') is %d" % get_option('x'))
You can also debug that by using the id() function which returns the “identity” of an object during it's lifetime.
For that the debugging code is:
OPTIONS = {'x': 0}
def get_option(key):
from foo import OPTIONS
print("Id is %d in get_option" % id(OPTIONS))
return OPTIONS[key]
if __name__ == '__main__':
OPTIONS['x'] = 1
print("Id is %d in main" % id(OPTIONS))
print("OPTIONS['x'] is %d" % OPTIONS['x'])
print("get_option('x') is %d" % get_option('x'))
Output:
Id is 140051744576688 in main
OPTIONS['x'] is 1
Id is 140051744604240 in get_option
get_option('x') is 0
Note: values of id's can be changed on your system.
Now, you can see the id's is different in both place, this means that there are two OPTIONS inside get_options() function one is __main__.OPTIONS and other one is foo.OPTIONS. But, if comment/remove line from foo import OPTIONS in get_options(), you get same id's at both places.
Related
I am learning Python 2.7 and trying to write a function in a module named new5.py like this:
def compare(a,b,c):
if a - 3 == 8:
return "I like a!"
elif b == c:
return "I like c!"
else:
return "I like b!"
When I try to call the function in the moudle named app02.py which is presented with detail code at the end of the qustion, I am told like this as presented as the following on the screen shot:
I guess the problem is on a, but what should I do to use the function? Thank you!
------ the following is the module app02.py rooted from web.py 0.3------
import web
import new5
urls = (
'/dyear', 'Index'
)
app = web.application(urls, globals())
render = web.template.render('/Users/Administrator/projects/gothonweb/templates/', base="layout01")
class Index(object):
def GET(self):
return render.hello_form01()
def POST(self):
form01 = web.input(a_year=1980)
form02 = web.input(a_month=01)
form03 = web.input(a_day=01)
greeting = "Your result from app02 is %s" % (new5.compare(form01, form02, form03))
return render.index(greeting = greeting)
if __name__ == "__main__":
app.run()
Instead of passing the whole Storage object to compare(), you should access a_year in form01, a_month in form02 and a_day in form03 objects like form01.a_year, form2.a_month or form3.a_day
So your function call should look something like
greeting = "Your result from app02 is %s" % (new5.compare(form01.a_year, form02.a_month, form03.a_day))
Also, note this from the docs
Note that the web.input() values will be strings even if there are
numbers passed to it.
so you'll need to typecast your web.input from string to the required type(here int) like so
if int(a) - 3 == 8:
This is what I have in mind because I find myself typing the name twice whenever I want to inspect the value of a variable:
a = 1
my_print(a) # "a: 1"
Is this possible in Python?
If you are in control of the calling function, you can hack this to work reasonably well like:
Code:
import inspect
def print_name_and_value(var):
lines = inspect.stack()[1][4]
var_name = ''.join(lines).strip().split('(')[-1].split(')')[0]
print("%s: %d" % (var_name, var))
a = 5
print_name_and_value(a)
Results:
a: 5
How does this work?
The inspect module can be used to inspect the caller, and get the line of code used by the caller. With a bit of string hacking the variable name (assuming it is a simple variable and not a more complex expression) can be gathered from the source code.
I would say "no", and any other magic doable is just... too much magic.
However there's something you can do, and that's looking at the stack trace using the inspect module.
import inspect
def my_print(thingy):
# print("id(thingy)=%s" % id(thingy))
previous_frame = inspect.currentframe().f_back
# print("locals: %s" % previous_frame.f_locals)
for variable_name, variable_value in previous_frame.f_locals.items():
if id(variable_value) == id(thingy):
return("%s: %s" % (variable_name, variable_value))
# print("globals: %s" % previous_frame.f_globals)
for variable_name, variable_value in previous_frame.f_globals.items():
if id(variable_value) == id(thingy):
return("%s: %s" % (variable_name, variable_value))
if __name__ == '__main__':
a = 1
print("Test %s" % my_print(a)) # "a: 1"
list_thingy = [1, 2, 3]
print("Test %s" % my_print(list_thingy))
def and_within_function():
d = {1: "a"}
print("Test %s" % my_print(d))
and_within_function()
But this is not reliable and I'd use it more as a curiosity, since there are plenty of "special cases". For instance: the first 255 integers (I think) in Python occupy a specific memory address so, if you have two variables that are =1 I don't think you're gonna really be guaranteed which one is it.
How can I use external variables in Python, like extern int x; in C?
For example,
main1.py:
from myfunc import print_a
a = 10
print a
print_a()
myfunc.py:
def print_a():
global a
print a
Simply re-assign the variable in the module:
import myfunc
from myfunc import print_a
a = 10
print a
myfunc.a = a
print_a()
Otherwise it is not possible.
Rememeber that python treats modules in a way that is quite different from C.
The import in python does not "copy the contents" of the file in that place,
but it executes the code in the given file and creates a module object.
The global variable of the module are the module object attributes, which can be modified as I've shown. There is no such notion as "global variable" except for built-ins.
I'd suggest to refactor your code in such a way that you don't have to modify this global variable at all, moving the code that uses myfunc.a from main1 to myfunc.
The fact that you need such global variable is already a code smell that there's something wrong with your code and you should try to fix it.
Actually there is a way to affect the "global scope" but it is so hackish that I don't even want to mention it. Trust me: you don't want to use it. If people see your code using such a hack you may be in physical danger.
Unlike C, variables declared at global scope are still limited in scope to the module they are created in, so you need to qualify the name a with the module it lives in.
The global keyword is used when you are going to modify a global variable by reassigning, you do not need it when you are just referencing a global variable.
If you are trying to access a variable of another file, you must import that module, and because of the way your files are structured you have a couple of ways to resolve issues:
Option 1) Move the referencing of myfunc.print_a inside of a function and import main1 inside myfunc to see a
main1.py
import myfunc
a = 10
def main():
print a
myfunc.print_a()
if __name__ == '__main__':
main()
myfunc.py
import main1
def print_a():
print main1.a
Option 2) recommended Move the variable(s) into another module and have both myfunc and main1 import it.
vals.py
a = 20
main1.py
import vals
from myfunc import print_a
vals.a = 10
print vals.a
print_a()
myfunc.py
import vals
def print_a():
print vals.a
This is a workaround to this problem by using a common external file. In this example I am storing an index variable to flag in each application whether a file is being accessed. The variable indxOpen in ext1.py and indxO in ext2.py are being updated and stored in a common external text file "externalVars.txt"
lead application ext1.py
# lead application ext1.py
#this alternately flips the value of indxOpen on prime number intervals
import time
def update(d,v1):
f=open(d+'externalVars.txt','r+')
f.write(str( v1))
f.truncate()
f.close()
# ensure variable is initialised and made available to external apps
indxOpen = False
var_dir = "<your external var directory>/"
try:
f =open(var_dir+'externalVars.txt','r')
except:
f= open(var_dir+'externalVars.txt','w')
f.close()
# this alternately flips the value of indxOpen on prime number intervals
update(var_dir,indxOpen)
i = 0
while True:
while indxOpen:
i += 1
if (i % 13) ==0:
indxOpen = indxOpen ^ True
update(var_dir,indxOpen)
f=open(var_dir+'externalVars.txt','r+')
t=f.readline()
print "app1",t," ",i
if t=='False':
print "app1 updated"
update(var_dir,indxOpen)
indxOpen = False
else:
time.sleep(1.4)
while not indxOpen:
f=open(var_dir+"externalVars.txt","r+")
t=f.readline()
print "app1",t
if t=='True':
indxOpen = True
else:
time.sleep(1)
ext2.py following application
# ext2.py this alternately flips the value of indxO on prime number intervals but it is initialised by the lead application
# in this case ext1.py
# python 2.7.12
import time
def update(d,v1):
f=open(d+'externalVars.txt','r+')
f.write(str( v1))
f.truncate()
f.close()
var_dir = "<your external var directory>/"
# intialise external variable
f=open(var_dir+'externalVars.txt','r+')
t=f.readline()
if t=='True':
indxO= True
if t=='False':
indxO= False
i=0
while True:
while indxO:
f=open(var_dir+"externalVars.txt","r+")
t=f.readline()
print "app2",t
if t=='False':
indxO = False
update(var_dir,indxO)
else:
time.sleep(1.5)
while not indxO:
i += 1
if (i % 17) ==0:
indxO = indxO ^ True
update(var_dir,indxO)
f=open(var_dir+"externalVars.txt","r+")
t=f.readline()
print "app2",t," ",i
if t=='True':
indxO = True
print "apt2 updated"
update(var_dir,indxO)
else:
time.sleep(1.3)
This is a followup question from 1
I need to test the function with two given cases in a loop. However, based on the printed results, it seems like only the first iteration is checked? Is this related to runner.run(unittest.makeSuite(MyTestCase))?
import unittest
from StringIO import StringIO
import rice_output
class MyTestCase(unittest.TestCase):
def setUp(self):
#####Pre-defined inputs########
self.dsed_in=[1,2]
self.a_in=[2,3]
self.pb_in=[3,4]
#####Pre-defined outputs########
self.msed_out=[6,24]
#####TestCase run variables########
self.tot_iter=len(self.a_in)
def testMsed(self):
for i in range(self.tot_iter):
print i
fun = rice_output.msed(self.dsed_in[i],self.a_in[i],self.pb_in[i])
value = self.msed_out[i]
testFailureMessage = "Test of function name: %s iteration: %i expected: %i != calculated: %i" % ("msed",i,value,fun)
return self.assertEqual(round(fun,3),round(self.msed_out[i],3),testFailureMessage)
from pprint import pprint
stream = StringIO()
runner = unittest.TextTestRunner(stream=stream)
result = runner.run(unittest.makeSuite(MyTestCase))
print 'Tests run ', result.testsRun
print 'Errors ', result.errors
Here is he output:
0
Tests run 1
Errors []
[]
Test output
testMsed (__main__.MyTestCase) ... ok
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
Any suggestions? Thanks!
Remove the return statement
def testMsed(self):
for i in range(self.tot_iter):
print i
fun = rice_output.msed(self.dsed_in[i],self.a_in[i],self.pb_in[i])
value = self.msed_out[i]
testFailureMessage = "Test of function name: %s iteration: %i expected: %i != calculated: %i" % ("msed",i,value,fun)
self.assertEqual(round(fun,3),round(self.msed_out[i],3),testFailureMessage)
Here's an example on what I'm thinking:
def check_args():
if len(sys.argv) < 2:
sys.exit('Reason')
if not os.path.exists(sys.argv[1]):
sys.exit('ERROR: Folder %s was not found!' % sys.argv[1])
global path
path = sys.argv[1]
As you can tell after check_args() completes succefully the "path" variable has universal meaning - you can use it in other functions as de-facto variable.
So I'm thinking if there is a way to access "path" e.g. check_args.path?
How about in python v3?
Python functions are objects. You can define whatever custom properties you want on them:
def a():
a.test = 123
a()
a.test # => 123
You can simply return the value
def check_args():
if len(sys.argv) < 2:
sys.exit('Reason')
if not os.path.exists(sys.argv[1]):
sys.exit('ERROR: Folder %s was not found!' % sys.argv[1])
path = sys.argv[1]
return path
my_path = check_args()
or when using if __name__ ...:
if __name__ == '__main__':
my_path = check_args()
results = do_something(path)