Skip to content

2.6。支持的 Python 功能

原文: http://numba.pydata.org/numba-doc/latest/reference/pysupported.html

除了下面的语言部分,它适用于对象模式nopython 模式,此页面仅列出 nopython 模式支持的功能]。

警告

在某些情况下,Numba 行为与 Python 语义不同。我们强烈建议审查与 Python 语义的偏差,以熟悉这些差异。

2.6.1。语言

2.6.1.1。构造

Numba 努力支持尽可能多的 Python 语言,但 Numba 编译的函数中没有一些语言功能。目前不支持以下 Python 语言功能:

  • 类定义
  • 异常处理(try .. excepttry .. finally
  • 上下文管理(with语句)
  • 一些理解(支持列表理解,但不支持字典,集合或生成器理解)
  • 发电机代表团(yield from

raise语句以多种形式支持:

  • raise(重新提高当前例外)
  • raise SomeException
  • raise SomeException(<arguments>):在 nopython 模式中,构造函数参数必须是编译时常量

同样,支持assert语句,有或没有错误消息。

2.6.1.2。功能

2.6.1.2.1。函数调用

Numba 支持使用位置和命名参数的函数调用,以及具有默认值和*args的参数(注意*args的参数只能是元组,而不是列表)。不支持显式**kwargs

只要可以完全内联函数,就支持对本地定义的内部函数的函数调用。

2.6.1.2.2。作为参数的函数

函数可以作为参数传递给另一个函数。但是,他们无法归还。例如:

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 不将函数对象作为真实对象处理。将函数分配给变量后,无法将变量重新分配给其他函数。

2.6.1.2.3。内部功能和闭合

Numba 现在支持内部函数,只要它们是非递归的并且只在本地调用,但不作为参数传递或作为结果返回。还支持在内部函数内使用闭包变量(在外部作用域中定义的变量)。

2.6.1.2.4。递归调用

支持大多数递归调用模式。唯一的限制是递归被调用者必须有一个返回的控制流路径而不会递归。 Numba 能够在不指定函数类型签名的情况下对类型推断递归函数(这在 numba 0.28 及更早版本中是必需的)。递归调用甚至可以调用函数的不同重载。

2.6.1.3。发电机

Numba 支持生成器功能,并且能够在对象模式nopython 模式中编译它们。返回的生成器既可以使用 Numba 编译的代码,也可以使用常规的 Python 代码。

不支持发生器的协同特征(即 generator.send()generator.throw()generator.close() 方法)。

2.6.2。内置类型

2.6.2.1。 int,bool

支持算术运算和真值。

支持以下属性和方法:

  • .conjugate()
  • .real
  • .imag

2.6.2.2。浮动,复杂

支持算术运算和真值。

支持以下属性和方法:

  • .conjugate()
  • .real
  • .imag

2.6.2.3。 str

Numba 在 Python 3 中支持(Unicode)字符串。字符串可以作为参数传递到 nopython 模式,以及从 nopython 模式构造和返回。与 Python 一样,切片(即使长度为 1)也会返回一个新的引用计数字符串。将来可能会引入有效访问单个字符的优化代码路径。

内存中的表示与 Python 3.4 中引入的相同,每个字符串都有一个标记,用于指示字符串是否在内存中使用 1,2 或 4 字节字符宽度。当组合不同编码的字符串时(如串联),结果字符串自动使用两个输入字符串的较大字符宽度。字符串切片也使用与原始字符串相同的字符宽度,即使切片可以用较窄的字符宽度表示。 (当然,这些细节对用户是不可见的。)

目前支持以下函数,属性和方法:

  • len()
  • +(字符串串联)
  • in.contains()
  • ==<<=>>=(比较)
  • .startswith()
  • .endswith()
  • .find()
  • .split()
  • .join()

在未来的 Numba 版本中将添加其他操作以及对 Python 2 字符串/ Python 3 字节的支持。可能永远不会支持 Python 2 Unicode 对象。

警告

已知某些操作的性能比 CPython 实现慢。这些包括子串搜索(in.contains()find())和字符串创建(如.split())。提高字符串性能是一项持续的任务,但 CPython 的速度不可能单独超越基本的字符串操作。 Numba 最成功地用于碰巧涉及字符串的较大算法,其中基本字符串操作不是瓶颈。

2.6.2.4。元组

支持以下操作:

  • 元组结构
  • 元组拆包
  • 元组之间的比较
  • 对同类元组进行迭代和索引
  • 元组之间的加法(连接)
  • 用常量切片切片元组
  • 元组的索引方法

2.6.2.5。清单

支持从 JIT 编译的函数创建和返回列表,以及所有方法和操作。列表必须严格同质:Numba 将拒绝任何包含不同类型对象的列表,即使类型是兼容的(例如,[1, 2.5]被拒绝,因为它包含 intfloat )。

例如,要创建数组列表:

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])]

2.6.2.5.1。列表反射

在 nopython 模式下,Numba 不对 Python 对象进行操作。 list被编译成内部表示。任何list参数必须在进入 nopython 模式的过程中转换为此表示形式,并且必须通过称为 reflection 的进程在原始 Python 对象中恢复其包含的元素。需要反射来维护与常规 Python 代码中相同的语义。但是,对于大型列表,反射过程可能很昂贵,而对于包含反射数据类型的列表则不支持。由于此限制,用户无法使用 list-of-list 作为参数。

注意

将列表传递给 JIT 编译的函数时,在函数返回之前,对 Python 解释器不会显示对列表所做的任何修改。 (反射过程的局限性。)

警告

列表排序当前使用快速排序算法,该算法具有与 Python 使用的算法不同的性能特征。

2.6.2.5.2。列表理解

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() 的调用。以下是生成 2D 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 能够优化程序以直接分配和初始化结果数组,而无需分配中间列表对象。因此,这里列表推导的嵌套不是问题,因为这里创建了多维数组而不是嵌套列表。

此外,当与 CPU 上的并行选项结合使用时,Numba 支持并行阵列压缩。

2.6.2.6。设置

JIT 编译的函数支持集合上的所有方法和操作。

集必须是严格同质的:Numba 将拒绝包含不同类型对象的任何集合,即使类型是兼容的(例如,{1, 2.5}被拒绝,因为它包含 intfloat )。

注意

将一个集合传递给 JIT 编译的函数时,在该函数返回之前,对该集合所做的任何修改都不会对 Python 解释器可见。

2.6.2.7。字典

警告

numba.typed.Dict是一项实验性功能。 API 可能会在将来的版本中发生变化。

Numba 不直接支持 Python dict,因为它是一个无类型的容器,可以将任何 Python 类型作为成员。为了生成有效的机器代码,Numba 需要密钥和字典的值具有预先声明的固定类型。为了实现这一点,Numba 有一个类型字典numba.typed.Dict,用户必须使用Dict.empty()构造函数方法显式声明 key-type 和 value-type。这个类型化的字典与 Python dict具有相同的 API,它实现了collections.MutableMapping接口,可用于解释的 Python 代码和 JIT 编译的 Numba 函数。因为键入的字典在 Numba 的本机,未装箱的数据布局中存储键和值,所以将 Numba 字典传递到 nopython 模式的开销非常低。但是,这意味着使用 Python 解释器中的类型字典比常规字典慢,因为 Numba 在获取或设置项目时必须对 key 和 unbox 进行包装和取消设置。

与 Python 的dict相比,类型字典的一个重要区别是当存储键或值时会发生隐式转换。因此,如果类型转换失败, setitem 操作可能会失败。

注意

numba.typed.Dict尚未使用Dict()构造,必须使用Dict.empty(key_type, value_type)类方法来构造类型化字典。

应该注意,Numba 类型字典是使用与 CPython 3.7 字典相同的算法实现的。因此,键入的字典是有序的,并且具有与 CPython 实现相同的冲突解决方案。

除了上面关于类型规范之外,对于可以用作键入字典中的键和/或值的类型存在限制,最值得注意的是当前不支持 Numba SetList类型。可接受的键/值类型包括但不限于:unicode 字符串,数组,标量,元组。随着 Numba 不断改进,预计这些限制将会放松。

这是从解释代码创建numba.typed.Dict实例并在 jit 代码中使用字典的示例:

from ex_typed_dict_from_cpython of examples/dict_usage.py

|

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

|

import numpy as np
from numba import njit
from numba import types
from numba.typed import Dict

# The Dict.empty() constructs a typed dictionary.
# The key and value typed must be explicitly declared.
d = Dict.empty(
    key_type=types.unicode_type,
    value_type=types.float64[:],
)

# The typed-dict can be used from the interpreter.
d['posx'] = np.asarray([1, 0.5, 2], dtype='f8')
d['posy'] = np.asarray([1.5, 3.5, 2], dtype='f8')
d['velx'] = np.asarray([0.5, 0, 0.7], dtype='f8')
d['vely'] = np.asarray([0.2, -0.2, 0.1], dtype='f8')

# Here's a function that expects a typed-dict as the argument
@njit
def move(d):
    # inplace operations on the arrays
    d['posx'] += d['velx']
    d['posy'] += d['vely']

print('posx: ', d['posx'])  # Out: posx:  [1\.  0.5 2\. ]
print('posy: ', d['posy'])  # Out: posy:  [1.5 3.5 2\. ]

# Call move(d) to inplace update the arrays in the typed-dict.
move(d)

print('posx: ', d['posx'])  # Out: posx:  [1.5 0.5 2.7]
print('posy: ', d['posy'])  # Out: posy:  [1.7 3.3 2.1]

|

这是一个从 jit 代码创建numba.typed.Dict实例并在解释代码中使用字典的示例:

from ex_typed_dict_njit of examples/dict_usage.py

|

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

|

import numpy as np
from numba import njit
from numba import types
from numba.typed import Dict

# Make array type.  Type-expression is not supported in jit functions.
float_array = types.float64[:]

@njit
def foo():
    # Make dictionary
    d = Dict.empty(
        key_type=types.unicode_type,
        value_type=float_array,
    )
    # Fill the dictionary
    d["posx"] = np.arange(3).astype(np.float64)
    d["posy"] = np.arange(3, 6).astype(np.float64)
    return d

d = foo()
# Print the dictionary
print(d)  # Out: {posx: [0\. 1\. 2.], posy: [3\. 4\. 5.]}

|

2.6.2.8。无

身份测试支持 None 值(使用 optional 类型时)。

2.6.2.9。 bytes,bytearray,memoryview

bytearray 类型,在 Python 3 上, bytes 类型支持索引,迭代和检索 len()。

memoryview 类型支持索引,切片,迭代,检索 len()以及以下属性:

2.6.3。内置功能

支持以下内置函数:

  • abs()
  • bool
  • complex
  • divmod()
  • enumerate()
  • float
  • hash() (参见下面的 Hashing
  • int :只有单参数形式
  • iter() :只有单参数形式
  • len()
  • min()
  • max()
  • next() :只有单参数形式
  • print() :仅限数字和字符串;没有filesep参数
  • range :即使在 Python 2 中,语义也类似于 Python 3:返回范围对象而不是值数组。范围的唯一允许使用是作为可调用函数(不能将范围作为参数传递给 jitted 函数或从 jitted 函数返回范围)。
  • round()
  • sorted() :不支持key参数
  • type():只有单参数形式,并且只在某些类型上(例如数字和命名元组)
  • zip()

2.6.3.1。哈希

支持 hash() 内置并为所有支持的可哈希类型生成哈希值,具有以下特定于 Python 版本的行为:

在 Python 3 下,Numba 计算的哈希值将与sys.hash_info.algorithmsiphash24(默认值)的条件下 CPython 中计算的哈希值完全匹配。

在 Python 2 下,由 Numba 计算的哈希值将遵循为 Python 3 描述的行为,sys.hash_info.algorithm被模拟为siphash24。没有尝试复制 Python 2 散列行为。

PYTHONHASHSEED环境变量以与 CPython 文档中描述的方式完全相同的方式影响散列行为。

2.6.4。标准库模块

2.6.4.1。 array

通过缓冲协议提供对 array.array 类型的有限支持。支持索引,迭代和获取 len()。除"u"外,支持所有类型代码。

2.6.4.2。 cmath

支持 cmath 模块的以下功能:

2.6.4.3。 collections

collections.namedtuple() 返回的命名元组类的支持方式与支持常规元组的方式相同。还支持构造函数中的属性访问和命名参数。

在 Numba 代码中创建一个命名的元组类是 _ 而不是 _ 支持;必须在全局级别创建该类。

2.6.4.4。 ctypes

Numba 能够使用以下参数和返回类型调用 ctypes 声明的函数:

2.6.4.5。 enum

支持 enum.Enumenum.IntEnum 子类。

2.6.4.6。 math

支持 math 模块的以下功能:

2.6.4.7。 operator

支持 operator 模块的以下功能:

2.6.4.8。 functools

支持 functools.reduce() 功能,但需要初始值设定项参数。

2.6.4.9。 random

Numba 支持 random 模块的顶级功能,但不允许您创建单独的 Random 实例。使用 Mersenne-Twister 发电机,具有专用的内部状态。它在启动时初始化,并从操作系统中提取熵。

注意

从非 Numba 代码(或从对象模式代码)调用 random.seed() 将播种 Python 随机生成器,而不是 Numba 随机生成器。

注意

从版本 0.28.0 开始,发生器是线程安全的和叉安全的。每个线程和每个进程将产生独立的随机数流。

也可以看看

Numba 还支持来自 Numpy 随机模块的大多数其他发行版。

2.6.4.10。 heapq

支持 heapq 模块的以下功能:

注意:必须为堆添加至少一个值以允许其类型被推断;假设堆项目在类型上是同类的。

2.6.5。第三方模块

2.6.5.1。 cffi

与 ctypes 类似,Numba 能够使用以下 C 类型和任何派生指针类型调用 cffi - 声明的外部函数:

  • 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.FFICompiledFFI对象的from_buffer()方法支持传递 Numpy 数组和其他类似缓冲区的对象。只接受 _ 连续 _ 参数。 from_buffer()的参数被转换为适当 C 类型的原始指针(例如float64数组的double *)。

可以向 Numba 注册用于从缓冲区到适当的 C 类型的转换的附加类型映射。这可能包括结构类型,但它只允许调用接受结构指针的函数 - 不支持按值传递结构。要注册映射,请使用:

numba.cffi_support.register_type(cffi_type, numba_type)

在使用 Numba 编译的函数中的任何函数之前,必须在 Numba 中注册外部 cffi 模块:

numba.cffi_support.register_module(mod)

使用 Numba 注册 cffi 外线模块mod

内联 cffi 模块不需要注册。



回到顶部