Python用于+
连接字符串,因为这是Python的核心开发人员定义该运算符的方式。
的确,__add__
通常使用特殊方法来实现该+
运算符,但不会 调用+
(BINARY_ADD
字节码指令),因为在Python 2和Python 3中都特别对待字符串。如果两个操作数都是字符串,Python会 直接 调用字符串连接函数,从而消除了需要调用特殊方法。 +
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);
}
...
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:
>>> class STR(str):
... def __add__(self, other):
... print('calling __add__')
... return super().__add__(other)
...
>>> STR('abc') + STR('def')
calling __add__
'abcdef'