Ale*_*ail 41 python pip setuptools
我有一个像这样的目录结构:
Package/
setup.py
src/
__init__.py
__main__.py
code.py
Run Code Online (Sandbox Code Playgroud)
我希望能够以很多不同的方式运行代码.
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' ] }
Run Code Online (Sandbox Code Playgroud)
__init__.py:
from Package.code import .......
Run Code Online (Sandbox Code Playgroud)
__main__.py:
from . import .......
Run Code Online (Sandbox Code Playgroud)
对我来说更有意义的是两种情况都要写
from code import ........
Run Code Online (Sandbox Code Playgroud)
但这给了我导入错误.
我的方式真的是唯一的方式吗?
最重要的是,我如何支持第三个用例?现在,python __main__.py
抛出
File "__main__.py", line 10, in <module>
from . import code
ImportError: cannot import name 'class defined in code.py'
Run Code Online (Sandbox Code Playgroud)
我读过了
a_g*_*est 30
你几乎拥有所需的一切(甚至更多)!我会使用以下设置:
code.py:
foo = 1
Run Code Online (Sandbox Code Playgroud)
__init__.py:
from .code import foo
Run Code Online (Sandbox Code Playgroud)
在这里进行相对导入因为__init__.py
将在导入整个包时使用.请注意,我们使用.
-syntax 将导入显式标记为相对,因为这是Python 3所必需的(如果你这样做,则在Python 2中from __future__ import absolute_import
).
__main__.py:
from Package import foo
print('foo = ', foo)
Run Code Online (Sandbox Code Playgroud)
这是包的主脚本,因此我们使用绝对import
语句.通过这样做,我们假设已经安装了包(或者至少已经放在路径上); 这就是应该处理包裹的方式!你可能会认为这与你的第三个用例的冲突,但实际上没有理由不来pip install
一个包的时候.这真的不是什么大问题(特别是在使用时virtualenv
)!
如果您需要修改源文件并通过运行__main__.py
文件轻松观察更改,那么您只需使用-e
("可编辑")开关安装软件包:( pip install -e .
假设您在目录中Package
).但是,使用当前的目录结构,这将无法工作,因为-e
交换机将放置一个egg-link
包含该setup.py
文件的目录; 这个目录不包含一个名为的包Package
,src
而是(我有一个问题).
相反,如果您按照约定在包本身之后命名包源的根目录(这是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
Run Code Online (Sandbox Code Playgroud)
这也让你省略了package_dir={'Package': 'src'}
in 的额外定义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()
Run Code Online (Sandbox Code Playgroud)
另一方面,入口点允许您直接__main__.main
从CLI 执行代码; 正在运行的$ Package
将执行相应的代码.
最重要的是我pip install
在处理包时总是使用.为什么不,特别是如果你已经创建了一个setup.py
文件?如果要"实时"应用对程序包的更改,则可以使用该-e
开关进行安装(这可能需要重命名该src
文件夹,请参见上文).因此,您的第三个用例将显示为"下载源代码和pip install (-e) Package
(在virtualenv中);然后您可以运行python __main__.py
".
__main__.py
无pip install
如果你不想通过pip安装软件包但仍然能够运行__main__.py
脚本,我仍然会使用上面的设置.然后,我们需要确保的from Package import ...
声明(S)还在后面,这可以通过扩大进口路径来实现(注意,这需要src
重命名为软件包的名称目录!).
PYTHONPATH
对于Linux bash,您可以按如下方式设置Pythonpath:
export PYTHONPATH=$PYTHONPATH:/path/to/Package
Run Code Online (Sandbox Code Playgroud)
或者如果您在以下目录中__main__.py
:
export PYTHONPATH=$PYTHONPATH:`cd ..; pwd`
Run Code Online (Sandbox Code Playgroud)
当然,不同的操作系统有不同的方式.
__main__.py
您(或者更确切地说是您的同事)可以将以下行添加到脚本的顶部(在from Package import ...
语句之前):
import sys
sys.path.append('/path/to/Package')
Run Code Online (Sandbox Code Playgroud)
sitecustomize.py
您可以放置sitecustomize.py
在lib/python3.5/site-packages/
Python安装目录中命名的模块,该模块包含以下行:
import sys
sys.path.append('/path/to/Package')
Run Code Online (Sandbox Code Playgroud)
main.py
脚本所以你有以下布局:
$ tree Package/
Package/
??? main.py <-- Add this file.
??? setup.py
??? src
??? code.py
??? __init__.py
??? __main__.py
Run Code Online (Sandbox Code Playgroud)
哪里main.py
包含
import src.__main__
Run Code Online (Sandbox Code Playgroud)
现在__main__.py
被视为src
包的一部分,相对导入将起作用.而不是跑步,python src/__main__.py
你现在就跑python main.py
.