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.