我有一个像这样的目录结构:
Package/
setup.py
src/
__init__.py
__main__.py
code.py
我希望能够以很多不同的方式运行代码。
pip install Package
然后python
然后from Package import *
python -m Package
应该__main__.py
python __main__.py
也应该在__main__.py
中执行此操作,但这一次,我们假设您已下载了源而不是pip installing
。
现在我已经让前两个工作了,但设置很乱:
setup.py:
setup(
name='Package',
packages=['Package'],
package_dir={'Package': 'src'},
...
entry_points={ 'console_scripts': ['Package = src.__main__:main' ] }
__ INIT __ PY:
from Package.code import .......
__主__ PY:
from . import .......
对我来说更有意义的是在两种情况下写
from code import ........
但是这给了我导入错误。
我的方式真的是唯一的方法吗?
最重要的是,我如何支持第三个用例?现在,python __main__.py
抛出
File "__main__.py", line 10, in <module>
from . import code
ImportError: cannot import name 'class defined in code.py'
我已阅读
答案 0 :(得分:24)
你几乎拥有所需的一切(甚至更多)!我将采用以下设置:
<强> code.py 强>:
foo = 1
<强> __ INIT __ PY:强>
from .code import foo
在此处执行相对导入,因为导入整个包时将使用__init__.py
。请注意,我们使用.
语法将导入显式标记为相对,因为这是Python 3所必需的(如果您from __future__ import absolute_import
,则需要在Python 2中。)
<强> __主__ PY:强>
from Package import foo
print('foo = ', foo)
这是包的主脚本,因此我们使用绝对import
语句。通过这样做,我们假设已经安装了包(或者至少已经放在路径上);这就是应该处理包裹的方式!您可能认为这与您的第三个用例冲突,但实际上在处理包时没有理由不到pip install
。这真的不是什么大问题(特别是在使用virtualenv
时)!
如果您需要修改源文件并通过运行__main__.py
文件轻松观察更改,那么您只需使用-e
(&#34;可编辑的&#34; )switch:pip install -e .
(假设你在目录Package
中)。但是,使用当前的目录结构,这不会起作用,因为-e
开关会将egg-link
放置到包含setup.py
文件的目录中;此目录不包含名为Package
的包,而是包含src
的包(我有a question about that)。
相反,如果您按照约定在包本身之后命名包源的根目录(对于您的示例是Package
),那么使用-e
进行安装不是问题:Python 在相应的目录中找到所需的包Package
:
$ tree Package/
Package/
├── setup.py
└── Package <-- Renamed "src" to "Package" because that's the package's name.
├── code.py
├── __init__.py
└── __main__.py
这也可以省略package_dir={'Package': 'src'}
中setup.py
的额外定义。
关于setup.py
的说明:对于您指定的三个用例,无需定义入口点。那就是你可以跳过entry_points={ 'console_scripts': ['Package = src.__main__:main' ] }
行。通过发运__main__.py
模块python -m Package
,可以轻松执行此模块中的代码。您还可以添加额外的if子句:
def main():
print('foo = ', foo)
if __name__ == '__main__':
main()
另一方面,入口点允许您直接从CLI执行__main__.main
中的代码;正在运行的$ Package
将执行相应的代码。
最重要的是,在处理软件包时,我总是使用pip install
。为什么不,特别是如果您已经创建了setup.py
文件?如果要对包裹进行实时修改&#34;实时&#34;然后你可以用-e
开关安装(这可能需要重命名src
文件夹,见上文)。因此,您的第三个用例将读作&#34;下载源代码和pip install (-e) Package
(在virtualenv中);然后你可以运行python __main__.py
&#34;。
__main__.py
pip install
如果您不想通过pip安装软件包但仍然可以运行__main__.py
脚本,我仍然可以使用上述设置。然后我们需要确保from Package import ...
语句仍然成功,这可以通过扩展导入路径来实现(请注意,这需要将src
目录重命名为包&# 39;名字!)。
PYTHONPATH
对于Linux bash,您可以按如下方式设置Pythonpath:
export PYTHONPATH=$PYTHONPATH:/path/to/Package
或者,如果您与__main__.py
位于同一目录中:
export PYTHONPATH=$PYTHONPATH:`cd ..; pwd`
当然,不同的操作系统有不同的方式。
__main__.py
您(或者更确切地说是您的同事)可以将以下行添加到脚本的顶部(from Package import ...
语句之前):
import sys
sys.path.append('/path/to/Package')
sitecustomize.py
您可以将名为sitecustomize.py
的模块放在Python安装的lib/python3.5/site-packages/
目录中,其中包含以下行:
import sys
sys.path.append('/path/to/Package')
main.py
脚本所以你有以下布局:
$ tree Package/
Package/
├── main.py <-- Add this file.
├── setup.py
└── src
├── code.py
├── __init__.py
└── __main__.py
main.py
包含
import src.__main__
现在__main__.py
被视为src
包的一部分,相对导入将起作用。
您现在可以运行python src/__main__.py
而不是python main.py
。
答案 1 :(得分:2)
from code import .........
失败,因为您的系统上没有安装名为code
的Python包。您的系统上有一个名为code
的Python 模块,但是在您的import语句中,您没有指定可以找到code
模块的包。
__init__.py
中的src/
文件的目的告诉Python src/
目录应该被视为Python包,其内容作为包中的模块。由于code.py
与src/
文件一起位于__init__.py
,因此您的code
模块位于src
包中。
现在您知道可以找到code
模块的哪个包,您可以通过以下方式从中导入内容:
from src.code import .........
另外,作为旁注:__init__.py
仅通过出现在src/
目录中完成其工作,因此它甚至不需要包含任何代码。因此,将__init__.py
文件留空是个好主意。
答案 2 :(得分:0)
我经常使用此设置,因为它适用于python setup.py develop
Package_root/
setup.py
src/
Package/
__init__.py
__main__.py
code.py
这可能不是(还)你想要的详细答案,但我认为值得尝试这三个用例。
setup( ...
package_dir = {'': 'src'},
entry_points = {'console_scripts': ['Package = Package.__main__:main'],},
packages = find_packages(exclude=["Package.egg_info",]),
...)