【问题标题】:What is a stdin redirect doing to the python interpreter什么是标准输入重定向到 python 解释器
【发布时间】:2018-08-13 17:41:01
【问题描述】:

我有以下情况我不明白,也许你可以指出答案或解释给我。

我的python文件结构结构如下:

project/ -folder_a/ -File_a -folder_b/ -File_b

File_a 正在导入 File_b。 File_a 是主文件,但如果我这样调用它,我只能从项目文件夹中运行它。

python < folder_a/File_a

否则我会收到无法导入 File_b 的导入错误。我知道“

非常感谢, 制作中

【问题讨论】:

  • project 是带有子包的包还是folder_afolder_b 是不同的包?你在任何地方都有__init__.py 文件吗?
  • 您正在做的是告诉 Python 将其标准输入解释为主脚本,然后将 folder_a/file_a 的内容作为该输入传递。
  • 您可能想要做的是(1)创建一个适当的 Python 项目,其中包含两个包和一个执行类似from folder_a.File_a import run; run() 的顶级脚本,或者( 2) 将模块作为带有python -m folder_a.File_a 的模块运行,而不是欺骗Python 认为它是一个脚本。

标签: python shell redirect import stdin


【解决方案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 时,您的shell 会将文件something.py 传送到Python 的标准输入中。由于该文件不是交互式控制台,因此 Python 不会执行所有交互式操作;它只是从脚本中读取并执行语句。


这类似于运行python something.py,但不完全相同。

最大的不同是 Python 不知道你给它的是什么脚本。它只能看到文件的内容,而不是文件名或其他任何内容,它甚至无法判断它们来自文件,而不是来自另一个程序的管道。

如果你看看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 行,将其安装在用户路径的某个位置,等等。


如果您的设计导致无法或不适合将“脚本”代码从模块中移出并放入单独的脚本中,您始终可以将其作为模块运行,就像在标准库:

$ 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>

【讨论】:

  • 非常感谢。这向我解释了很多。我会看看我(我们)可以改变什么,让它以正常的方式工作。
猜你喜欢
  • 2012-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多