[英]How can I make a python file runnable as a script and importable as a package?
I'm still trying to get a hang of python 3 and I'm running into an issue where I can either run a .py file as a script or import it as a module, but not both. 我仍然想摆脱python 3的困扰,遇到了一个问题,我可以将.py文件作为脚本运行,也可以将其作为模块导入,但不能同时使用。
Directory Structure 目录结构
test/
__init__.py
test.py
subwayclock/
__init__.py
subwayclock.py
build/
gen/
__init__.py
gtfs_realtime_pb2.py
nyct_subway_pb2.py
__init__.py
in this scenario test.py looks like this and works (rawFEED() is a function in subwayclock.subwayclock): 在这种情况下,test.py看起来像这样并且可以工作(rawFEED()是metroclock.subwayclock中的一个函数):
from subwayclock.subwayclock import *
print(rawFEED())
However, I cannot run the script directly ie 但是,我不能直接运行脚本,即
python subwayclock/subwayclock.py
because it gives the following error: 因为它给出以下错误:
Traceback (most recent call last):
File "subwayclock.py", line 32, in <module>
from .build.gen.gtfs_realtime_pb2 import FeedMessage
SystemError: Parent module '' not loaded, cannot perform relative import
HOWEVER, if I modify the import statement in subwayclock/subwayclock.py to state (ie with the leading '.' removed): 但是,如果我将metroclock / subwayclock.py中的import语句修改为状态(即删除了前导“。”):
from subwayclock.subwayclock import FeedMessage
I can run the subwayclock.py script directly through the command line, calling the main function perfectly. 我可以直接通过命令行运行metroclock.py脚本,完美调用main函数。
BUT, when I run the original test.py file, the import statement no longer works, and I get the following error: 但是,当我运行原始的test.py文件时,导入语句不再起作用,并且出现以下错误:
Traceback (most recent call last):
File "test.py", line 1, in <module>
from subwayclock.subwayclock import *
File "/var/www/test/subwayclock/subwayclock.py", line 32, in <module>
from build.gen.gtfs_realtime_pb2 import FeedMessage
ImportError: No module named 'build'
Can I make this script independently runnable and importable? 我可以使该脚本独立运行和导入吗?
您可以使用-m
开关和标准软件包路径从软件包中运行脚本。
python -m subwayclock.subwayclock
In this case, you could just use absolute imports instead of relative imports , but depending on the dependencies between your modules, it could result in some odd behavior, where objects and classes are technically being defined twice (once in your __main__
script, and once when another module imports your module) 在这种情况下,您可以只使用绝对导入而不是相对导入 ,但是根据模块之间的依赖关系,这可能会导致某些奇怪的行为,技术上对象和类在技术上定义了两次(一次在
__main__
脚本中定义一次,一次当另一个模块导入您的模块时)
The proper way to do this would be to create a proper python package with a setup.py
script and use the console_scripts
entry point feature to expose a function as a command line script. 正确的方法是使用
setup.py
脚本创建适当的python包,并使用console_scripts
入口点功能将函数作为命令行脚本公开。
Your project should be organized something like this. 您的项目应按以下方式组织。
/subwayclock
/subwayclock
__init__.py
subwayclock.py
...
setup.py
Your setup.py would look like this 您的setup.py看起来像这样
from setuptools import setup, find_packages
setup(name='subwayclock',
version='0.1',
packages=find_packages(),
zip_safe=False,
entry_points = {
'console_scripts': ['subwayclock_script_name=subwayclock.subwayclock:rawFEED'],
}
)
Then you just install the package 然后您只需安装软件包
$ python setup.py install
(you can also use develop
mode so you can still work on it) (您也可以使用
develop
模式,因此仍可以进行develop
)
$ python setup.py develop
And you will be able to run that command line script 您将能够运行该命令行脚本
$ subwayclock_script_name
I will try to describe you, how it works and, also, to help. 我将尽力描述您的工作方式,并为您提供帮助。
First of all, python has a number of different methods to import some. 首先,python有多种导入方法。 Some of them is a relative import (
from .package import somemodule
) 其中一些是相对导入(
from .package import somemodule
)
The dot means that we want to import a somemodule
from the current package. 点表示我们要从当前包中导入
somemodule
。 That means that we should declare our package(when we import this module, we import it from the package , which has a name and etc.) 这意味着我们应该声明我们的包(当我们导入该模块时,我们从具有名称等的包中导入它)。
This import is used nearly everywhere in simple scripts and you must know this. 在简单的脚本中,几乎在所有地方都使用此导入,您必须知道这一点。
Example: 例:
from app import db
Where app
is a python module( app.py
file) and db
is a variable in it.If you want to know more, read the docs . 其中
app
是python模块( app.py
文件), db
是其中的变量。如果您想了解更多信息,请阅读docs 。
I don't really know a pretty way to avoid this, but if I were you, I would do like this: 我真的不知道一种避免这种情况的好方法,但是如果我是你,我会这样做:
if __name__ == '__main__':
from mypackage.module import function
else:
from .module import function
Also you can run python -m package.module.function
in simple cases, but it's not quiet a good idea. 您也可以在简单的情况下运行
python -m package.module.function
,但这并不是一个好主意。
Or you can add your package directory to a PYTHONPATH
variable. 或者,您可以将包目录添加到
PYTHONPATH
变量。 See the good answer to the nearly the same question. 看到几乎相同的问题的好答案 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.