Running cards against starmap?

I tried to make pure-python (without external dependencies) a phased comparison of two sequences. My first solution was:

list(map(operator.eq, seq1, seq2))

Then I found a starmapfunction from itertoolsthat seemed very similar to me. But in the worst case, it turned out to be 37% faster on my computer. Since this was not obvious to me, I measured the time required to extract 1 element from the generator (I do not know if this path is correct):

from operator import eq
from itertools import starmap

seq1 = [1,2,3]*10000
seq2 = [1,2,3]*10000
seq2[-1] = 5

gen1 = map(eq, seq1, seq2))
gen2 = starmap(eq, zip(seq1, seq2))

%timeit -n1000 -r10 next(gen1)
%timeit -n1000 -r10 next(gen2)

271 ns ± 1.26 ns per loop (mean ± std. dev. of 10 runs, 1000 loops each)
208 ns ± 1.72 ns per loop (mean ± std. dev. of 10 runs, 1000 loops each)

When extracting elements, the second solution is 24% more efficient. After that, both of them give the same results for list. But from somewhere we get an additional 13% in time:

%timeit list(map(eq, seq1, seq2))
%timeit list(starmap(eq, zip(seq1, seq2)))

5.24 ms ± 29.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
3.34 ms ± 84.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

, ? , 13% list?

EDIT: , all, all list. .

CPython 3.6.2 Windows 10 (64 )

+6
2

, ( ) :

  • zip tuple, 1 __next__.
  • map tuple, " " __next__. , , , Python . map .
  • starmap , iterable tuple, .
  • C C PyObject_Call , .

, starmap zip , operator.eq, . map, , ( C CPython 3.6) , operator.eq. , - .

Cython, :

In [1]: %load_ext cython

In [2]: %%cython
   ...:
   ...: from cpython.ref cimport Py_DECREF
   ...:
   ...: cpdef func(zipper):
   ...:     a = next(zipper)
   ...:     print('a', a)
   ...:     Py_DECREF(a)
   ...:     b = next(zipper)
   ...:     print('a', a)

In [3]: func(zip([1, 2], [1, 2]))
a (1, 1)
a (2, 2)

, tuple , Py_DECREF , "" zip, , !

"tuple-pass-thru":

In [4]: %%cython
   ...:
   ...: def func_inner(*args):
   ...:     print(id(args))
   ...:
   ...: def func(*args):
   ...:     print(id(args))
   ...:     func_inner(*args)

In [5]: func(1, 2)
1404350461320
1404350461320

, ( , C!) Python:

In [6]: def func_inner(*args):
   ...:     print(id(args))
   ...:
   ...: def func(*args):
   ...:     print(id(args))
   ...:     func_inner(*args)
   ...:

In [7]: func(1, 2)
1404350436488
1404352833800

, , C, C:

In [8]: %%cython
   ...: 
   ...: def func_inner_c(*args):
   ...:     print(id(args))
   ...: 
   ...: def func(inner, *args):
   ...:     print(id(args))
   ...:     inner(*args)
   ...:

In [9]: def func_inner_py(*args):
    ...:     print(id(args))
    ...:
    ...:

In [10]: func(func_inner_py, 1, 2)
1404350471944
1404353010184

In [11]: func(func_inner_c, 1, 2)
1404344354824
1404344354824

, "", , starmap zip , map , C...

+2

, , , map . map zip . zip tuple , , , map * .


* MSeifert 3.5.4 map_next, Python. 3.6 5 C, - , . PR: # 27809: map_next() _PY_FASTCALL_SMALL_STACK | : https://bugs.python.org/issue27809

+1

All Articles