Нет, в Cython нет способа сделать это.
Когда вы посмотрите на код, созданный на Cython, вы увидите, что gen
(и другие функции генератора) возвращают генератор, которыйв основном это __pyx_CoroutineObject
объект, который выглядит следующим образом :
typedef PyObject *(*__pyx_coroutine_body_t)(PyObject *, PyThreadState *, PyObject *);
typedef struct {
PyObject_HEAD
__pyx_coroutine_body_t body;
PyObject *closure;
...
int resume_label;
char is_running;
} __pyx_CoroutineObject;
Самая важная часть - body
-член: это функция, которая выполняет фактический расчет.Как мы видим, он возвращает PyObject
, и нет способа (пока?) Для его адаптации к int
, double
или подобному.
Что касается причин, по которым это не сделаноЯ могу только строить догадки - но, вероятно, есть более чем одна причина.
Если вы действительно заботитесь о производительности, генераторы в любом случае вносят слишком много накладных расходов (например, yield
невозможна в cdef
-функциях) и должен быть переработан во что-то более простое.
Более подробно о возможных рефакторингах.Исходя из предположения, что мы хотели бы суммировать все созданные значения:
%%cython
def gen(int x):
cdef int i
for i in range(x):
yield(i ** 2)
def sum_it(int n):
cdef int i
cdef int res=0
for i in gen(n):
res+=i
return res
Сроки это приводит к:
>>> %timeit sum_it(1000)
28.9 µs ± 1.06 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Хорошая новость: это примерно в 10 раз быстрее, чем чистыеверсия Python, но если мы действительно после скорости:
%%cython
cdef int gen_fast(int i):
return i ** 2
def sum_it_fast(int n):
cdef int i
cdef int res=0
for i in range(n):
res+=gen_fast(i)
return res
Это:
>>> %timeit sum_it_fast(1000)
661 ns ± 20.7 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
примерно в 50 раз быстрее.
Я понимаю, это довольноизменение, и это может быть довольно сложно сделать - я бы сделал это, только если это действительно является узким местом моей программы - но тогда ускорение 50 было бы реальной мотивацией для этого.
Очевидно, что естьЕсть много других подходов: использование numpy-массивов или array.array
вместо генераторов или написание собственного генератора (cdef-class), который обеспечил бы дополнительную быструю / эффективную возможность получить int
-значения, а не PyObjects
- но это все зависит от вашего сценария под рукой.Я просто хотел показать, что есть потенциал для улучшения производительности, отключив генераторы.