如果您查看以下时间:
C:\Users\Henry>python -m timeit -s "mul = int.__mul__" "reduce(mul,range(10000))"
1000 loops, best of 3: 908 usec per loop
C:\Users\Henry>python -m timeit -s "from operator import mul" "reduce(mul,range(10000))"
1000 loops, best of 3: 410 usec per loop
之间的执行速度存在显着差异
reduce(int.__mul__,range(10000))
和 reduce(mul,range(10000))
后者更快。使用
dis
模块查看发生了什么:使用
int.__mul__
方法:C:\Users\Henry>python
Python 2.7.4 (default, Apr 6 2013, 19:55:15) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> mul = int.__mul__
>>> def test():
... mul(1,2)
...
>>> import dis
>>> dis.dis(test)
2 0 LOAD_GLOBAL 0 (mul)
3 LOAD_CONST 1 (1)
6 LOAD_CONST 2 (2)
9 CALL_FUNCTION 2
12 POP_TOP
13 LOAD_CONST 0 (None)
16 RETURN_VALUE
>>>
和操作符
mul
方法C:\Users\Henry>python
Python 2.7.4 (default, Apr 6 2013, 19:55:15) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from operator import mul
>>> def test():
... mul(1,2)
...
>>> import dis
>>> dis.dis(test)
2 0 LOAD_GLOBAL 0 (mul)
3 LOAD_CONST 1 (1)
6 LOAD_CONST 2 (2)
9 CALL_FUNCTION 2
12 POP_TOP
13 LOAD_CONST 0 (None)
16 RETURN_VALUE
>>>
它们看起来一样,那么为什么执行速度会有差异呢?我指的是Python的CPython实现
在 python3 上也会发生同样的情况:
$ python3 -m timeit -s 'mul=int.__mul__;from functools import reduce' 'reduce(mul, range(10000))'
1000 loops, best of 3: 1.18 msec per loop
$ python3 -m timeit -s 'from operator import mul;from functools import reduce' 'reduce(mul, range(10000))'
1000 loops, best of 3: 643 usec per loop
$ python3 -m timeit -s 'mul=lambda x,y:x*y;from functools import reduce' 'reduce(mul, range(10000))'
1000 loops, best of 3: 1.26 msec per loop
最佳答案
int.__mul__
是一个槽包装器,即 PyWrapperDescrObject ,而 operator.mul
是一个内置函数。
我认为相反的执行速度是由这种差异造成的。
>>> int.__mul__
<slot wrapper '__mul__' of 'int' objects>
>>> operator.mul
<built-in function mul>
当我们调用 PyWrapperDescrObject 时,会调用
wrapperdescr_call
。
static PyObject *
wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds)
{
Py_ssize_t argc;
PyObject *self, *func, *result;
/* Make sure that the first argument is acceptable as 'self' */
assert(PyTuple_Check(args));
argc = PyTuple_GET_SIZE(args);
if (argc d_type->tp_name);
return NULL;
}
self = PyTuple_GET_ITEM(args, 0);
if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self),
(PyObject *)(descr->d_type))) {
PyErr_Format(PyExc_TypeError,
"descriptor '%.200s' "
"requires a '%.100s' object "
"but received a '%.100s'",
descr_name((PyDescrObject *)descr),
descr->d_type->tp_name,
self->ob_type->tp_name);
return NULL;
}
func = PyWrapper_New((PyObject *)descr, self);
if (func == NULL)
return NULL;
args = PyTuple_GetSlice(args, 1, argc);
if (args == NULL) {
Py_DECREF(func);
return NULL;
}
result = PyEval_CallObjectWithKeywords(func, args, kwds);
Py_DECREF(args);
Py_DECREF(func);
return result;
}
让我们看看我们发现了什么!
func = PyWrapper_New((PyObject *)descr, self);
已经构建了一个新的 PyWrapper 对象。它会显着降低执行速度。
有时,创建一个新对象比运行一个简单的函数需要更多的时间。
因此,
int.__mul__
比 operator.mul
慢也就不足为奇了。关于python - int.__mul__ ,执行速度比 operator.mul 慢 2 倍,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27818859/