支持的 Python 特性
除了下面的 语言 部分(适用于 对象模式 和 nopython 模式),本页仅列出 nopython 模式 中支持的功能。
警告
Numba 的行为在某些情况下与 Python 语义不同。我们强烈建议查看 与Python语义的偏差 以熟悉这些差异。
语言
构造
Numba 致力于尽可能支持 Python 语言的大部分内容,但在 Numba 编译的函数中,某些语言特性是不可用的。以下是 Python 构造支持级别的快速参考。
支持 的结构:
条件分支:
if .. elif .. else
循环:
while
,for .. in
,break
,continue
基本生成器:
yield
断言:
assert
部分支持 的结构:
上下文管理器:
with
(仅支持 numba.objmode())`列表推导(详见此 部分)
不支持 的结构:
函数
函数调用
Numba 支持使用位置参数和命名参数的函数调用,以及带有默认值的参数和 *args``(注意 ``*args
的参数只能是元组,不能是列表)。显式的 **kwargs
不受支持。
只要可以完全内联,就支持对本地定义的内部函数的函数调用。
作为参数的函数
函数可以作为参数传递给另一个函数。但是,它们不能被返回。例如:
from numba import jit
@jit
def add1(x):
return x + 1
@jit
def bar(fn, x):
return fn(x)
@jit
def foo(x):
return bar(add1, x)
# Passing add1 within numba compiled code.
print(foo(1))
# Passing add1 into bar from interpreted code
print(bar(add1, 1))
备注
Numba 不将函数对象作为真正的对象处理。一旦一个函数被赋值给一个变量,该变量就不能被重新赋值为不同的函数。
内部函数和闭包
Numba 现在支持内部函数,只要它们是非递归的并且在本地调用,而不是作为参数传递或作为结果返回。内部函数中使用闭包变量(在外部作用域中定义的变量)也是支持的。
递归调用
大多数递归调用模式都受支持。唯一的限制是递归调用者必须有一个不递归的控制流路径。Numba 能够在不指定函数类型签名的情况下推断递归函数的类型(这在 numba 0.28 及更早版本中是必需的)。递归调用甚至可以调用函数的不同重载。
生成器
Numba 支持生成器函数,并能够在 对象模式 和 nopython 模式 下编译它们。返回的生成器可以在 Numba 编译的代码和常规 Python 代码中使用。
生成器的协程特性不受支持(即 generator.send()
、generator.throw()
、generator.close()
方法)。
异常处理
raise
语句
raise
语句仅支持以下形式:
raise SomeException
raise SomeException(<参数>)
目前不支持重新抛出在编译代码中创建的异常。
try .. except
try .. except
结构部分支持。以下形式是支持的:
捕获所有异常的 bare except:
try: ... except: ...
在
except
子句中使用Exception
类:try: ... except Exception: ...
这将匹配任何作为
Exception
子类的异常,如预期。目前,Exception
及其子类的实例是编译代码中唯一可以引发的异常类型。
警告
Numba 目前屏蔽了像 KeyboardInterrupt
和 SystemExit
这样的信号。在执行 Numba 编译的代码期间,这些信号异常会被忽略。Python 解释器会在控制权返回给它时处理这些异常。
目前,异常对象在编译的函数内部没有被具体化。因此,不可能将异常对象存储到用户变量中,也不可能重新引发异常。由于这种限制,唯一现实的用例可能看起来像:
try:
do_work()
except Exception:
handle_error_case()
return error_code
try .. except .. else .. finally
try .. except
的 else
块和 finally
块是支持的:
>>> @jit(nopython=True) ... def foo(): ... try: ... print('main block') ... except Exception: ... print('handler block') ... else: ... print('else block') ... finally: ... print('final block') ... >>> foo() main block else block final block
不带 except
子句的 try .. finally
结构也是支持的。
内置类型
int, bool
支持算术运算以及真值。
支持以下属性和方法:
.conjugate()
.real
.imag
float, complex
支持算术运算以及真值。
支持以下属性和方法:
.conjugate()
.real
.imag
str
Numba 支持 Python 3 中的 (Unicode) 字符串。字符串可以作为参数传递到 nopython 模式,也可以从 nopython 模式 中构造和返回。与 Python 中一样,切片(即使是长度为 1 的切片)会返回一个新的、引用计数的字符串。未来可能会引入高效访问单个字符的优化代码路径。
内存中的表示形式与Python 3.4中引入的相同,每个字符串都有一个标签,用于指示该字符串在内存中使用的是1、2还是4字节的字符宽度。当不同编码的字符串组合在一起(如连接时),生成的字符串会自动使用两个输入字符串中较大的字符宽度。字符串切片也使用与原始字符串相同的字符宽度,即使切片可以用更窄的字符宽度表示。(当然,这些细节对用户是不可见的。)
以下构造函数、函数、属性和方法目前支持:
str(int)
len()
+
(字符串连接)*
(字符串重复)in
,.contains()
==
,<
,<=
,>
,>=
(比较).capitalize()
.casefold()
.center()
.count()
.endswith()
.endswith()
.expandtabs()
.find()
.index()
.isalnum()
.isalpha()
.isdecimal()
.isdigit()
.isidentifier()
.islower()
.isnumeric()
.isprintable()
.isspace()
.istitle()
.isupper()
.join()
.ljust()
.lower()
.lstrip()
.partition()
.replace()
.rfind()
.rindex()
.rjust()
.rpartition()
.rsplit()
.rstrip()
.split()
.splitlines()
.startswith()
.strip()
.swapcase()
.title()
.upper()
.zfill()
常规字符串字面量(例如 "ABC"
)以及不带格式说明的 f-字符串(例如 "ABC_{a+1}"
),仅使用字符串和整数变量(具有 str()
重载的类型)在 nopython 模式 中受支持。
Numba 的未来版本将添加对 Python 2 字符串 / Python 3 字节的其他操作和支持。Python 2 Unicode 对象可能永远不会得到支持。
警告
某些操作的性能已知比 CPython 实现慢。这些包括子字符串搜索(in
、.contains()
和 find()
)和字符串创建(如 .split()
)。提高字符串性能是一个持续的任务,但 CPython 在单独的基本字符串操作中的速度不太可能被超越。Numba 最成功地用于涉及字符串的大型算法,其中基本字符串操作不是瓶颈。
元组
元组支持根据元组内容分为两类。第一类是同质元组,这些元组中所有值的类型相同;第二类是异质元组,这些元组中值的类型不同。
备注
tuple()
构造函数本身是不受支持的。
同质元组
一个同质元组的示例:
homogeneous_tuple = (1, 2, 3, 4)
以下操作支持在同质元组上进行:
元组构造。
元组解包。
元组之间的比较。
迭代与索引。
元组之间的加法(连接)。
使用常量切片对元组进行切片。
元组上的索引方法。
异构元组
一个异构元组的例子:
heterogeneous_tuple = (1, 2j, 3.0, "a")
以下操作在异构元组上受支持:
元组之间的比较。
使用编译时常量作为索引值进行索引,例如
mytuple[7]
,其中7
显然是一个常量。遍历一个元组(需要实验性的
literal_unroll()
功能,见下文)。
警告
以下功能(literal_unroll()
)是实验性的,并在版本0.47中添加。
为了允许对异构元组进行迭代,必须使用特殊函数 numba.literal_unroll()
。此函数除了作为允许使用此功能的标记外,没有其他效果。示例用法:
from numba import njit, literal_unroll
@njit
def foo():
heterogeneous_tuple = (1, 2j, 3.0, "a")
for i in literal_unroll(heterogeneous_tuple):
print(i)
警告
以下限制适用于 literal_unroll()
的使用:
literal_unroll()
只能用于元组和编译时常量的常量列表,例如[1, 2j, 3, "a"]
并且列表未被修改。对于
literal_unroll()
唯一支持的使用模式是循环迭代。每个循环嵌套只允许一个
literal_unroll()
调用(即禁止嵌套的异构元组迭代循环)。通常的类型推断/稳定性规则仍然适用。
更复杂的 literal_unroll()
使用可能涉及类型特定的调度,请记住字符串和整数字面值被视为它们自己的类型,例如:
from numba import njit, types, literal_unroll
from numba.extending import overload
def dt(x):
# dummy function to overload
pass
@overload(dt, inline='always')
def ol_dt(li):
if isinstance(li, types.StringLiteral):
value = li.literal_value
if value == "apple":
def impl(li):
return 1
elif value == "orange":
def impl(li):
return 2
elif value == "banana":
def impl(li):
return 3
return impl
elif isinstance(li, types.IntegerLiteral):
value = li.literal_value
if value == 0xca11ab1e:
def impl(li):
# capture the dispatcher literal value
return 0x5ca1ab1e + value
return impl
@njit
def foo():
acc = 0
for t in literal_unroll(('apple', 'orange', 'banana', 3390155550)):
acc += dt(t)
return acc
print(foo())
列表
警告
从版本 0.45.x 开始,Numba 中列表数据类型的内部实现正在发生变化。直到最近,只有一种列表数据类型的实现可用,即所谓的 *反射列表*(见下文)。然而,由于其局限性,它从版本 0.44.0 开始被计划弃用。从版本 0.45.0 开始,一种新的实现,即所谓的 *类型化列表*(见下文),作为实验性功能可用。更多信息,请参见:弃用通知。
从即时编译的函数中创建和返回列表是支持的,以及所有方法和操作。列表必须是严格同质的:Numba 将拒绝包含不同类型对象的任何列表,即使这些类型是兼容的(例如,[1, 2.5]
被拒绝,因为它包含一个 int
和一个 float
)。
例如,要创建一个数组列表:
In [1]: from numba import njit
In [2]: import numpy as np
In [3]: @njit
...: def foo(x):
...: lst = []
...: for i in range(x):
...: lst.append(np.arange(i))
...: return lst
...:
In [4]: foo(4)
Out[4]: [array([], dtype=int64), array([0]), array([0, 1]), array([0, 1, 2])]
列表反射
在 nopython 模式下,Numba 不操作 Python 对象。list
被编译成内部表示。任何 list
参数在进入 nopython 模式时必须转换为这种表示,并且它们包含的元素必须通过一个称为 反射 的过程恢复到原始的 Python 对象中。反射是必要的,以保持与常规 Python 代码中相同的语义。然而,对于大型列表,反射过程可能会很昂贵,并且不支持包含反射数据类型的列表。由于这种限制,用户不能使用列表的列表作为参数。
备注
当将列表传递给即时编译的函数时,对该列表所做的任何修改在函数返回之前对Python解释器是不可见的。(这是反射过程的一个限制。)
警告
列表排序目前使用的是快速排序算法,这与Python使用的算法具有不同的性能特征。
初始值
警告
这是一个实验性功能!
列表:
使用方括号语法构建
具有字面类型的值
它们的初始值将存储在类型的 .initial_value
属性中,以便在编译时允许检查这些值。如果需要,为了强制基于值的分派,literally 函数将接受这样一个列表。
示例:
1from numba import njit, literally
2from numba.extending import overload
3
4# overload this function
5def specialize(x):
6 pass
7
8@overload(specialize)
9def ol_specialize(x):
10 iv = x.initial_value
11 if iv is None:
12 return lambda x: literally(x) # Force literal dispatch
13 assert iv == [1, 2, 3] # INITIAL VALUE
14 return lambda x: x
15
16@njit
17def foo():
18 l = [1, 2, 3]
19 l[2] = 20 # no impact on .initial_value
20 l.append(30) # no impact on .initial_value
21 return specialize(l)
22
23result = foo()
24print(result) # [1, 2, 20, 30] # NOT INITIAL VALUE!
类型化列表
备注
numba.typed.List
是一个实验性功能,如果你在功能上遇到任何错误或遭受意外的性能下降,请报告此问题,理想情况下是通过在 Numba 问题跟踪器上打开一个新问题。
从版本 0.45.0 开始,一个新的列表数据类型实现可用,即所谓的 类型化列表。这是一个由编译库支持的、类型同质的列表数据类型,是对上述 反射列表 的改进。此外,列表现在可以任意嵌套。由于该实现被认为是实验性的,您需要从 numba.typed 模块显式导入它:
In [1]: from numba.typed import List
In [2]: from numba import njit
In [3]: @njit
...: def foo(l):
...: l.append(23)
...: return l
...:
In [4]: mylist = List()
In [5]: mylist.append(1)
In [6]: foo(mylist)
Out[6]: ListType[int64]([1, 23])
备注
随着类型化列表的稳定,它将完全取代反射列表,构造函数 [] 和 list() 将创建一个类型化列表而不是反射列表。
以下是一个使用 List()
在 jit 编译函数内部创建 numba.typed.List
并让编译器推断项目类型的示例:
1from numba import njit
2from numba.typed import List
3
4@njit
5def foo():
6 # Instantiate a typed-list
7 l = List()
8 # Append a value to it, this will set the type to int32/int64
9 # (depending on platform)
10 l.append(42)
11 # The usual list operations, getitem, pop and length are
12 # supported
13 print(l[0]) # 42
14 l[0] = 23
15 print(l[0]) # 23
16 print(len(l)) # 1
17 l.pop()
18 print(len(l)) # 0
19 return l
20
21foo()
22
以下是使用 List()
在 jit 编译函数外部创建 numba.typed.List
,然后将其作为参数传递给 jit 编译函数的示例:
1from numba import njit
2from numba.typed import List
3
4@njit
5def foo(mylist):
6 for i in range(10, 20):
7 mylist.append(i)
8 return mylist
9
10# Instantiate a typed-list, outside of a jit context
11l = List()
12# Append a value to it, this will set the type to int32/int64
13# (depending on platform)
14l.append(42)
15# The usual list operations, getitem, pop and length are supported
16print(l[0]) # 42
17l[0] = 23
18print(l[0]) # 23
19print(len(l)) # 1
20l.pop()
21print(len(l)) # 0
22
23# And you can use the typed-list as an argument for a jit compiled
24# function
25l = foo(l)
26print(len(l)) # 10
27
28# You can also directly construct a typed-list from an existing
29# Python list
30py_list = [2, 3, 5]
31numba_list = List(py_list)
32print(len(numba_list)) # 3
33
最后,这里是一个使用嵌套 List() 的示例:
1from numba.typed import List
2
3# typed-lists can be nested in typed-lists
4mylist = List()
5for i in range(10):
6 l = List()
7 for i in range(10):
8 l.append(i)
9 mylist.append(l)
10# mylist is now a list of 10 lists, each containing 10 integers
11print(mylist)
12
字面列表
警告
这是一个实验性功能!
Numba 支持使用包含任何值的文字列表,例如:
l = ['a', 1, 2j, np.zeros(5,)]
这些列表的主要用途是作为配置对象使用。这些列表显示为 LiteralList
类型,它继承自 Literal
,因此列表项的字面值在编译时是可用的。例如:
1from numba import njit
2from numba.extending import overload
3
4# overload this function
5def specialize(x):
6 pass
7
8@overload(specialize)
9def ol_specialize(x):
10 l = x.literal_value
11 const_expr = []
12 for v in l:
13 const_expr.append(str(v))
14 const_strings = tuple(const_expr)
15
16 def impl(x):
17 return const_strings
18 return impl
19
20@njit
21def foo():
22 const_list = ['a', 10, 1j, ['another', 'list']]
23 return specialize(const_list)
24
25result = foo()
26print(result) # ('Literal[str](a)', 'Literal[int](10)', 'complex128', 'list(unicode_type)') # noqa E501
关于这类列表需要注意的重要事项:
它们是不可变的,使用突变方法例如
.pop()
会导致编译失败。支持只读静态访问和只读方法,例如len()
。无法动态访问项目,例如
some_list[x]
,对于值x
不是编译时常量的情况。这是因为无法静态确定被访问项目的类型。在编译器内部,这些列表实际上只是添加了一些额外内容的元组,使它们看起来像是列表。
它们不能从编译函数返回给解释器。
列表推导式
Numba 支持列表推导。例如:
In [1]: from numba import njit
In [2]: @njit
...: def foo(x):
...: return [[i for i in range(n)] for n in range(x)]
...:
In [3]: foo(3)
Out[3]: [[], [0], [0, 1]]
备注
在版本0.39.0之前,Numba不支持创建嵌套列表。
Numba 也支持“数组推导”,这是一种列表推导紧接着调用 numpy.array()
的操作。以下是一个生成二维 Numpy 数组的示例:
from numba import jit
import numpy as np
@jit(nopython=True)
def f(n):
return np.array([ [ x * y for x in range(n) ] for y in range(n) ])
在这种情况下,Numba 能够优化程序,直接分配和初始化结果数组,而无需分配中间列表对象。因此,这里的列表推导嵌套不是问题,因为这里创建的是多维数组,而不是嵌套列表。
此外,Numba 支持在 CPU 上结合 parallel 选项时进行并行数组推导。
设置
在JIT编译的函数中,支持集合的所有方法和操作。
集合必须是严格同质的:Numba 将拒绝包含不同类型对象的任何集合,即使这些类型是兼容的(例如,{1, 2.5}
会被拒绝,因为它包含一个 int
和一个 float
)。集合中不支持使用引用计数类型,例如字符串。
备注
当将一个集合传递给即时编译的函数时,对该集合所做的任何修改在函数返回之前对Python解释器是不可见的。
类型化字典
警告
numba.typed.Dict
是一个实验性功能。API 可能在未来的版本中发生变化。
备注
在0.44之前的版本中,dict()
是不被支持的。目前,调用 dict()
会转换为调用 numba.typed.Dict()
。
Numba 支持使用 dict()
。这种使用在语义上等同于 {}
和 numba.typed.Dict()
。它将创建一个 numba.typed.Dict
的实例,其中键值类型将通过使用情况推断。Numba 还明确支持 dict(iterable)
构造函数。
Numba 不完全支持 Python 的 dict
,因为它是一个可以包含任何 Python 类型的无类型容器。为了生成高效的机器代码,Numba 需要字典的键和值具有固定的类型,并且需要提前声明。为了实现这一点,Numba 有一个类型化的字典 numba.typed.Dict
,其类型推断机制必须能够通过使用推断键值类型,或者用户必须使用 Dict.empty()
构造方法显式声明键值类型。这个类型化字典的 API 与 Python 的 dict
相同,它实现了 collections.MutableMapping
接口,并且可以在解释型 Python 代码和 JIT 编译的 Numba 函数中使用。由于类型化字典以 Numba 的本地、未装箱的数据布局存储键和值,因此将 Numba 字典传递到 nopython 模式的开销非常低。然而,这意味着从 Python 解释器使用类型化字典比使用常规字典要慢,因为 Numba 在获取或设置项目时必须对键和值对象进行装箱和拆箱。
与Python的``dict``相比,类型化字典的一个重要区别是,当存储键或值时会发生**隐式类型转换**。因此,如果类型转换失败,*setitem*操作可能会失败。
需要注意的是,Numba 类型化字典是使用与 CPython 3.7 字典相同的算法实现的。因此,类型化字典是有序的,并且具有与 CPython 实现相同的冲突解决机制。
关于类型规范,如上所述,类型字典中可以作为键和/或值使用的类型存在限制,最值得注意的是,Numba 的 Set
和 List
类型目前不支持。可接受的关键字/值类型包括但不限于:Unicode字符串、数组(仅限值)、标量、元组。随着Numba的不断改进,预计这些限制将会放宽。
以下是使用 dict()
和 {}
创建 numba.typed.Dict
实例并让编译器推断键值类型的示例:
1from numba import njit
2import numpy as np
3
4@njit
5def foo():
6 d = dict()
7 k = {1: np.arange(1), 2: np.arange(2)}
8 # The following tells the compiler what the key type and the
9 # value
10 # type are for `d`.
11 d[3] = np.arange(3)
12 d[5] = np.arange(5)
13 return d, k
14
15d, k = foo()
16print(d) # {3: [0 1 2], 5: [0 1 2 3 4]}
17print(k) # {1: [0], 2: [0 1]}
以下是一个从解释代码创建 numba.typed.Dict
实例并在 jit 代码中使用字典的示例:
1import numpy as np
2from numba import njit
3from numba.core import types
4from numba.typed import Dict
5
6# The Dict.empty() constructs a typed dictionary.
7# The key and value typed must be explicitly declared.
8d = Dict.empty(
9 key_type=types.unicode_type,
10 value_type=types.float64[:],
11)
12
13# The typed-dict can be used from the interpreter.
14d['posx'] = np.asarray([1, 0.5, 2], dtype='f8')
15d['posy'] = np.asarray([1.5, 3.5, 2], dtype='f8')
16d['velx'] = np.asarray([0.5, 0, 0.7], dtype='f8')
17d['vely'] = np.asarray([0.2, -0.2, 0.1], dtype='f8')
18
19# Here's a function that expects a typed-dict as the argument
20@njit
21def move(d):
22 # inplace operations on the arrays
23 d['posx'] += d['velx']
24 d['posy'] += d['vely']
25
26print('posx: ', d['posx']) # Out: posx: [1. 0.5 2. ]
27print('posy: ', d['posy']) # Out: posy: [1.5 3.5 2. ]
28
29# Call move(d) to inplace update the arrays in the typed-dict.
30move(d)
31
32print('posx: ', d['posx']) # Out: posx: [1.5 0.5 2.7]
33print('posy: ', d['posy']) # Out: posy: [1.7 3.3 2.1]
以下是一个从jit代码创建 numba.typed.Dict
实例并在解释代码中使用字典的示例:
1import numpy as np
2from numba import njit
3from numba.core import types
4from numba.typed import Dict
5
6# Make array type. Type-expression is not supported in jit
7# functions.
8float_array = types.float64[:]
9
10@njit
11def foo():
12 # Make dictionary
13 d = Dict.empty(
14 key_type=types.unicode_type,
15 value_type=float_array,
16 )
17 # Fill the dictionary
18 d["posx"] = np.arange(3).astype(np.float64)
19 d["posy"] = np.arange(3, 6).astype(np.float64)
20 return d
21
22d = foo()
23# Print the dictionary
24print(d) # Out: {posx: [0. 1. 2.], posy: [3. 4. 5.]}
需要注意的是,numba.typed.Dict
不是线程安全的。具体来说,从多个线程修改字典的函数可能会导致内存损坏,从而引发一系列可能的故障。然而,只要字典的内容在并行访问期间不发生变化,就可以安全地从多个线程读取字典。
字典推导
Numba 支持字典推导,前提是 numba.typed.Dict
实例可以从推导中创建。例如:
In [1]: from numba import njit
In [2]: @njit
...: def foo(n):
...: return {i: i**2 for i in range(n)}
...:
In [3]: foo(3)
Out[3]: DictType[int64,int64]<iv=None>({0: 0, 1: 1, 2: 4})
初始值
警告
这是一个实验性功能!
类型化的字典,其:
使用大括号语法构建
使用字面字符串键
具有字面类型的值
它们的初始值将存储在类型的 .initial_value
属性中,以便在编译时允许检查这些值。如果需要,为了强制基于值的分派,literally 函数将接受一个类型化的字典。
示例:
1from numba import njit, literally
2from numba.extending import overload
3
4# overload this function
5def specialize(x):
6 pass
7
8@overload(specialize)
9def ol_specialize(x):
10 iv = x.initial_value
11 if iv is None:
12 return lambda x: literally(x) # Force literal dispatch
13 assert iv == {'a': 1, 'b': 2, 'c': 3} # INITIAL VALUE
14 return lambda x: literally(x)
15
16@njit
17def foo():
18 d = {'a': 1, 'b': 2, 'c': 3}
19 d['c'] = 20 # no impact on .initial_value
20 d['d'] = 30 # no impact on .initial_value
21 return specialize(d)
22
23result = foo()
24print(result) # {a: 1, b: 2, c: 20, d: 30} # NOT INITIAL VALUE!
异构字面字符串键字典
警告
这是一个实验性功能!
Numba 支持使用静态声明的字符串键到任何值的字典,例如:
d = {'a': 1, 'b': 'data', 'c': 2j}
这些字典的主要用途是协调高级编译调度或作为配置对象的容器。这些字典表现为 LiteralStrKeyDict
类型,该类型继承自 Literal
,因此键的字面值和项的类型在编译时是可用的。例如:
1import numpy as np
2from numba import njit, types
3from numba.extending import overload
4
5# overload this function
6def specialize(x):
7 pass
8
9@overload(specialize)
10def ol_specialize(x):
11 ld = x.literal_value
12 const_expr = []
13 for k, v in ld.items():
14 if isinstance(v, types.Literal):
15 lv = v.literal_value
16 if lv == 'cat':
17 const_expr.append("Meow!")
18 elif lv == 'dog':
19 const_expr.append("Woof!")
20 elif isinstance(lv, int):
21 const_expr.append(k.literal_value * lv)
22 else: # it's an array
23 const_expr.append("Array(dim={dim}".format(dim=v.ndim))
24 const_strings = tuple(const_expr)
25
26 def impl(x):
27 return const_strings
28 return impl
29
30@njit
31def foo():
32 pets_ints_and_array = {'a': 1,
33 'b': 2,
34 'c': 'cat',
35 'd': 'dog',
36 'e': np.ones(5,)}
37 return specialize(pets_ints_and_array)
38
39result = foo()
40print(result) # ('a', 'bb', 'Meow!', 'Woof!', 'Array(dim=1')
关于这类字典需要注意的重要事项:
它们是不可变的,使用突变方法例如
.pop()
会导致编译失败。支持只读静态访问和只读方法,例如len()
。动态访问项目是不可能的,例如
some_dictionary[x]
,对于一个不是编译时常量的值x
。这是因为无法静态地确定被访问项目的类型。在编译器内部,这些字典实际上只是带有某些额外内容的命名元组,使它们看起来像是字典。
它们不能从编译函数返回给解释器。
.keys()
、.values()
和.items()
方法在功能上都起作用,但返回的是元组而不是可迭代对象。
无
None 值支持用于身份测试(当使用 optional
类型时)。
字节, 字节数组, 内存视图
The bytearray
类型和在 Python 3 中的 bytes
类型支持索引、迭代和获取 len()。
The memoryview
类型支持索引、切片、迭代、获取 len(),以及以下属性:
内置函数
支持以下内置函数:
getattr()
: 属性必须是一个字符串字面量,并且返回类型不能是函数类型(例如getattr(numpy, 'cos')
不支持,因为它返回一个函数类型)。int
:仅支持单参数形式iter()
: 仅支持单参数形式next()
: 仅限单参数形式print()
: 仅支持数字和字符串;不支持file
或sep
参数range
: range 的唯一允许使用方式是作为可调用函数(不能将 range 作为参数传递给 jitted 函数或从 jitted 函数返回 range)。sorted()
:key
参数不被支持str()
type()
: 仅支持单参数形式,并且仅适用于某些类型(例如数字和命名元组)
哈希
支持 hash()
内置函数,并为所有支持的可哈希类型生成哈希值,具有以下特定于Python版本的行为:
在 Python 3 下,Numba 计算的哈希值将与 CPython 在 sys.hash_info.algorithm
为 ``siphash24``(默认)时计算的哈希值完全匹配。
PYTHONHASHSEED
环境变量以 CPython 文档中描述的方式精确影响哈希行为。
标准库模块
array
通过缓冲协议提供了对 array.array
类型的有限支持。支持索引、迭代和获取 len()。除了 "u"
之外的所有类型代码都受支持。
cmath
以下是 cmath
模块中支持的函数:
collections
命名元组类,如由 collections.namedtuple()
返回的,以与常规元组相同的方式得到支持。构造函数中的属性访问和命名参数也得到支持。
在 Numba 代码中创建命名元组类 不 受支持;该类必须在全局级别创建。
ctypes
Numba 能够调用 ctypes 声明的函数,支持以下参数和返回类型:
enum
支持 enum.Enum
和 enum.IntEnum
子类。
math
以下是 math
模块中支持的函数:
operator
以下 operator
模块中的函数是被支持的:
operator.imatmul()
(Python 3.5 及以上)operator.matmul()
(Python 3.5 及以上)
functools
支持 functools.reduce()
函数,但 initializer 参数是必需的。
random
Numba 支持 random
模块中的顶级函数,但不允许你创建单独的 Random 实例。使用的是梅森旋转生成器,具有专用的内部状态。它在启动时使用从操作系统中提取的熵进行初始化。
random.getrandbits()
: 位数不能大于64random.seed()
: 仅使用整数参数random.shuffle()
: 序列参数必须是一个一维的 Numpy 数组或提供缓冲区的对象(例如bytearray
或array.array
);第二个(可选)参数不受支持
警告
从非Numba代码(或从 对象模式 代码)调用 random.seed()
将种子化Python随机生成器,而不是Numba随机生成器。要种子化Numba随机生成器,请参见下面的示例。
from numba import njit
import random
@njit
def seed(a):
random.seed(a)
@njit
def rand():
return random.random()
# Incorrect seeding
random.seed(1234)
print(rand())
random.seed(1234)
print(rand())
# Correct seeding
seed(1234)
print(rand())
seed(1234)
print(rand())
备注
自版本0.28.0起,生成器是线程安全和分叉安全的。每个线程和每个进程将生成独立的随机数流。
参见
Numba 还支持 Numpy 随机模块 中的大多数其他分布。
heapq
以下 heapq
模块中的函数被支持:
heapq.nlargest()
: 仅前两个参数heapq.nsmallest()
: 仅前两个参数
注意:堆必须至少用一个值进行初始化,以便推断其类型;堆中的项目假定为同类型。
第三方模块
cffi
与 ctypes 类似,Numba 能够调用 cffi 声明的外部函数,使用以下 C 类型及其派生的指针类型:
char
short
int
long
long long
unsigned char
unsigned short
unsigned int
unsigned long
unsigned long long
int8_t
uint8_t
int16_t
uint16_t
int32_t
uint32_t
int64_t
uint64_t
float
double
ssize_t
size_t
void
cffi.FFI
和 CompiledFFI
对象的 from_buffer()
方法支持传递 Numpy 数组和其他类似缓冲区的对象。仅接受 连续 参数。from_buffer()
的参数被转换为适当 C 类型的原始指针(例如,float64
数组的 double *
)。
在从缓冲区转换为适当的C类型时,可以使用Numba注册额外的类型映射。这可能包括结构体类型,尽管只允许调用接受结构体指针的函数——按值传递结构体是不支持的。要注册映射,请使用:
- numba.core.typing.cffi_utils.register_type(cffi_type, numba_type)
外部cffi模块在使用Numba编译函数中的任何函数之前,必须先在Numba中注册:
- numba.core.typing.cffi_utils.register_module(mod)
使用 Numba 注册 cffi 的离线模块
mod
。
内联 cffi 模块无需注册。