简体   繁体   English

Python:如何从 package 中导入 function,这取决于 ZEFE8B70A8E6034A787 中的其他功能?

[英]Python: How to import a function from a package that depends on other functions in that package?

Consider the following scenario:考虑以下场景:

test_setup/
├── __init__.py
├── helper.py
└── main.py

helper.py is: helper.py是:

def helper_func():
    print('helping')

main.py is: main.py是:

from helper import helper_func

def main_func():
    helper_func()

if __name__ == '__main__':
    main_func()

__init__.py is: __init__.py是:

from .main import main_func

I would like to be able to do two things:我希望能够做两件事:

1.run main from within the package. 1.从 package 内部运行main This works.这行得通。

2.import main_func for use outside this package. 2.import main_func以供在此 package 之外使用。 This doesn't work.这行不通。 When called from the parent directory of test_setup , from test_setup import main_func yields:当从test_setup的父目录调用时, from test_setup import main_func产生:

In [1]: from test_setup import main_func
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
<ipython-input-1-c395483f58c8> in <module>
----> 1 from test_setup import main_func

~/PycharmProjects/test_setup/__init__.py in <module>
      1 #from .helper import helper_func
----> 2 from .main import main_func

~/PycharmProjects/test_setup/main.py in <module>
----> 1 from helper import helper_func
      2 
      3 def main_func():
      4     helper_func()
      5 

ModuleNotFoundError: No module named 'helper'

If I change the first line in main.py to a relative import from.helper import helper_func that works, but fails when I just try to run from within the package (goal 1 above) yielding:如果我将main.py中的第一行更改为可以工作的相对 import from.helper import helper_func ,但是当我尝试从 package (上述目标 1)中运行时失败,则产生:

Traceback (most recent call last):
  File "/Users/xxx/PycharmProjects/test_setup/main.py", line 1, in <module>
    from .helper import helper_func
ImportError: attempted relative import with no known parent package

What's going on here, and how do I fix things to achieve goals 1 and 2?这是怎么回事,我该如何解决问题以实现目标 1 和 2? Trying to import helper_func in __init__.py didn't help either.尝试在__init__.py中导入helper_func也无济于事。 The following failed as well:以下也失败了:

In [1]: from test_setup.main import main_func
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
<ipython-input-1-764832db473f> in <module>
----> 1 from test_setup.main import main_func

~/PycharmProjects/test_setup/__init__.py in <module>
----> 1 from .main import main_func

~/PycharmProjects/test_setup/main.py in <module>
----> 1 from helper import helper_func
      2 
      3 def main_func():
      4     helper_func()
      5 

ModuleNotFoundError: No module named 'helper'

It should be: from test_setup.main import main_func to import the function directly.应该是: from test_setup.main import main_func main_func 直接导入function。 However, you can use it from the module.但是,您可以从模块中使用它。

import test_setup

test_setup.main_func()

On the edit, you have missed a .在编辑时,您错过了一个. on from.helper import helper_func to indicate a relative import.from.helper import helper_func上表示相对导入。

On further look at the goal 1 problem and this great post you should read , Guido himself advises against running scripts within module, rather than as a module.在进一步查看目标 1 问题和您应该阅读的这篇精彩文章时,Guido 本人建议不要在模块中运行脚本,而不是作为模块运行。

The import docs say: 导入文档说:

Note that relative imports are based on the name of the current module.请注意,相对导入基于当前模块的名称。 Since the name of the main module is always " main ", modules intended for use as the main module of a Python application must always use absolute imports.由于主模块的名称始终为“ main ”,因此用作 Python 应用程序的主模块的模块必须始终使用绝对导入。

This means scripts (things you would run independently from the package) should not be ran from within, if possible.这意味着如果可能的话,不应从内部运行脚本(您将独立于包运行的东西)。 If you need to keep the current structure, you can run the main.py file as a module using python -m test_setup.main which will work with relative imports.如果您需要保留当前结构,您可以使用python -m test_setup.main将 main.py 文件作为模块运行,这将与相对导入一起使用。

Another option is adding the parent to test_setup folder to PYTHONPATH which will allow absolute imports such as test_setup.main.main_func from anywhere, although there are good threads suggesting you should use the proper development tools when building a package.另一种选择是将父级添加到test_setup文件夹到 PYTHONPATH,这将允许从任何地方进行绝对导入,例如test_setup.main.main_func ,尽管有很好的线程建议您在构建 package 时应该使用适当的开发工具

Don't know which version you are working with, but this may help you...不知道您使用的是哪个版本,但这可能会对您有所帮助...

__init__.py : __init__.py

# 1. run main from within the package

# Python2
'''
>>> from main import main_func
main: from helper import helper_func
>>> main_func()
helping
'''

# Python3
'''
>>> from main import main_func
main: from helper import helper_func
>>> main_func()
helping
'''

# XXX: Notice that both of the above are the same
# However, note the differences below

# 2. import main_func for use outside this package

# Python2
'''
>>> from test_setup import main_func
test_setup.main: from helper import helper_func
test_setup: from main import main_func
>>> main_func()
helping
'''

# Python3
'''
>>> from test_setup import main_func
# Failed
ImportError:0 No module named 'main' in module test_setup
ImportError:0 No module named 'helper' in module test_setup.main
# Succeeded
test_setup.main: from .helper import helper_func
test_setup: from .main import main_func
>>> main_func()
helping
'''

try:
    from main import main_func
    print("%s: from main import main_func"%(__name__))
except ImportError as exc:
    print("ImportError:0 %s in module %s"%(exc,__name__))
    try:
        from .main import main_func
        print("%s: from .main import main_func"%(__name__))
    except ImportError as exc:
        print("ImportError:1 %s in module %s"%(exc,__name__))
        from test_setup.main import main_func
        print("%s: from test_setup.main import main_func"%(__name__))

main.py : main.py

try:
    from helper import helper_func
    print("%s: from helper import helper_func"%(__name__))
except ImportError as exc:
    print("ImportError:0 %s in module %s"%(exc,__name__))
    try:
        from .helper import helper_func
        print("%s: from .helper import helper_func"%(__name__))
    except ImportError as exc:
        print("ImportError:1 %s in module %s"%(exc,__name__))
        from test_setup.helper import helper_func
        print("%s from test_setup.helper import helper_func"%(__name__))


def main_func():
    helper_func()

if __name__ == '__main__':
    main_func()

Edited for clarification:为澄清而编辑:

__init__.py : __init__.py

"""Init for main module"""

print("__init__.__doc__ = %s"%(__doc__))

# -----------------------------------------------------------------------------
from os import path
import sys

print("sys.executable = %s"%(sys.executable))
print("sys.argv[0] = %s"%(sys.argv[0]))

main_prg_path = path.abspath(path.dirname(__file__))
print("main_prg_path = %s"%(main_prg_path))

if getattr(sys, 'frozen', False):
    # When being bundled by pyinstaller, paths are different
    print("Running as pyinstaller bundle!", sys.argv[0])
    main_prg_path = path.abspath(path.dirname(sys.argv[0]))

sys.path.append(main_prg_path)
print("main_prg_path = %s"%(main_prg_path))
# Append other directories needed for main program
#sys.path.append(os.path.join(main_prg_path, 'utils'))

# -----------------------------------------------------------------------------
from main import main_func

main.py : main.py

"""Main module"""

print("main.__doc__ = %s"%(__doc__))

# -----------------------------------------------------------------------------
# Running in python
# inside:  from main import main_func
# outside: from test_setup import main_func

# Running in terminal
# inside:  python -m main
# outside: python -m test_setup/main
# -----------------------------------------------------------------------------
from os import path
import sys

print("sys.executable = %s"%(sys.executable))
print("sys.argv[0] = %s"%(sys.argv[0]))

main_prg_path = path.abspath(path.dirname(__file__))
print("main_prg_path = %s"%(main_prg_path))

if getattr(sys, 'frozen', False):
    # When being bundled by pyinstaller, paths are different
    print("Running as pyinstaller bundle!", sys.argv[0])
    main_prg_path = path.abspath(path.dirname(sys.argv[0]))

sys.path.append(main_prg_path)
print("main_prg_path = %s"%(main_prg_path))
# Append other directories needed for main program
#sys.path.append(os.path.join(main_prg_path, 'utils'))

# -----------------------------------------------------------------------------
from helper import helper_func


def main_func():
    helper_func()

# -----------------------------------------------------------------------------
if __name__ == '__main__':
    print("running as main: %s"%(__name__))
    main_func()
else:
    print("running as file: %s"%(__file__))
    main_func()

helper.py : helper.py

"""Helper module"""

print("helper.__doc__ = %s"%(__doc__))

__author__ = "Your Name"
__author_email__ = "Your Email"
__version__ = "0.0.1"
__date__ = "24 Jan 2021"

def helper_func():
    print("Author = %s\nEmail = %s\nVersion = %s\nDate = %s"%(
        __author__, __author_email__, __version__, __date__))

@rhz EDIT: Added changes to show what is happening and simple usage example of sys.path.append @rhz 编辑:添加更改以显示正在发生的事情和sys.path.append的简单用法示例

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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