gpt4 book ai didi

python - Cython - 替换 def __init__() 方法,因为 Cython 的 Python 函数和方法无法处理值为 0 的无符号字符数组

转载 作者:行者123 更新时间:2023-12-01 00:17:01 24 4
gpt4 key购买 nike

全部。下面有一个 Cython 代码示例,其中有一个无符号字符数组,a 填充有无符号整数。当我将此数组传递给 Python def 方法时,包含 0 的索引之后的任何索引的值都会变得困惑。

在此示例中,由于 0 值位于第 6 个索引处,因此传递到 __cinit__() 方法的数组中的所有后续数组索引都有不正确的值。对于 __init__() 方法或使用 Python 声明 def 的任何函数或方法,也会发生此行为。

但是,当数组传递到任何 cdefcpdef 函数或方法时,数组的值是正确的。

所以,我有两个问题(请注意,我使用的是 .pyx 运行程序文件):

  1. 我是否错误地将数组传递到 __cinit__() 方法中?还有其他方法吗?
  2. 或者,是否有一种 Cythonic 方法可以替换 def __cinit__() 方法?当然,我可以使用解决方法并使用 cdefcpdef 方法,特别是对于我展示的这个简单的小示例,但我想了解是否有换一种方式...

代码:

cdef class Classical:
def __cinit__(self, unsigned char *b):
for x in range(0, 12):
print b[x], " init" # This does not work

cdef void bar(self, unsigned char *b):
for x in range(0, 12):
print b[x], " method" # This works fine

def foo(unsigned char *b):
for x in range(0, 12):
print b[x], " function" # This does not work either

cdef unsigned char a[12]
a = [
83,
12,
85,
31,
7,
0,
91,
11,
0,
12,
77,
100
]
Classical(a).bar(a)
foo(a)

输出:

83  init
12 init
85 init
31 init
7 init
0 init
0 init
0 init
0 init
0 init
0 init
0 init
83 method
12 method
85 method
31 method
7 method
0 method
91 method
11 method
0 method
12 method
77 method
100 method
83 function
12 function
85 function
31 function
7 function
0 function
100 function
0 function
0 function
0 function
0 function
0 function

最佳答案

def 函数的所有参数都是 Python 对象。一个char * ( unsigned char * 也是如此)不是 Python 对象,但是可以自动将(某些)Python 对象转换为 char * 。所以

def foo(char *x):
...

对于 Cython 来说意味着:检查传递的 Python 对象是否可以转换为 cdef char * ,执行转换并在函数体中使用此转换的结果。

当使用 char * 调用 def 函数时(另请参阅此有点相关的 SO-post )作为参数:

cdef char a[12]
....
bar(a) # a decays to char *

Cython 执行以下操作:使用 char * 的自动转换假设它是一个以 null 结尾的 c 字符串到一个字节对象,并将这个临时字节对象传递给 def -功能bar .

这意味着在你的情况下:

  • 调用 foo(a)创建一个长度为 5 的临时字节对象(而不是 12,因为第 6 个元素是 0 ),前 5 个字符将被复制到其中。
  • 函数内部foo该字节对象缓冲区的地址被用作 unsigned char *b ,现在只有 6 个元素(包括尾随 \0 ),因此可以通过 b[6] 访问它是未定义的行为,可能会导致段错误。

您可以验证ab通过指向不同的地址

print("Address:", <unsigned long long>(&a[0])) # or &b[0]

所以问题实际上是,当你调用 foo 时不是整个数组都转换为临时bytes -目的。从/到 char * 的转换Cython-documentation 中描述。在您的情况下,调用应该是:

foo(a[:12]) #pass the length explicitly, so cython doesn't have to depend on '\0'

现在打印以下内容:

83  function
12 function
85 function
31 function
7 function
0 function
91 function
11 function
0 function
12 function
77 function
100 function
<小时/>

cdef 的情况有所不同-函数,其中 char *停留char *并且不会转换为 Python 对象。然而,__cinit__必须是def函数,因此在这种情况下通常是 cdef - 使用工厂函数,如the answer pointed out by @DavidW ,例如:

cdef class Classical:
...
@staticmethod
cdef Classical create(char* ptr):
obj = <Classical>Classical.__new__(Classical) # __init__ isn't called!
# set up obj while using ptr
...
return obj

显然,Classical.create只能从 Cython 代码中使用,但另一方面,只有 Cython 代码才有指针!

关于python - Cython - 替换 def __init__() 方法,因为 Cython 的 Python 函数和方法无法处理值为 0 的无符号字符数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59260575/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com