为什么+(plus)可以在Python中连接两个字符串?

时间:2016-01-06 05:48:52

标签: python string python-internals

我正在学习学习Python的方法。

w = "This is the left side of..."
e = "a string with a right side."
print w + e

解释为什么用+ +添加两个字符串we会产生更长的字符串。

即使我知道它可以工作,但我不明白为什么以及如何?请帮帮我。

3 个答案:

答案 0 :(得分:9)

Python使用+来连接字符串,因为Python的核心开发人员如何定义该操作符。

虽然__add__特殊方法通常用于实现+运算符,+BINARY_ADD bytecode instruction)确实 call str.__add__因为+特别处理Python 2和Python 3中的字符串。如果+的两个操作数都是字符串,Python将直接调用字符串连接函数 ,因此无需调用特殊方法。

Python 3 调用unicode_concatenatesource code):

TARGET(BINARY_ADD) {
    PyObject *right = POP();
    PyObject *left = TOP();
    PyObject *sum;
    if (PyUnicode_CheckExact(left) &&
             PyUnicode_CheckExact(right)) {
        sum = unicode_concatenate(left, right, f, next_instr);
        /* unicode_concatenate consumed the ref to v */
    }
    else {
        sum = PyNumber_Add(left, right);
        Py_DECREF(left);
    }
    ...

Python 2 调用string_concatenatesource code):

case BINARY_ADD:
    w = POP();
    v = TOP();
    if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) {
        /* INLINE: int + int */
        register long a, b, i;
        a = PyInt_AS_LONG(v);
        b = PyInt_AS_LONG(w);
        /* cast to avoid undefined behaviour
           on overflow */
        i = (long)((unsigned long)a + b);
        if ((i^a) < 0 && (i^b) < 0)
            goto slow_add;
        x = PyInt_FromLong(i);
    }
    else if (PyString_CheckExact(v) &&
             PyString_CheckExact(w)) {
        x = string_concatenate(v, w, f, next_instr);
        /* string_concatenate consumed the ref to v */
        goto skip_decref_vx;
    }
    else {
      slow_add:
        x = PyNumber_Add(v, w);

    ...

自2004年以来,这种优化一直在Python中。来自issue980695

  

...在附加的补丁 ceval.c 特殊情况下添加了两个字符串(与特殊情况相同 - 添加了两个整数)

但请注意,主要目标不仅仅是消除特殊属性查找。

对于它的价值,str.__add__仍然按预期工作:

>>> w.__add__(e)
'This is the left side of...a string with a right side.'

并且Python会调用__add__子类的str方法,因为上面代码段中的PyUnicode_CheckExact(left) && PyUnicode_CheckExact(right)(或PyString_CheckExact(v) && PyString_CheckExact(w),在Python 2中)将为false:< / p>

>>> class STR(str):
...     def __add__(self, other):
...         print('calling __add__')
...         return super().__add__(other)
... 
>>> STR('abc') + STR('def')
calling __add__
'abcdef'

答案 1 :(得分:3)

当您以这种方式添加(连接)两个字符串时,将调用类__add__的{​​{1}}方法。 str方法可以这样工作,但以下内容并非源于源代码:

__add__

示例:

def __add__(self, str1, str2):
    str3 = [str1] #Convert to list
    str3.append(str2) #Add the second string to the list
    return ''.join(str3) #Return the two joined
class MyString:
    def __init__(self, initstr):
        self.string = initstr
    def __add__(str1, str2):
        str3 = [str1.string] #Convert to list
        str3.append(str2.string) #Add the second string to the list
        return MyString(''.join(str3)) #Return the two joined

答案 2 :(得分:1)

+-*和其他运算符将适用于实现正确方法的任何内容。由于字符串实现了__add__(self, other)方法,因此您可以使用+添加两个字符串。

试试这个:定义你自己的字符串子类并覆盖它的__add__方法:

class BadString(str):
    def __add__(self, other):
        # Ignore both input strings and just return this:
        return "Nothing Useful"

s = BadString("hello")

print("hello" + " world")    # "hello world"
print(s + "world")           # "Nothing Useful"

使用相同的技术,运算符重载,可以创建可以有用地使用内置运算符(如+*的类),例如可以一起添加的向量。