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()是subwayclock.subwayclock中的一个函数):
from subwayclock.subwayclock import *
print(rawFEED())
However, I cannot run the script directly i.e.
但是,我不能直接运行脚本,即
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 (i.e. with the leading '.' removed):
但是,如果我在subwayclock / subwayclock.py中将import语句修改为state(即删除了前导'。'):
from subwayclock.subwayclock import FeedMessage
I can run the subwayclock.py script directly through the command line, calling the main function perfectly.
我可以直接通过命令行运行subwayclock.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文件时,import语句不再有效,我收到以下错误:
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?
我可以使这个脚本独立运行并可导入吗?
3 个解决方案
#1
0
You can run a script from a package using the -m
switch and the fully qualified package path
您可以使用-m开关和完全限定的包路径从包中运行脚本
python -m subwayclock.subwayclock
#2
0
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)
(你也可以使用开发模式,这样你仍然可以使用它)
$ python setup.py develop
And you will be able to run that command line script
您将能够运行该命令行脚本
$ subwayclock_script_name
#3
0
I will try to describe you, how it works and, also, to help.
我将尝试描述你,它是如何工作的,并且还要帮助你。
Relative import
First of all, python has a number of different methods to import some. Some of them is a relative import (from .package import somemodule
)
The dot means that we want to import a somemodule
from the current package. 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.)
首先,python有许多不同的方法可以导入一些。其中一些是相对导入(来自.package import somemodule)点表示我们要从当前包导入somemodule。这意味着我们应该声明我们的包(当我们导入这个模块时,我们从包中导入它,它有一个名字等)
Absolute import(maybe there is another name)
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是变量。如果你想了解更多,请阅读文档。
Solution
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.
Or you can add your package directory to a PYTHONPATH
variable. See the good answer to the nearly the same question.
你也可以在简单的情况下运行python -m package.module.function,但它不是一个好主意。或者您可以将包目录添加到PYTHONPATH变量。看到几乎相同问题的好答案。
#1
0
You can run a script from a package using the -m
switch and the fully qualified package path
您可以使用-m开关和完全限定的包路径从包中运行脚本
python -m subwayclock.subwayclock
#2
0
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)
(你也可以使用开发模式,这样你仍然可以使用它)
$ python setup.py develop
And you will be able to run that command line script
您将能够运行该命令行脚本
$ subwayclock_script_name
#3
0
I will try to describe you, how it works and, also, to help.
我将尝试描述你,它是如何工作的,并且还要帮助你。
Relative import
First of all, python has a number of different methods to import some. Some of them is a relative import (from .package import somemodule
)
The dot means that we want to import a somemodule
from the current package. 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.)
首先,python有许多不同的方法可以导入一些。其中一些是相对导入(来自.package import somemodule)点表示我们要从当前包导入somemodule。这意味着我们应该声明我们的包(当我们导入这个模块时,我们从包中导入它,它有一个名字等)
Absolute import(maybe there is another name)
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是变量。如果你想了解更多,请阅读文档。
Solution
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.
Or you can add your package directory to a PYTHONPATH
variable. See the good answer to the nearly the same question.
你也可以在简单的情况下运行python -m package.module.function,但它不是一个好主意。或者您可以将包目录添加到PYTHONPATH变量。看到几乎相同问题的好答案。