【问题标题】:String concatenation without '+' operator没有“+”运算符的字符串连接
【发布时间】:2013-09-21 11:23:01
【问题描述】:

我在玩 python,我意识到我们不需要使用 '+' 运算符来连接静态字符串。但是如果我将它分配给一个变量,它就会失败。

例如:

string1 = 'Hello'   'World'  #1 works fine
string2 = 'Hello' + 'World'  #2 also works fine

string3 = 'Hello'
string4 = 'World'
string5 = string3   string4  #3 causes syntax error
string6 = string3 + string4  #4 works fine

现在我有两个问题:

  1. 为什么语句 3 不起作用而语句 1 起作用?
  2. 语句1和语句2有计算速度等技术差异吗?

【问题讨论】:

标签: python string optimization concatenation string-concatenation


【解决方案1】:

这是隐式字符串文字连接。它只发生在字符串文字上,而不是变量或其他计算为字符串的表达式。曾经有一个(微小的)性能差异,但现在,窥视孔优化器应该使表单基本相同。

【讨论】:

    【解决方案2】:

    回答您的第二个问题:根本没有区别(至少在我使用的实现中)。反汇编这两个语句,它们被呈现为LOAD_CONST STORE_FAST。它们是等价的。

    【讨论】:

    • 在 CPython 中就是这种情况,但并非在每个实现中都如此。
    • @flornquake 感谢您的意见。我更新并在一定程度上限制了我的答案。
    【解决方案3】:

    来自docs

    允许多个相邻的字符串文字(由空格分隔),可能使用不同的引用约定,它们的含义与它们的连接相同。因此,"hello" 'world' 等价于 "helloworld"。


    语句 3 不起作用,因为:

    “+”运算符必须用于在运行时连接字符串表达式。

    请注意,文档中子标题的标题也是“字符串文字连接”。这仅适用于字符串文字,不适用于其他对象。


    可能没有区别。如果有,它可能非常小,任何人都不应该担心。


    另外,请理解这可能存在危险:

    >>> def foo(bar, baz=None):
    ...     return bar
    ... 
    >>> foo("bob"
    ... "bill")
    'bobbill'
    

    这是一个完美的例子,错误不应该默默地传递。如果我希望 "bill" 成为参数 baz 怎么办?我忘记了逗号,但没有引发错误。相反,发生了串联。

    【讨论】:

    • 因此,在这种情况下,“错误永远不应静默传递”意味着应定义语法,以便如果从任何有效程序中删除逗号,则生成的程序要么无效,要么具有相同的含义作为原始程序?我的意思是语法上重要的逗号,ofc,该规则不适用于从字符串文字中删除逗号;-)
    • @SteveJessop 嗯,我想它不适合这个例子,不是吗。因为技术上没有错误,对吧?
    • 另一个适用于 Python 和 C 的示例(即使逗号不代表相同的意思):1 - 11 , - 1 是不同的。基本上,上下文相关的运算符会导致这样的示例,并且并列实际上将令牌边界变成了上下文相关的运算符。字符串连接是一个特别容易犯的错误,因为在逗号分隔的字符串列表中引入换行符是很常见的。如果你写了foo(1, <newline> -1),那么实际上你也同样缺乏语言来判断你什么时候离开逗号的能力。
    • @SteveJessop 哇,太棒了。我以前尝试过学习 C++,但我从来没有接触过它,因为我非常喜欢 python(尤其是它的语法),但你在这里肯定教会了我很多东西。谢谢!
    • 这是python一个可怕的“特性”。我的程序只是默默地失败了,因为我在为 pandas 标题输入一长串名称时错过了一个逗号。
    【解决方案4】:

    您可以使用%s,因为这比使用 + 号更有效。

    >>> string2 = "%s %s" %('Hello', 'World')
    >>> string2
    'Hello World'
    

    (或)


    另一种方法是.format

    >>> string2 = "{0} {1}".format("Hello", "World")
    >>> string2
    'Hello World'
    >>> 
    

    【讨论】:

      【解决方案5】:

      语句 3 不起作用,因为当您连接两个字符串表达式以创建一个新字符串时,您需要一个“+”运算符。

      而在 sting 1,2 和 4 的情况下,由空格分隔的相邻文字使用不同的引用约定。因此允许它们使它们的打印与它们的连接相同。

      此外,运行这 2 个操作不会有任何显着或明显的时间差异。

      %%timeit -n 1
      s1='ab'
      s2='ba'
      print(s1+s2)
      

      o/p 最慢的运行时间是最快的运行时间的 17.08 倍。这可能意味着正在缓存中间结果。 每个循环 57.8 µs ± 92.5 µs(7 次运行的平均值 ± 标准偏差,每次 1 个循环)

      %%timeit -n 1
      s3='ab' 'ba'
      print(s3)
      

      o/p 最慢的运行时间是最快的运行时间的 4.86 倍。这可能意味着正在缓存中间结果。 每个循环 25.7 µs ± 21 µs(7 次运行的平均值 ± 标准偏差,每个循环 1 个)

      【讨论】:

        【解决方案6】:

        为什么语句 3 不起作用,而语句 1 起作用?

        因为,在第一个语句中,我们将一些常量分配给一个变量。变量赋值非常简单,因此我们可以继续将多个常量放入单个变量,并且赋值仍然会通过。术语"hello""world" 是两个相同类型的常量。所以,这个说法奏效了。

        如果我们执行以下操作,我们将得到SyntaxError

        string1 = "Hello" 1
        

        原因是我们在一个变量赋值中提供了多个常量。这使 python 感到困惑,并将其作为错误抛出。

        语句 3 是关于基于两个变量分配一个变量。这将产生SyntaxError,因为在将 2 个变量分配给变量之前,python 不知道它可以做什么。

        语句1和语句2有计算速度等技术上的区别吗?

        是的。唯一的技术区别是可读性而不是其他任何东西。可读性在 Python 中最重要。对于未经训练的眼睛,"hello" "world" 可能看起来编译器会将空格添加到字符串中。事实并非如此。

        然而,

        "hello" + "world"
        

        是明确的和正常的。几乎总是,显式优于隐式。

        【讨论】:

          猜你喜欢
          • 2019-01-09
          • 2014-02-27
          • 2016-07-19
          • 2015-08-28
          • 2010-09-08
          • 1970-01-01
          • 2012-05-07
          相关资源
          最近更新 更多