Python - 打印输出时,和+之间的区别

Posted

技术标签:

【中文标题】Python - 打印输出时,和+之间的区别【英文标题】:Python - Difference between , and + when printing output 【发布时间】:2018-09-16 13:16:56 【问题描述】:

快速且可能很愚蠢的问题。当我需要连接文本和数值进行输出时,我通常会使用:

number = 4
print("Two plus two = " + str(number))

但有时我会看到:

number = 4
print("Two plus two =",number)

第二个示例不需要类型转换并添加前导空格,但除此之外它们执行相同的操作。有谁知道为什么有两种方法可以做同样的事情?哪种方法“更好”?

【问题讨论】:

我猜第二个例子从长远来看具有更好的性能,因为字符串连接可能很昂贵。 使用+操作符可以添加多个空格,使用,可以添加单个空格。 @KOD 。 . .他们不会“做同样的事情”。它们恰好具有相同(或相似)的效果。第一个创建一个字符串,然后输出。第二个输出两个不同的元素。通常,第一种方法与format()一起使用。 【参考方案1】:

请务必了解,在 print("Two plus two = " + str(number)) 中,连接操作与 print 无关,并且发生在调用 print 之前。

让我们做一些计时:

from timeit import Timer

def with_concat():
    print("Two plus two = " + str(4))

def no_concat():
    print("Two plus two =", 4)

print(min(Timer(with_concat).repeat(100, 100)))
print(min(Timer(no_concat).repeat(100, 100)))

输出

0.0006760049999998685
0.0013034899999999627

反直觉(请参阅我对问题的评论,字符串连接可能很昂贵)连接示例实际上更快(2倍!)以可重现的方式。但为什么呢?

让我们检查字节码:

from dis import dis

def with_concat():
    print("Two plus two = " + str(4))

def no_concat():
    print("Two plus two =", 4)

dis(with_concat)

输出

 0 LOAD_GLOBAL              0 (print)
 2 LOAD_CONST               1 ('Two plus two = ')
 4 LOAD_GLOBAL              1 (str)
 6 LOAD_CONST               2 (4)
 8 CALL_FUNCTION            1
10 BINARY_ADD
12 CALL_FUNCTION            1
14 POP_TOP
16 LOAD_CONST               0 (None)
18 RETURN_VALUE

虽然

dis(no_concat)

输出

 0 LOAD_GLOBAL              0 (print)
 2 LOAD_CONST               1 ('Two plus two =')
 4 LOAD_CONST               2 (4)
 6 CALL_FUNCTION            2
 8 POP_TOP
10 LOAD_CONST               0 (None)
12 RETURN_VALUE

从字节码来看,no_concat 应该更快(更短、更简单的代码)。

延迟必须来自 C 源代码(至少在 CPython 的情况下)。

让我们看看相关的行:

static PyObject *
builtin_print(PyObject *self, PyObject *args, PyObject *kwds)

    .
    .
    .

    for (i = 0; i < PyTuple_Size(args); i++) 
        if (i > 0) 
            if (sep == NULL)
                err = PyFile_WriteString(" ", file);
            else
                err = PyFile_WriteObject(sep, file,
                                         Py_PRINT_RAW);
            if (err)
                return NULL;
        
        err = PyFile_WriteObject(PyTuple_GetItem(args, i), file,
                                 Py_PRINT_RAW);
        if (err)
            return NULL;
    

    .
    .
    .

在我看来,使用print(*args) 的开销似乎是由于对PyTuple_GetItem(args, i) 的重复调用,而使用它而不是print(a + lot + of + concatenated + strings) 的好处只有在连接字符串的数量足够大时才会出现使串联成为瓶颈(即比重复调用PyTuple_GetItem(args, i) 慢)。

【讨论】:

【参考方案2】:

正如@DeepSpace 评论的那样,使用 + 运算符连接字符串,使用两个参数只是使用 sep 参数作为分隔符(默认为空格)一一打印字符串。 有关更多信息,您可以查看 Python 3.4 source code。

【讨论】:

【参考方案3】:

这是一个旧线程,但我会尝试以更简单的方式回答这个问题,因为我曾经有完全相同的疑问。我不确定这是否是正确的方法,如果我错了,请纠正我。

所以如果你查看python打印函数文档:

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)。 将对象打印到文本流文件,以 sep 分隔,后跟 end。 sep、end、file 和 flush(如果存在)必须作为关键字参数给出。

所有非关键字参数都会像 str() 那样转换为字符串 和 写入流,以 sep 分隔,后跟 end。

例如,让我们检查一个示例代码:

age = 21
name = "Swapneil"
str1 = "Name is: "+name"+" and age is: "+str(age)

print(str1)
print("Name is:",name,"and age is",age)

这里两个 print 语句的输出是相同的,但是在第一个 print 中 str1 是单个对象,因为字符串是连接在一起的,并且在需要时需要一个类型大小写。但是,在第二个打印语句中,所有非关键字参数都以“,”分隔。它将所有参数转换为以 sep 参数的默认值分隔的字符串并抛出相同的结果。

这里唯一的区别是 str1 是单个对象,而在第二个 print 中有多个对象(print 函数的第一个参数是 *objects)它可以接受我们提供的任意多个位置参数。

【讨论】:

以上是关于Python - 打印输出时,和+之间的区别的主要内容,如果未能解决你的问题,请参考以下文章

Python--格式化输出%s和%d之小区别

python中返回和打印之间的区别? [复制]

python中return和print的区别

pythonprint和pprint的区别

python2与python3之间的主要区别

python中初级装饰器总结