Global variables in imported modules python - python

When global variables are all on one script, things work smoothly.
def foo():
global x
x = 'bar'
goo()
def goo()
global x
print(x)
foo()
would print bar as expected.
However, it does not work when I have to import goo from another file, for example
file1.py
from file2 import goo
def foo():
global x
x = 'bar'
goo()
foo()
file2.py
def goo()
global x
print(x)
results in NameError. How can x be passed to the imported function like in the first case without passing it explicitly as an argument?

you have to set <module_name>.<variable_name> = 'bar' for it to work like so:
import file2
def foo():
file2.x = 'bar'
file2.goo()
foo()
file1 is the same

Related

Global keyword in nested functions of Python

Following is a function with a nested function. Please help me understand why value of 'x' is same before and after calling bar(). And why x=25 when we call the main function.
def foo():
x = 20
def bar():
global x
x = 25
print("Before calling bar: ", x)
print("Calling bar now")
bar()
print("After calling bar: ", x)
foo()
print("x in main: ", x)
This is the output we get:
Before calling bar: 20
Calling bar now
After calling bar: 20
x in main: 25
Shouldn't the code print out x=25 after calling bar() since it has x as global variable?
global is used to access global namespace outside of a local context, so in your example you access the namespace outside of foo. That's why the value of x inside foo is unchanged. If you want to access values inside foo from bar, you have to use nonlocal instead. This will result in a NameError when you try to print x on the last line of your script, since x is no longer defined in your global namespace:
def foo():
x = 20
def bar():
nonlocal x
x = 25
print("Before calling bar: ", x)
print("Calling bar now")
bar()
print("After calling bar: ", x)
foo()
print("x in main: ", x) # Raises NameError because x is not defined in global namespace

How can I use a global variable in another file in Python?

I want to make i into 3 in file s2.py, but it keeps becoming 1.
File s1.py
i=1
class a():
def f():
global i
i = 3
File s2.py
from s1 import *
a.f()
print(i)
Every module has its own global scope, and Python is lexically scoped, meaning a.f refers to the global scope of s1 no matter where it is called from. i is initialized to the value of s1.i, but is otherwise independent of it. Changes to s1.i do not affect s2.i.
You have to re-import your variable after calling your method if you want to see any changes made.
#s1.py
i=1
class a():
def f():
global i
i = 3
#s2.py
from s1 import *
a.f()
from s1 import i
print(i)
#s1.py
i=1
class a():
def f():
global i
i += 3
#s2.py
import s1
s1.a.f()
print(s1.i)
I believe you are referencing the local variable i and aren't referencing the instance of i in the class. Try this.
print(a.i)
Reimport the variable after calling the method:
File s1.py
i = 1
class a():
def f():
global i
i += 3
File s2.py
import s1
s1.a.f()
print(s1.i)

How to test variable scoped in file, from unit test

I have a program like this
class A():
def __init__(self):
self.foo = x
if __name__ == '__main__':
x = 96
a=A()
print(a.foo)
When this runs from the shell "python foo.py" it prints out 96
I also have test_foo.py
import foo
import unittest
class TestFoo(unittest.TestCase):
def test1(self):
x=37
a=foo.A()
self.assertEqual(a.foo, 37)
if __name__ == '__main__':
unittest.main()
When I run this test_foo.py from the shell I get
$ python test_foo.py
E
======================================================================
ERROR: test1 (__main__.TestFoo)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_foo.py", line 8, in test1
a=foo.A()
File "/home/zzz/foo.py", line 3, in __init__
self.foo = x
NameError: global name 'x' is not defined
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (errors=1)
So my question is, is it possible to test foo.py from test_foo.py, to set x and see it being used in the class A. f Without altering the foo.py program
Obviously, this is a simplified version of a real program
I get the same results with python 3.6 and 2.7
I have tried using various combinations of global but didn't find a way using this
Your x variable is defined inside the if block that checks if foo.py is being run as the main program, so when foo.py is imported by test_foo.py, x would not be defined, hence the error.
You should define x outside the if block instead:
x = 96
class A():
def __init__(self):
self.foo = x
if __name__ == '__main__':
a=A()
print(a.foo)
And in test_foo.py, if you want to override the value of the x of foo, you should do foo.x=37 instead of x=37 since x would otherwise be a local variable to test1.
You need to change it to:
class A():
def __init__(self,x):
self.foo = x
and in the test:
class TestFoo(unittest.TestCase):
def test1(self):
x=37
a=foo.A(x)
self.assertEqual(a.foo, 37)
You make access to variable x in global scope here:
self.foo = x
When you run script directly __name__ is 'main', than you set global variable x and than construct A().
When you import foo module code under if is not executed. There is no variable x in global scope nor in any outer scope.

Python Importing Functions

If I have a function defined in my code lets call foo(), and I use the following code:
from mod1 import *
With mod1 containing a function also with the same name of foo() and call the foo() function, will this override my original definition of the function when it evaluates it?
As far as I know it will.
you would need to either rename you foo() function you have built OR change your module input to read
import mod1 and subsequently define any use of the foo() function from mod1 to mod1.foo()
Depends on where the function is:
def foo():
pass
from mod1 import *
foo() # here foo comes from mod1
# -------
# another interesting case
def foo():
from mod1 import *
foo() # this will also call foo from mod1
foo() # but this one is still the foo defined above.
# ---------
# The opposite
from mod1 import *
def foo():
pass
foo() # here foo is the one defined above
Anyway, from module import * is considered a VERY bad and error-prone practice. It is a kind of using namespace std;-like thing in C++. Avoid it as much as possible.
a.py
def foo():
print 'Hello A'
Test
>>> def foo():
... print 'Hello 1'
...
>>> foo()
Hello 1
>>> from a import *
>>> foo()
Hello A
>>> def foo():
... print 'Hello 2'
...
>>> foo()
Hello 2
I get the following:
file mod1.py contains
def foo():
print "hello foo"
and then i start python interpreter and do the following:
>>> def foo():
... print "hello world"
...
>>> from mod1 import *
>>> foo()
hello foo
>>>
So yes, it would override.
Unless you then do, a new
def foo():
print "new foo"
In which case it would print "new foo"
It depends on the relative order of the function definition and the import statement. Whichever is executed second will override the first.

changing values inside a local space by a function in that local space

here's a sample code:
def foo():
def bar():
foobar = 'foobaz'
foobar = 'foobar'
print foobar
bar()
print foobar
foo()
I want to change variable foobar inside foo by function bar. The code above will not work, since foobar inside bar is in separate namespace with foobar in foo. A simple workaround would be making a global foobar and have both foo and bar can access it, but I hope there would be simpler workarounds.
On python 3.x you can use nonlocal and for python 2.x try using function attributes:
def foo():
def bar():
foo.foobar = 'foobaz' #change the function attribute
foo.foobar = 'foobar' #declare as function attribute
print foo.foobar
bar()
print foo.foobar
foo()
output:
foobar
foobaz
You are looking for the nonlocal keyword, which exists in 3.x.
def f():
x = None
def g():
nonlocal x
x = 1
If you are stuck in 2.x, you can do it by having a list or similar mutable data container and accessing that as a work around.
def f():
x = [None]
def g():
x[0] = 1
This works as variables do fall into scope, but won't leak out of scope. With mutable objects, we can change them inside the scope, and those changes propagate out.
Not possible in python 2.7. In python 3:
def foo():
def bar():
nonlocal foobar
foobar = 'foobaz'
foobar = 'foobar'
print foobar
bar()
print foobar
foo()
In 2.x, you can do:
def foo():
foobar = []
def bar():
foobar[0] = 'foobaz'
foobar[0] = 'foobar'
print foobar[0]
bar()
print foobar[0]
foo()
def foo():
def bar():
foobar = 'foobaz'
return foobar
foobar = 'foobar'
print foobar
foobar = bar()
print foobar
foo()
Even though functions are already first class objects in Python, you can create your own "functor" or function object something like this:
class Foo(object):
def bar(self):
self.foobar = 'foobaz'
def __call__(self):
self.foobar = 'foobar'
print self.foobar
self.bar()
print self.foobar
foo = Foo()
foo()

Categories