ValueError: attempted relative import beyond top-level package

前端 未结 3 1753
情书的邮戳
情书的邮戳 2020-12-24 10:46

I was playing the the Python\'s import system in order to understand better how it works, and I encountered another problem. I have the following structure

         


        
相关标签:
3条回答
  • 2020-12-24 11:29

    Python 3 changed the import system so every time you want a module that is around the one you are working, you need relative imports (unless you mess with PYTHONPATH or sys.path).

    The correct usage here should be

    from .subpkg import a
    

    When you are working with IDLE, you have a totally different environment. Therefore, you could add the current location to your path so imports work again.

    try:

    sys.path.insert(0, '')
    

    It might be weird, but it is for a greater good

    PS: If this last thing do not work -- I don't have an IDLE environment right now -- it is probably because the work directory is set wrong.

    Try this answer instead: https://stackoverflow.com/a/17361545/754991

    0 讨论(0)
  • 2020-12-24 11:41

    I found this solution:

    #! /usr/bin/env python
    import os
    import sys
    sys.path.append(os.path.realpath('.'))
    from d import *
    
    0 讨论(0)
  • 2020-12-24 11:48

    This had me question my insanity.

    The problem stems from the confusion that people mistakenly take the relative import as path relative which is not.

    Relative imports depend on the location of the file that is run.

    This answer goes deeper into explaining how the python modules actually work, but to summarize.

    1. When a file is loaded, it is given a name:
      • If it was loaded as the top-level script (run directly), its name is __main__.
      • If it was loaded as a module (with import), its name is the filename, preceded by the names of any packages/subpackages of which it is a part, separated by dots - pkg.subpkg.a
    2. If you do a from .. there must be at least 2 dots in the file name. from ... - 3 dots.

    Now comes the funny part.

    If you run c.py directly, then it is given the name __main__ and a.py has subpkg.a.

    As per the 2nd statement, you must have at least 2 dots in the name of subpkg.a to run from .. inside it.

    The fix

    Create a new file outside the pkg, say main.py

    pkg/
        __init__.py
        c.py
        d.py
    
        subpkg/
            __init__.py
            a.py
            b.py
    main.py
    

    Inside main.py

    import pkg.c
    

    If we run main.py, it get's the name __main__, and a.py get's pkg.subpkg.a. As per the 2nd statement it now has 2 dots in the name and we can do the from ..

    One more thing. Now that c.py is loaded as a module, we have to use from to load a.py.

    from .subpkg import a
    
    0 讨论(0)
提交回复
热议问题