我有以下情况,我不了解,也许您可以指出答案或向我解释。
我具有以下python文件结构:
project/
-folder_a/
-File_a
-folder_b/
-File_b
File_a正在导入File_b。 File_a是主文件,但是如果我这样调用它,我只能从项目文件夹中运行它。
python < folder_a/File_a
否则,我将收到无法导入File_b的导入错误。我知道“ <”符号是stdin的重新定义,但是它对python解释器有什么作用,为什么它只能以这种方式工作。
非常感谢, 化妆
答案 0 :(得分:1)
Python可以通过几种不同的方式运行代码:您可以给它提供运行脚本,使用-m
的模块或使用-c
的命令。但是,如果您不输入任何内容,它将读取标准输入并一次执行一条语句,直到EOF。
您习惯使用交互式解释器来查看此内容:
$ python
Python 2.7.10 (default, Oct 6 2017, 22:29:07)
[GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.31)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> print('hello')
hello
>>> ^D
$
它读取print('hello')
与标准输入不符并执行它。然后它将ctrl-D读为EOF并退出。
如果标准输入不是交互式控制台(实际上是if not sys.stdin.isatty():
),则它不会打印横幅,显示>>>
提示,启用readline
命令行编辑,等等。但是它仍会一一读取并执行语句,直到EOF。
执行python < something.py
时,您的外壳程序将文件something.py
输送到Python的标准输入中。由于该文件不是交互式控制台,因此Python不会完成所有交互式工作。它只是从脚本中读取并执行语句。
这类似于运行python something.py
,但不相同。
最大的区别是Python不知道您要给它什么脚本。它只能看到文件的内容,而不能看到文件名或其他任何内容,它甚至不能说出它们是来自文件,而不是例如来自另一个程序的管道。 / p>
如果您查看sys.path
的工作原理:
在程序启动时初始化,此列表的第一项
path[0]
是包含用于调用Python解释器的脚本的目录。如果脚本目录不可用(例如,如果解释器是交互式调用的,或者从标准输入中读取了脚本),则path[0]
是空字符串,它会引导Python首先在当前目录中搜索模块。>
因此,实际上,python folder_a/File_a.py
将./folder_a
放在sys.path
上,而python < folder_a/File_a.py
将.
放在sys.path
上。
这确实不是解决您问题的好方法,但不能解释为什么大多数情况下都能正常工作。
一个更好的解决方案是重新组织代码,以便您拥有要导入的模块的完整程序包,然后是要在这些程序包之外运行的所有顶级脚本。像这样:
project/
script.py
-pkg_a/
-__init__.py
-module_a.py
-pkg_b/
-__init__.py
-module_b.py
这些__init__.py
文件实际上在Python 3中不是必需的,但是它们(向Python解释器和您的读者)都发出信号,它们是“普通包”(与名称空间包或目录相对)根本不是软件包。
现在,script.py
可以import
并从module_a.py
运行代码,就像其他任何Python代码一样。例如,代替此:
# pkg_a/module_a.py
print('hello')
…执行此操作:
# pkg_a/module_a.py
def run():
print('hello')
# script.py
from pkg_a.module_a import run
run()
如果您打算使用setuptools
通过pip
安装代码,则可以走得更远-将pkg_a.module_a.run
指定为“入口点”,并指定pip
将为您创建script.py
,确保其可执行,为用户的特定Python设置shbang行,将其安装在用户路径上的某个位置,等等。
如果设计方面的某些事情使将“脚本”代码从模块中移出并移到单独的脚本中是不可能的或不适当的,则始终可以将其作为模块运行,就像处理模块中的代码一样。 stdlib:
$ python -m pip install spam
<installs the spam package>
$ echo '[{"dense":"json"}]' | python -m json.tool
[
{
"dense": "json"
}
]
$ python -m pkg_a.module_a
<runs the code in pkg_a/module_a.py as a module>