2016-01-06 4 views
1

Я учу Трудно знаю Python.Почему + (плюс) может конкатенировать две строки в Python?

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

Объясните, почему добавление двух строк w и e с + делает более длинную строку.

Даже я знаю, что он может работать, но я не понимаю, почему и как? Пожалуйста, помогите мне.

+4

Почему это вас удивляет, а не факт, что '+' может добавить два числа? Именно так Guido определил оператор '+' Python. – user2357112

+0

* Объясните, почему добавление двух строк w и e с + делает более длинную строку. * - Что еще вы ожидаете? – thefourtheye

+4

Подождите, пока вы доберетесь до ''Hello' * 3' –

ответ

6

Python использует + для конкатенации строк, потому что вот как основные разработчики Python определили этот оператор.

Хотя это правда, что __add__ специальный метод обычно используется для реализации + оператора, + (BINARY_ADD bytecode instruction) делает не вызов str.__add__ потому что + обрабатывает строки специально как в Python 2 и Python 3. Python вызывает функцию конкатенации непосредственно, если оба операнда + являются строками, что устраняет необходимость вызова специальных методов.

Python 3 вызовы unicode_concatenate (source 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_concatenate (source 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); 

    ... 

Эта оптимизация была в Python когда-либо с 2004 года из issue980695:

... в прилагаемом патче ceval.с специальные футляры сложение двух строк (таким же образом, как это специальные футляры сложения двух целых чисел уже)

Но обратите внимание, что основной целью было больше, чем устранение специального поиска атрибута.


Для чего это стоит, 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) из ​​фрагментов кода выше будет ложным:

>>> class STR(str): 
...  def __add__(self, other): 
...   print('calling __add__') 
...   return super().__add__(other) 
... 
>>> STR('abc') + STR('def') 
calling __add__ 
'abcdef' 
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" 

Тот же метод, перегрузка операторов, позволяет создавать классы, которые можно использовать встроенные операторы, как + или * полезно, как векторы, которые могут быть объединены вместе.

3

Метод __add__ класса 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 

>>> a = MyString("Hello") 
>>> b = MyString(" World!") 
>>> c = a+b 
>>> c.string 
'Hello World!' 
>>> 
Смежные вопросы