sten
sten

Reputation: 7486

range() as method argument for loop iterator

this code generates a nice loop :

for i in range(self.ix):

__pyx_t_3 = __pyx_v_self->ix;
__pyx_t_4 = __pyx_t_3;
for (__pyx_t_5 = 0; __pyx_t_5 < __pyx_t_4; __pyx_t_5+=1) {
  __pyx_v_i = __pyx_t_5;

but i want to be able to pass this iterator as argument (so i can have different iterators/generators)

if i try this :

  cdef ixrange(self): return range(self.ix)

already is too unwieldy and the loop is no longer a simple loop. :

static PyObject *__pyx_f_3lib_10sparse_ary_9SparseAry_ixrange(struct __pyx_obj_3lib_10sparse_ary_SparseAry *__pyx_v_self) {
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("ixrange", 0);
  __Pyx_XDECREF(__pyx_r);
  __pyx_t_1 = __Pyx_PyInt_From_unsigned_int(__pyx_v_self->ix); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 139, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_builtin_range, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 139, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_r = __pyx_t_2;
  __pyx_t_2 = 0;
  goto __pyx_L0;

  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_XDECREF(__pyx_t_2);
  __Pyx_AddTraceback("lib.sparse_ary.SparseAry.ixrange", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = 0;
  __pyx_L0:;
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

any way i can make it simple loop again ?

Upvotes: 0

Views: 125

Answers (1)

DavidW
DavidW

Reputation: 30916

I don't think it is possible.

The effect of for i in range(self.ix): is to generate a range object, and then call next on that range object until a StopIteration exception is raised. That's also the behaviour that Cython takes for general for loops.

There's actually a fairly long list of conditions that have to be met for Cython to transform that into an optimized loop:

  • range must be used directly - i.e. it = range(...); for i in it won't work because you might need the range object after the loop.
  • the types of the start and stop point must be integers.
  • the type of the loop variable must be an integer (Cython can infer this, but if you assign something of a different type to the loop variable then it won't work)
  • Cython must know that you haven't reassigned range
  • The sign of the stop variable must be known.

In your case I think you're hoping for Cython to look inside the cdef function and pick out the range. This is beyond what the current optimizer can do. But also, you can override cdef functions in a derived class (in C++ terms, they're "virtual"), so Cython could almost never safely make the optimization.

Cython is usually able to optimize best when you really restrict the types it's working with. The request that it should generate a fast C for loop but also be able to handle arbitrary iterators does not seem realistically achievable.

Upvotes: 1

Related Questions