use*_*269 6 python generator numba
这个问题的后续:numba 中的函数类型。
我正在编写一个需要将生成器作为其参数之一的函数。粘贴在这里太复杂了,所以考虑这个玩具示例:
def take_and_sum(gen):
@numba.jit(nopython=False)
def inner(n):
s = 0
for _ in range(n):
s += next(gen)
return s
return inner
Run Code Online (Sandbox Code Playgroud)
它返回n生成器的第一个元素的总和。用法示例:
@numba.njit()
def odd_numbers():
n = 1
while True:
yield n
n += 2
take_and_sum(odd_numbers())(3) # prints 9
Run Code Online (Sandbox Code Playgroud)
它是咖喱,因为我想编译,nopython=True然后我不能将gen(a pyobject) 作为参数传递。不幸的是,nopython=True我收到一个错误:
TypingError: Failed at nopython (nopython frontend)
Untyped global name 'gen'
Run Code Online (Sandbox Code Playgroud)
即使我nopython编译了我的生成器。
真正令人困惑的是,对输入进行硬编码是有效的:
def take_and_sum():
@numba.njit()
def inner(n):
gen = odd_numbers()
s = 0.0
for _ in range(n):
s += next(gen)
return s
return inner
take_and_sum()(3)
Run Code Online (Sandbox Code Playgroud)
我也尝试将我的生成器变成一个类:
@numba.jitclass({'n': numba.uint})
class Odd:
def __init__(self):
self.n = 1
def next(self):
n = self.n
self.n += 2
return n
Run Code Online (Sandbox Code Playgroud)
同样,这在对象模式下有效,但在 nopython 模式下,我得到了无法搜索的信息:
LoweringError: Failed at nopython (nopython mode backend)
Internal error:
NotImplementedError: instance.jitclass.Odd#4aa9758<n:uint64> as constant unsupported
Run Code Online (Sandbox Code Playgroud)
我实际上无法解决您的问题,因为据我所知,这是根本不可能的。我只是强调一些方面(适用于numba 0.30):
您无法创建 numba-jitclass生成器:
import numba
@numba.jitclass({'n': numba.uint})
class Odd:
def __init__(self):
self.n = 1
def __iter__(self):
return self
def __next__(self):
n = self.n
self.n += 2
return n
Run Code Online (Sandbox Code Playgroud)
你试一试:
>>> next(Odd())
TypeError: 'Odd' object is not an iterator
Run Code Online (Sandbox Code Playgroud)
当你删除它时,它numba.jitclass会起作用:
>>> next(Odd())
1
Run Code Online (Sandbox Code Playgroud)
您使用硬编码生成器的示例并不等效。您最初的尝试创建一个生成器对象,将其传递给 numba 函数并修改生成器。您可能希望它更新生成器的状态。
>>> t = odd_numbers()
>>> take_and_sum(t)(3)
9
>>> next(t) # State has been updated, unfortunatly that requires nopython=False!
7
Run Code Online (Sandbox Code Playgroud)
但这对于 numba 来说根本不可能(目前)。
第二个示例有所不同,因为每次调用函数时都会创建生成器,因此函数外部没有需要更新的状态:
>>> take_and_sum()(3) # using your hardcoded version
9.0
>>> take_and_sum()(3) # no updated state so this returns the same:
9.0
Run Code Online (Sandbox Code Playgroud)
绝对可以更改它,但不能选择使用任意函数:
@numba.jitclass({'n': numba.uint})
class Odd:
def __init__(self):
self.n = 1
def calculate(self, n):
s = 0.0
for _ in range(n):
s += self.n
self.n += 2
return s
>>> x = Odd()
>>> x.calculate(3)
9.0
>>> x.calculate(3)
27.0
Run Code Online (Sandbox Code Playgroud)
我知道这不是你想要的,但至少它在某种程度上有效:-)