sys.stdout作为默认函数参数

3

假设我们有以下虚拟函数:

import sys

def writeline(text, stream=sys.stdout):
    stream.write(text + '\n')

with open('/path/to/file', 'w') as f:
    # writes to /path/to/file
    writeline('foo', f)

# writes to standard output
writeline('bar')

鉴于 Python 在函数定义时评估默认参数,因此将 sys.stdout 设置为默认参数是否安全,或者可能会产生意外的副作用?


1
除非你在客户端代码中暂时重定向stdout,否则你应该没问题。如果你想进行这种重定向,函数仍将保留对原始stdout的引用,因此重定向将无法正常工作。 - Łukasz Rogalski
3个回答

5

我认为一个问题是,有时您需要自己将 sys.stdout 重定向到文件(或管道、设备等)

例如,您的主程序可能会像这样:

if __name__ == '__main__':
    if len(sys.argv) > 1:
        sys.stdout = open(sys.argv[1],'w')
    try:
        # ... run the program
    finally:
        if len(sys.argv) > 1:
            sys.stdout.close()

这可能对于想把程序日志记录到文件中的人很有用(比如像python3 file.py logfile.log这样提到文件名的情况)。由于您设置了sys.stdout,所以您的writeline方法不会注意到此修改。
因此,我认为更安全的做法是:
def writeline(text, stream<b> = None</b>):
    <b>if stream is None:</b>
        <b>stream = sys.stdout</b>
    stream.write(text + '\n')

一般情况下,将不可变对象设置为默认参数(例如NoneFalse(1,)等)可能是一个好建议。仅在罕见的情况下,Python中才会有意使用不可变对象(或可能改变引用的对象)。

但是,如果您确定不会将sys.stdout重定向到文件、管道等,则是安全的。


好观点。我知道将_immmutable_对象设置为默认参数更好的原因,但是在这种情况下,我认为这并不必要,因为我没有考虑到sys.stdout本身可能会发生变化。 - farsil

1
当对命名参数的恒定值存在疑虑时,最常用的成语是将参数设置为None,因此解析始终在运行时针对调用时间的当前值进行:
def writeline(text, stream=None):
    if stream is None:
        stream = sys.stdout
    stream.write(text + '\n')

0
如果您正在使用Python 3的打印函数,如果file参数为None,则输出将像往常一样打印到stdout。因此,您可以将默认值设置为None,如下所示:
def write_something(items, outfile=None):
    for item in items:
        print(item, file=outfile)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接