4

I have two files say a.py and b.py.

in a.py , we do

import xxx
from b import *

in b.py we have a function which requires module xxx. Now when the function in b.py is called from a.py it cant find the module xxx.

Why is that and what can be the solution here? i cant do import xxx in b.py for some reason.

MCV:

a.py

import xxx
from b import *
fun()

b.py

def fun():
    xxx.dosomething()

Error:

Global name xxx not defined

vks
  • 67,027
  • 10
  • 91
  • 124
  • 4
    Not sure what you are trying to achievie. Please provide a [Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve). It shouldn't be too hard. – K. Kirsz Jul 20 '17 at 05:17
  • Could you use `import a` in the `b` module? – awesoon Jul 20 '17 at 05:19
  • What is the import error that you get? – Moyote Jul 20 '17 at 05:20
  • 1
    you need to import xxx in b.py – Kallz Jul 20 '17 at 05:21
  • What is the reason that prevents you from doing `import xxx` in a module that contains a function that needs it? – Thierry Lathuille Jul 20 '17 at 05:22
  • Have you checked this: https://stackoverflow.com/questions/3977167/nameerror-global-name-is-not-defined ? – Moyote Jul 20 '17 at 05:23
  • What do you mean by "conflicts" exactly? Isn't solving this conflict your real problem? – Thierry Lathuille Jul 20 '17 at 05:24
  • `it conflicts with another module` - I'm not sure, that hacking python imports is *the way* to fix the conflicting modules – awesoon Jul 20 '17 at 05:24
  • @ThierryLathuille its a conflict between `grequests` which patches all sockets and `multiprocess` which does not want patched `sockets` – vks Jul 20 '17 at 05:27
  • 1
    Maybe you should ask a question about *that* explicitely. – Thierry Lathuille Jul 20 '17 at 05:32
  • @ThierryLathuille but this is more related to `a.py`'s namespace .when `xxx` is there why cant it process it – vks Jul 20 '17 at 05:33
  • @vks: is it better to create a class that inherits from the library and then modify the class instead of directly monkey patching the library? hmm. i guess you didn't make grequests. – hamster on wheels Jul 20 '17 at 05:58
  • @rxu i have the solution....i just want to know the reason behind this behaviou – vks Jul 20 '17 at 05:59
  • @vks: Although the `multiprocessing` imported and patched in `grequest` is not directly visible in your program, python probably just keep a single copy of `multiprocessing` in memory. `grequests` monkey patches `multiprocessing`'s `sockets`. Then you import the `multiprocessing`. python thought `multiprocessing` is already imported, so it goes on and use the patched version of `multiprocessing`. python never import the same thing twice. Really, please edit to say this is the question you want to ask, if that is the case. The monkey patching part is not visible in your question. – hamster on wheels Jul 20 '17 at 06:04
  • @vks: what is the solution? – hamster on wheels Jul 20 '17 at 07:03
  • @rxu I imported `xxx` in indivisual functions where it is required. – vks Jul 20 '17 at 07:31
  • @vks if you import xxx in function then be careful about cyclic import problem for more info about cyclic info https://stackoverflow.com/questions/744373/circular-or-cyclic-imports-in-python – Kallz Jul 20 '17 at 07:48
  • I just want to point to the fact that your example for file `a.py` is probably wrong: `import xxx; from b import *; b.fun()`. `b` is not defined in `a.py`. You should be calling simply `fun()` and not `b.fun()`. Just a suggestion to edit your example. – AGN Gazer Jul 20 '17 at 08:41
  • @AGNGazer done!! thanx – vks Jul 20 '17 at 08:44

6 Answers6

5

In python all modules have their own global namespaces, and A namespace containing all the built-in names is created, and module don't share it with other only built in Namespace are common and available for all modules, when you import a module it added into module global namespace, not into built namespace

enter image description here

The import statement does two things:

one, if the requested module does not yet exist, executes the code in the imported file

two makes it available as a module. Subsequent import statements will skip the first step.

and the Main point is that the code in a module will be executed exactly once, no matter how many times it is imported from various other modules.

SOURCE

vks
  • 67,027
  • 10
  • 91
  • 124
Kallz
  • 3,244
  • 1
  • 20
  • 38
  • 1
    what's the source for all this – vks Jul 20 '17 at 06:08
  • This is the case. Say, a.py import library X and monkey patches X. Then, b.py imports a.py. At this point, X is not directly visible to b.py. After that b.py imports X. Python won't import the same thing twice, so it goes on and uses the X patched in a.py for b.py instead of importing a new copy of X for b.py. That is why b.py only gets the patched X, but not the original X. – hamster on wheels Jul 20 '17 at 06:18
  • @vks You shouldn't accept an answer which shows no effort at answering your questions. Blind copy paste is tantamount to plagiarism and must be frowned upon. – cs95 Aug 18 '17 at 14:09
  • @cᴏʟᴅsᴘᴇᴇᴅ while you may be correct,I also had an aspect to look upon wherein I was stuck with this and somebody got me outta it.... So had no option but to accept this :) – vks Aug 24 '17 at 05:19
1

Question:

a.py:

import numpy
print("a.py is imported")

b.py:

import a
numpy.zeros(8)

Result (python3 b.py):

a.py is imported
Traceback (most recent call last):
  File "b.py", line 3, in <module>
    numpy.zeros(8)
NameError: name 'numpy' is not defined

Answer:

I guess this is better for writing a library. Let's say a.py is part of the library, b is the user's program that uses the library, and I wrote the library. If everything I imported (import numpy) in a.py shows up in b.py, the API of my library won't be that clean because I can't hide the numpy library from the users of my library. I guess that is the reason that libraries imported in a.py is hidden from b.py if b.py imports a.py.

hamster on wheels
  • 2,771
  • 17
  • 50
  • That would be too heavy...a.py is very huge and b.py is just utility....which many people use...not a great idea – vks Jul 20 '17 at 05:28
  • python is a bit slow at importing things.That is fine if the computing takes a long time. I think it is fine to import numpy in a library. Many python programs uses numpy anyway. importing numpy twice takes nearly the same amount of time as importing numpy once. – hamster on wheels Jul 20 '17 at 05:32
  • no `a.py` has a lot of things which we dont want in `b.py` .`b.py` it just a small utility – vks Jul 20 '17 at 05:35
  • hmm. does the start up time/file size of b.py matters a lot? If that is the case, make a smaller library for b.py, make b.py a standalone program (that doesn't import a.py), or just write it in c/c++ and compile it. – hamster on wheels Jul 20 '17 at 05:42
  • python's import and c/c++'s #include really don't work the same way. In c++, if you #include something in a header, and then include that header in another header, that something is visible in both headers, and we need include guards. Python doens't need include guard because if you import numpy in python file a.py, that import numpy stays in a.py. Even if b.py imports a.py, numpy in a.py won't show up in b.py. – hamster on wheels Jul 20 '17 at 05:49
1

Here is a set of two files that attempt to simulate your issue. Version 1 is what you describe and Version 2 is what works.

VERSION 1 (OP issue)

file 'a.py':

print("a.py: entered a.py")
import math
print("a.py: imported math")
print("a.py: 1st dir()={}".format(dir()))
from b import *
print("a.py: imported * from b")
print("a.py: 2nd dir()={}".format(dir()))
def angle(x, y):
    return math.acos(x/mysq(x*x+y*y))
print("a.py: angle has been defined")
print("a.py: 3rd dir()={}".format(dir()))
import b
print("a.py: dir(b)={}".format(dir(b)))

file 'b.py':

print("b.py: entered b.py")
print("b.py: 1st dir():{}".format(dir()))
def mysq(x):
    return math.sqrt(x)
print("b.py: mysq has been defined")        
print("b.py: 2nd dir():{}".format(dir()))
print("b.py: leaving b.py...")

Then

>>> import a
a.py: entered a.py
a.py: imported math
a.py: 1st dir()=['__builtins__', '__cached__', '__doc__', '__file__',
                 '__loader__', '__name__', '__package__', '__spec__',
                 'math']
b.py: entered b.py
b.py: 1st dir():['__builtins__', '__cached__', '__doc__', '__file__',
                 '__loader__', '__name__', '__package__', '__spec__']
b.py: mysq has been defined
b.py: 2nd dir():['__builtins__', '__cached__', '__doc__', '__file__',
                 '__loader__', '__name__', '__package__', '__spec__',
                 'mysq'] # <-- NOTICE that module 'b' is still hasn't
                         # loaded 'math' before leaving it!!!
b.py: leaving b.py...
a.py: imported * from b
a.py: 2nd dir()=['__builtins__', '__cached__', '__doc__', '__file__',
                 '__loader__', '__name__', '__package__', '__spec__',
                 'math', 'mysq']
a.py: angle has been defined
a.py: 3rd dir()=['__builtins__', '__cached__', '__doc__', '__file__',
                 '__loader__', '__name__', '__package__', '__spec__',
                 'angle', 'math', 'mysq']
a.py: dir(b)=['__builtins__', '__cached__', '__doc__', '__file__',
              '__loader__', '__name__', '__package__', '__spec__',
              'mysq'] # <-- NOTICE that module 'b' is still not aware of 'math'!!!
>>> a.angle(7,8)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/.../a.py", line 9, in angle
    return math.acos(x/mysq(x*x+y*y))
  File "/Users/.../b.py", line 4, in mysq
    return math.sqrt(x)
NameError: name 'math' is not defined

VERSION 2 (working)

Put import math in b.py and remove it from a.py:

file 'a.py':

from b import *
print("a.py: imported * from b")
print("a.py: 1st dir()={}".format(dir()))
def angle(x, y):
    return math.acos(x/mysq(x*x+y*y))
print("a.py: angle has been defined")
print("a.py: 2nd dir()={}".format(dir()))

file 'b.py':

print("b.py: entered b.py")
import math
print("b.py: loaded math")
print("b.py: 1st dir():{}".format(dir()))
def mysq(x):
    return math.sqrt(x)
print("b.py: mysq has been defined")        
print("b.py: 2nd dir():{}".format(dir()))
print("b.py: leaving b.py...")

Then

>>> import a
b.py: entered b.py
b.py: loaded math
b.py: 1st dir():['__builtins__', '__cached__', '__doc__', '__file__',
                 '__loader__', '__name__', '__package__', '__spec__', 'math']
b.py: mysq has been defined
b.py: 2nd dir():['__builtins__', '__cached__', '__doc__', '__file__',
                 '__loader__', '__name__', '__package__', '__spec__',
                 'math', 'mysq']
b.py: leaving b.py...
a.py: imported * from b
a.py: 1st dir()=['__builtins__', '__cached__', '__doc__', '__file__', 
                 '__loader__', '__name__', '__package__', '__spec__',
                 'math', 'mysq'] # <-- NOTICE 'math' in a.py!!!
a.py: angle has been defined
a.py: 2nd dir()=['__builtins__', '__cached__', '__doc__', '__file__',
                 '__loader__', '__name__', '__package__', '__spec__',
                 'angle', 'math', 'mysq']
>>> a.angle(7,8)
0.8519663271732721

I can't explain (formulate) exactly the machinery behind this behavior but it seems reasonable to me: How is mysq() in b.py is supposed to know about math? The output from numerous print statements indicate that in Version 1 (OP question) importing from b results in importing into a.py's namespace everything that was defined/imported in b.py. The entire b.py is executed once at the time of the import into a.py. However, b itself never "knows" anything about math.

In Version 2 everything works as expected because math is imported into b which is executed immediately at the time of its import into a and imports everything from b (including math) into a.

Now, let's do some more experimentation... Let's break version 2:

VERSION 2b (broken)

In this version we modify a.py as follows (b.py stays the same as in Version 2):

file 'a.py':

import b # <-- We do not import 'math' from b into a!
         # Is it still "loaded" somehow into 'a'?
def angle(x, y):
    return math.acos(x/b.mysq(x*x+y*y))

Importing "just" b itself (as opposite to importing everything from b) does not import math into a:

>>> a.angle(7,8)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/.../a.py", line 10, in angle
    return math.acos(x/b.mysq(x*x+y*y))
NameError: name 'math' is not defined

VERSION 1b (fixed)

Finally, let's fix Version 1 by importing everything from a into b as well as continuing to import everything from b into a:

file 'a.py':

print("a.py: entered a.py")
import math
print("a.py: imported math")
print("a.py: 1st dir()={}".format(dir()))
from b import *
print("a.py: imported * from b")
print("a.py: 2nd dir()={}".format(dir()))
def angle(x, y):
    return math.acos(x/mysq(x*x+y*y))
print("a.py: angle has been defined")
print("a.py: 3rd dir()={}".format(dir()))
import b # extra check of b
print("a.py: dir(b)={}".format(dir(b)))

file 'b.py':

print("b.py: entered b.py")
print("b.py: 1st dir():{}".format(dir()))
from a import *
print("b.py: imported * from a")
print("b.py: 2nd dir():{}".format(dir()))
def mysq(x):
    return math.sqrt(x)
print("b.py: mysq has been defined")        
print("b.py: 3rd dir():{}".format(dir()))
print("b.py: leaving b.py...")

Then

>>> import a
a.py: entered a.py
a.py: imported math
a.py: 1st dir()=['__builtins__', '__cached__', '__doc__', '__file__',
                 '__loader__', '__name__', '__package__', '__spec__',
                 'math'] # 'math' is loaded first into 'a'
b.py: entered b.py
b.py: 1st dir():['__builtins__', '__cached__', '__doc__', '__file__',
                 '__loader__', '__name__', '__package__', '__spec__'
                ] # 'b' doesn't "know" yet about 'math'
b.py: imported * from a
b.py: 2nd dir():['__builtins__', '__cached__', '__doc__', '__file__', 
                 '__loader__', '__name__', '__package__', '__spec__', 
                 'math'] # after importing *(!!!) from 'a' into 'b', 'b' now has 'math' 
b.py: mysq has been defined
b.py: 3rd dir():['__builtins__', '__cached__', '__doc__', '__file__', 
                 '__loader__', '__name__', '__package__', '__spec__', 
                 'math', 'mysq']
b.py: leaving b.py...
a.py: imported * from b
a.py: 2nd dir()=['__builtins__', '__cached__', '__doc__', '__file__', 
                 '__loader__', '__name__', '__package__', '__spec__', 
                 'math', 'mysq'] # NOTICE: math is not imported twice into 'a'
a.py: angle has been defined
a.py: 3rd dir()=['__builtins__', '__cached__', '__doc__', '__file__', 
                 '__loader__', '__name__', '__package__', '__spec__', 
                 'angle', 'math', 'mysq']
a.py: dir(b)=['__builtins__', '__cached__', '__doc__', '__file__',
              '__loader__', '__name__', '__package__', '__spec__',
              'math', 'mysq'] # just to make sure, check that 'b' still has 'math' defined.
>>> a.angle(7,8)
0.8519663271732721

So, you can fix your code by importing * from a into b and from b into a. You cannot import a package xxx and b into a and expect b to magically learn about xxx. For instance, b is not aware of a when b is imported into a just like math has no clue that it was imported into a and it (math) cannot "learn" what other packages were imported into a when a imported math.

By the way, you can easily break the fixed version 1b again by switching the order of imports in a.py:

file 'a.py':

from b import * # swap order of imports breaks Version 1b!
import math
AGN Gazer
  • 8,025
  • 2
  • 27
  • 45
  • `import math` should not be there in `b.py` – vks Jul 20 '17 at 05:30
  • @vks OK, I fixed my experiment to match your situation. – AGN Gazer Jul 20 '17 at 05:50
  • we have `xxx` in `a`'s namespace...now we call some function of `b` from `a`'s namespace....dont you thing that function would have info about `a`'s namespace? – vks Jul 20 '17 at 05:54
  • @vks I have significantly expanded my examples with numerous `print` statements. It also shows that you can fix your code by importing * from A into B and by importing * from B into A. – AGN Gazer Jul 20 '17 at 08:09
  • @vks It's ok even if you did not up-vote but I am happy you did. Thanks! I just hope this exercise hoped to elucidate the situation about imports. It was a good learning for me. However, I cannot imagine how did `b.fun()` work before assuming `b.py` is a legacy code that you have to deal with now. – AGN Gazer Jul 20 '17 at 08:24
  • I imported `b` so i used `b.fun` that way....new learning for me as well...oh i can add functions to `b` but cant change much...if i import `a` into it the dependencies will increase for any one using just `b`. – vks Jul 20 '17 at 08:25
1

Based on my experimentation in my previous answer and with some information from How to get a reference to current module's attributes in Python, I came up with a solution that actually may fix your problem with imports. All the changes are made exclusively to the file a.py and b.py is not touched.

Solution 1:

# in file a.py do this
import xxx
import sys # OR import b (see below)
from b import *
b = sys.modules[fun.__module__] # alternatively, "import b" and drop "import sys" above
# "inject" 'xxx' into 'b':
b.__dict__['xxx'] = globals()['xxx']

Solution 2:

# in file a.py do this
import xxx
import sys
from b import *
b = sys.modules[fun.__module__] # alternatively, "import b"
# "inject" 'xxx' into 'b':
b.__dict__['xxx'] = sys.modules[__name__].__dict__['xxx']

EXAMPLE:

file a.py:

import math # my version of 'xxx'
import sys
from b import *
b = sys.modules[mysq.__module__] # mysq is a function defined in b.py
b.__dict__['math'] = globals()['math']
def angle(x, y):
    return math.acos(x / mysq(x*x + y*y))

file b.py:

def mysq(x):
    return math.sqrt(x)

Run:

>>> import a
>>> a.angle(7, 8)
0.8519663271732721
AGN Gazer
  • 8,025
  • 2
  • 27
  • 45
0

You can import xxx in b.py

If its name conflicts with another file you import in b, do this:

import xxx as some_name

and within b.py you can now refer to it as some_name, i.e.,

some_name.run()
Julian Chan
  • 446
  • 2
  • 8
  • No its not a conflict of name.its a conflict between grequests which patches all sockets and multiprocess which does not want patched sockets – vks Jul 20 '17 at 05:27
  • @vks I have not much experience using grequests and multiprocess, but I think your issue is more of abstraction then? Your code in b.py could probably be written better so that you can choose to use either grequests or unpatched sockets for multiprocess, instead of tightly coupling it with grequests? – Julian Chan Jul 20 '17 at 05:50
0

a.py:

import numpy as np_patched
def f():
    print("patched")
np_patched.array = f

b.py

import a as np_patched
import numpy as np
np.array()

c.py (order of import doesn't matter?)

import numpy as np
import a as np_patched
np.array()

Result (python3 b.py, or python3 c.py)

patched

Explanation:

a.py import library X (numpy) and monkey patches X. Then, b.py imports a.py. At this point, X is not directly visible to b.py. After that b.py imports X. Python won't import the same thing twice, so it goes on and uses the X patched in a.py for b.py instead of importing a new copy of X for b.py. That is why b.py only gets the patched X, but not the original X.

hamster on wheels
  • 2,771
  • 17
  • 50