importing function giving scoping error - python

Suppose we save the following into a Python file called test.py:
x = 14
def print_x():
print x
def increment_x():
x += 1
and then run the following from an interactive Python shell in the same directory:
from test import print_x, increment_x
print_x()
increment_x()
print x
Why does the third call produce an error? Doesn't x need to be defined for the first two to work?

The functions do not throw an error because they still live in the module test, and they still see x in the module test. When you import a reference to a function elsewhere it dose not really move, or become disconnected from its original context. If it did there wouldn't be much use for modules.

The reason why you get a Scope error message is because x is only global in test.py and when you do:
from test import print_x, increment_x
You are not actually importing x to the global scope of the second script.
So, if you want to make x global as well in the second script, do:
from test import *
Try to use the DEBUGGER utility within IDLE to see when x is GLOBAL and when is not

Related

Part of Python code Cannot be Imported from another file

I have two python files under the same directory. One is called a.py and the other is called aa.py. They both import something from each other like:
# a.py
x = 1
from aa import var
y=1
# aa.py
import a
var = 1
print(a.x)
print(a.y)
If I run python aa.py It will pop up error AttributeError: module 'a' has no attribute 'y'.
I am very confused why x is successfully imported while y cannot. It feels like because in a.py, x is declared before from aa import var but why is that?
Thanks.
Someone with a lot more back-end programming experience could probably add a lot more, but my thought is that any Python being imported is going to be compiled before you can call it, and it's going to note the call for a before it has been defined.
FYI, you're going to run into circular dependencies if you keep writing your code like this: https://stackabuse.com/python-circular-imports
If you need something in both files, put it in a third file that can be called from both but that doesn't call either of the first two.

Python: how to enable a called file to access functions defined in the calling file?

I have two program files: a.py and b.py. The former calls the latter, but the latter expects to have access to some functions defined in the former. I can't seem to get this to work properly.
To give a concrete, simple example:
a.py
def onemore(x):
return x+1
import b
print "result is:", b.twomore(5)
b.py:
def twomore(x):
import a
return a.onemore(x)+1
Desired behavior from running a.py:
result is: 7
Actual behavior from running a.py:
result is: result is: 7
7
I have tried a bunch of different import structures, checked other answers posted here, but without any luck. The above is actually the best result I've been able to achieve, but it seems to run things twice, which is not permissible for my actual use case.
I recognize the circular nature of the imports here, but surely this is a solvable problem?
The practical motivation for this is: I'm trying to call an auxiliary routine from within a program, that needs access to basic functions defined in the program.
Your code
print "result is:", b.twomore(5)
gets run when import a is executed. Try putting it inside a block that only runs it if the file is being run directly from your console.
if __name__ == "__main__":
print "result is:", b.twomore(5)
That should fix it, but you should generally try to avoid circular dependencies if you can.
you should only import onemore from a (from a import onemore), otherwise import a also runs the print expression

Module global variables

I am using a python program (version 2.7) that imports a module and uses its functions and variables, like demonstrated below.
This is the module.
# module.py
variable = 2
def function(number):
global variable
variable = number
This is the program that uses the module.
# program.py
from module import *
print variable
function(1)
print variable
The program prints the following:
2
2
However, if you change program.py to this:
# program.py
import module
print module.variable
module.function(1)
print module.variable
The program prints this:
2
1
I have no idea why this is happening. Any insight would be helpful.
Thanks,
The Turtle 🐢
What you're trying to do is not possible using the global keyword.
In python, global variables are only global to their module and not shared across modules (not as in e.g. C). Also see this PEP for more information about this topic.
Besides, what you're doing in your example is ugly global abuse and leads to unmaintainable and hard to debug programs. There's a better way to do this depending on your exact situation.

How to properly evaluate sage code from within a Python script

I've been trying to evaluate a simple "integrate(x,x)" statement from within Python, by following the Sage instructions for importing Sage into Python. Here's my entire script:
#!/usr/bin/env sage -python
from sage.all import *
def main():
integrate(x,x)
pass
main()
When I try to run it from the command line, I get this error thrown:
NameError: global name 'x' is not defined
I've tried adding var(x) into the script, global x, tried replacing integrate(x,x) with sage.integrate(x,x), but I can't seem to get it to work, I always get an error thrown.
The command I'm using is ./sage -python /Applications/path_to/script.py
I can't seem to understand what I'm doing wrong here.
Edit: I have a feeling it has something to do with the way I've "imported" sage. I have my a folder, let's call it folder 1, and inside of folder 1 is the "sage" folder and the "script.py"
I am thinking this because typing "sage." doesn't bring up any autocomplete options.
The name x is not imported by import sage.all. To define a variable x, you need to issue a var statement, like thus
var('x')
integrate(x,x)
or, better,
x = SR.var('x')
integrate(x,x)
the second example does not automagically inject the name x in the global scope, so that you have to explicitly assign it to a variable.
Here's what Sage does (see the file src/sage/all_cmdline.py):
from sage.all import *
from sage.calculus.predefined import x
If you put these lines in your Python file, then integrate(x,x) will work. (In fact, sage.calculus.predefined just defines x using the var function from sage.symbolic.ring; this just calls SR.var, as suggested in the other answer. But if you want to really imitate Sage's initialization process, these two lines are what you need.)

Pass variable between python scripts

I'm sure this is very simple but I've been unable to get it working correctly. I need to have my main python script call another python script and pass variables from the original script to the script that I've called
So for a simplistic example my first script is,
first.py
x = 5
import second
and my second script is,
second.py
print x
and I would expect it to print x but I get
NameError: name 'x' is not defined
I'm not sure if import is right way to achieve this, but if someone could shed light on it in a simple way that would be great!
thanks,
EDIT
After reading the comments I thought I would expand on my question. Aswin Murugesh answer fixes the import problem I was having, however the solution does not have the desired outcome as I can not seem to pass items in a list this way.
In first.py I have a list which I process as follows
for insert, (list) in enumerate(list, start =1):
'call second.py passing current list item'
I wanted to pass each item in the list to a second python file for further processing (web scraping), I didn't want to do this in first.py as this is meant to be the main 'scan' program which then calls other programs. I hope this now make more sense.
Thanks for the comments thus far.
When you call a script, the calling script can access the namespace of the called script. (In your case, first can access the namespace of second.) However, what you are asking for is the other way around. Your variable is defined in the calling script, and you want the called script to access the caller's namespace.
An answer is already stated in this SO post, in the question itself:
Access namespace of calling module
But I will just explain it here in your context.
To get what you want in your case, start off the called script with the following line:
from __main__ import *
This allows it to access the namespace (all variables and functions) of the caller script.
So now your calling script is, as before:
x=5
import second
and the called script is:
from __main__ import *
print x
This should work fine.
use the following script:
first.py:
x=5
second.py
import first
print first.x
this will print the x value. Always imported script data should be referenced with the script name, like in first.x
To avoid namespace pollution, import the variables you want individually: from __main__ import x, and so on. Otherwise you'll end up with naming conflicts you weren't aware of.
Try use exec
Python3.5:
first.py
x=5
exec(open('second.py').read())
second.py
print(x)
You can also pass x by using:
x=5
myVars = {'x':x}
exec(open('second.py').read(), myVars)
Not sure if this is a good way.
Finally,
I created a package for Python to solve this problem.
Install Guli from PIP.
$ pip install guli
Guli doesn't require installing any additional PIP package.
With the package you can
Guli can be used to pass between different Python scripts, between many processes or at the same script.
pass variables between main Process and another (Multiprocess) Process.
Pass variables between different Python scripts.
Pass variables between 'Main Process' and another (Multiprocess) Process.
Use variables at the same script.
Create / Delete / Edit - GuliVariables.
Example
import guli
import multiprocessing
string = guli.GuliVariable("hello").get()
print(string) # returns empty string ""
def my_function():
''' change the value from another process '''
guli.GuliVariable("hello").setValue(4)
multiprocessing.Process(target=my_function).start()
import time
time.sleep(0.01) # delay after process to catch the update
string = guli.GuliVariable("hello").get()
print(string) # returns "success!!!"
Hope I solved the problem for many people!

Categories

Resources