简体   繁体   中英

Problems when importing in Python 3.x

my problem can be summarized as follows.

I have the following files structure:

<path>/
- a.py
<path>/subdir/
- b.py
- c.py

The relation is that a imports b and b imports c (a->b->c).

More precisely, the content of each file is as follows:

  • c.py
def foo():
    print("Hello World!")
  • b.py
import c
def fie():
    c.foo()
    print("Second Hello World!")
if __name__=="__main__":
    fie()
  • a.py
from subdir import b
b.fie()

What I want is that invoking a.py will print those strings, namely:

$ python3 a.py
Hello World!
Second Hello World!
$ 

and invoking b.py from /subdir will print the same thing:

$ cd subdir
$ python3 b.py
Hello World!
Second Hello World!
$ 

Instead if I invoke a.py from <path> I have this:

$ python3 a.py
Traceback (most recent call last):
  File "a.py", line 1, in <module>
    from subdir import b
  File "<path>/subdir/b.py", line 1, in <module>
    import c
ModuleNotFoundError: No module named 'c'
$ 

if I, instead, invoke b.py from <path>/subdir I have the intended behavior:

$ cd subdir
$ python3 b.py
Hello World!
Second Hello World!
$ 

If I change b.py the following way:

  • b.py
from subdir import c
def fie():
    c.foo()
    print("Second Hello World!")
if __name__=="__main__":
    fie()

the invocation of a.py works as intended, but this time is the invocation of b.py that gives ModuleNotFoundError :

$ cd subdir
$ python3 b.py
Traceback (most recent call last):
  File "b.py", line 1, in <module>
    from subdir import c
ModuleNotFoundError: No module named 'subdir'
$ 

Strangely enough even this invocation from <path> gives the same error:

$ python3 subdir/b.py
Traceback (most recent call last):
  File "b.py", line 1, in <module>
    from subdir import c
ModuleNotFoundError: No module named 'subdir'
$ 

If I replace the following string in b.py:

from subdir import c

in

from . import c

I have exactly the same effect of the lastest test.

In the real case scenario both b and c are part of a library self-contained in subdir that is meant to be used both directly (with the if __name__ trick) and imported from anywhere else in order to use their functions. Said library can not be installed in a fixed space of the file system at this moment (or at least I shouldn't rely on that).

I never had such problems when working with Python 2.6 and I'm recently migrating to Python 3.x. Reading the python 3.x guide to importing was helpful but I didn't find any useful information to solve this case which should be pretty basic (which is why I'm thinking that I've omitted something trivial there).

Can you suggest a way to change any of [a,b,c].py files to cover this use case?

I kepy my directory structure like this: Directory of C:\\Users\\G1\\Desktop\\Test

30-06-2019  01:17                   a.py
30-06-2019  01:17    <DIR>          path/

 Directory of C:\Users\G1\Desktop\Test\path

30-06-2019  01:18                b.py
30-06-2019  01:15                c.py

a.py

import sys
**sys.path.append("path")**
from path import b
b.fie()

b.py

import c
def fie():
    c.foo()
    print("Second Hello World!")
if __name__=="__main__":
    fie()

c.py

def foo():
    print("Hello World!")

outputs:

C:\Users\G1\Desktop\Test>python a.py
Hello World!
Second Hello World!

C:\Users\G1\Desktop\Test>python path\b.py
Hello World!
Second Hello World!

You have to append the path of module c.py

Above code is tested in python3 and python2 also.

The following works for me (under Windows at least).

Start your main program by calling addpath giving as parameter the directory (as string) or directories (as list of strings) that you want your app to have access to:

def addpath(dirs):
  import sys,os
  my_path = '/'.join(os.path.abspath(sys.argv[0]).replace('\\','/').split('/')[:-1])+'/'
  if type(dirs) is str:
    sys.path.append(my_path+dirs)
  elif type(dirs) is list:
    for dir in dirs:
      sys.path.append(my_path+dir)

################################################################################

addpath('subdir')  #or addpath(['subdir1',...])

from subdir import b
b.fie()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM