为什么我不能使用 "from sys import stdout" 重定向 STDOUT?
Why can I not redirect STDOUT using "from sys import stdout"?
我正在尝试将 python 脚本的 STDOUT 重定向到文件。
如果 STDOUT 是从 sys 导入的,脚本的输出不会被重定向到一个文件:
from sys import stdout
stdout = open("text", "w")
print("Hello")
但是,如果我只导入 sys 并使用 sys.stdout,则脚本的输出成功重定向:
import sys
sys.stdout = open("text", "w")
print("Hello")
这是为什么?根据 this answer,"import X" 和 "from X import Y" 之间的唯一区别是绑定的名称。这如何影响标准输出?
是的,唯一的区别是名称 Y
绑定到 X.Y
。
无论如何,将 Y
绑定到其他内容不会影响 X
.
中的任何内容
如果它更容易,考虑这个平行:
>>> y = 2
>>> x = y
>>> x = 3
您希望这会将 y
更改为 3
吗?当然不是。但这与您正在做的完全一样。
如果还不清楚,让我们分解一下 import
的实际作用。
当你import sys
时,相当于:
sys.modules['sys'] = __import__('sys')
sys = sys.modules['sys']
sys.stdout = open(text, "w")
但是 from sys import stdout
:
sys.modules['sys'] = __import__('sys')
stdout = sys.modules['sys'].stdout
stdout = open(text, "w")
等于:
x = some_object.some_attr
x = open(...)
在这种情况下,您不会更改 some_object.some_attr
。您只是在分配本地值。
当您使用 sys.stdout = ...
时,您实际上是在更新标准输出。
通过这个小技巧,您可以节省一些精力并为自己赢得一些 "Pythonic" 积分:
import sys
print('hello', file=sys.stdout)
当然,默认情况下 print
已经转到 sys.stdout
,所以也许我遗漏了什么。我不确定 open('text', 'w')
发生了什么,但如果你这样做可能没有必要:)
在回答有关变量赋值影响的问题时,当您在变量上使用 =
运算符时,实际上是将其赋给范围字典中的值(在本例中 globals
).
因此,当您导入 sys
时,sys
会导入到 globals
字典中。
所以 globals
看起来像,
{...,
'sys': <module 'sys' (built-in)>}
你可以把模块本身想象成一本字典。所以当你做 sys.stdout=
时......就像做 globals()['sys'].__dict__['stdout'] =...
当您只导入 stdout
时,globals
看起来像:
{...,
'stdout': <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>}
因此,当您执行 stdout=...
时,您实际上是在直接替换字典中的那个键:
globals()['stdout'] = ...
希望这有助于增加一点清晰度!
我的方法是创建一个contextmanager。
@contextmanager
def suppress_stdout():
with open(os.devnull, 'w') as devnull:
old_stdout = sys.stdout
old_stderr = sys.stderr
sys.stdout = devnull
try:
yield
finally:
sys.stdout = old_stdout
sys.stderr = old_stderr
然后当我想抑制某个命令的标准输出时:
with suppress_stdout():
# suppressed commands
我正在尝试将 python 脚本的 STDOUT 重定向到文件。
如果 STDOUT 是从 sys 导入的,脚本的输出不会被重定向到一个文件:
from sys import stdout
stdout = open("text", "w")
print("Hello")
但是,如果我只导入 sys 并使用 sys.stdout,则脚本的输出成功重定向:
import sys
sys.stdout = open("text", "w")
print("Hello")
这是为什么?根据 this answer,"import X" 和 "from X import Y" 之间的唯一区别是绑定的名称。这如何影响标准输出?
是的,唯一的区别是名称 Y
绑定到 X.Y
。
无论如何,将 Y
绑定到其他内容不会影响 X
.
如果它更容易,考虑这个平行:
>>> y = 2
>>> x = y
>>> x = 3
您希望这会将 y
更改为 3
吗?当然不是。但这与您正在做的完全一样。
如果还不清楚,让我们分解一下 import
的实际作用。
当你import sys
时,相当于:
sys.modules['sys'] = __import__('sys')
sys = sys.modules['sys']
sys.stdout = open(text, "w")
但是 from sys import stdout
:
sys.modules['sys'] = __import__('sys')
stdout = sys.modules['sys'].stdout
stdout = open(text, "w")
等于:
x = some_object.some_attr
x = open(...)
在这种情况下,您不会更改 some_object.some_attr
。您只是在分配本地值。
当您使用 sys.stdout = ...
时,您实际上是在更新标准输出。
通过这个小技巧,您可以节省一些精力并为自己赢得一些 "Pythonic" 积分:
import sys
print('hello', file=sys.stdout)
当然,默认情况下 print
已经转到 sys.stdout
,所以也许我遗漏了什么。我不确定 open('text', 'w')
发生了什么,但如果你这样做可能没有必要:)
在回答有关变量赋值影响的问题时,当您在变量上使用 =
运算符时,实际上是将其赋给范围字典中的值(在本例中 globals
).
因此,当您导入 sys
时,sys
会导入到 globals
字典中。
所以 globals
看起来像,
{...,
'sys': <module 'sys' (built-in)>}
你可以把模块本身想象成一本字典。所以当你做 sys.stdout=
时......就像做 globals()['sys'].__dict__['stdout'] =...
当您只导入 stdout
时,globals
看起来像:
{...,
'stdout': <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>}
因此,当您执行 stdout=...
时,您实际上是在直接替换字典中的那个键:
globals()['stdout'] = ...
希望这有助于增加一点清晰度!
我的方法是创建一个contextmanager。
@contextmanager
def suppress_stdout():
with open(os.devnull, 'w') as devnull:
old_stdout = sys.stdout
old_stderr = sys.stderr
sys.stdout = devnull
try:
yield
finally:
sys.stdout = old_stdout
sys.stderr = old_stderr
然后当我想抑制某个命令的标准输出时:
with suppress_stdout():
# suppressed commands