我想在cython中使用像structarray这样的东西,我希望这个structarray在python中像在cython中一样容易访问。 基于一时兴起,我使用了一个使用dtype的recarray,看起来像我想要使用的结构。奇怪的是,它只是工作,并允许我使用一个c structarray,通过引擎盖;),是python用户的numpy recarray。
以下是我的示例
# This is a "structarray in cython with numpy recarrays" testfile
import numpy as np
cimport numpy as np
# My structarray has nodes with fields x and y
# This also works without packed, but I have seen packed used in other places where people asked similar questions
# I assume that for two doubles that is equivalent but is necessary for in8s in between
cdef packed struct node:
double x
double y
# I suppose that would be the equivalent numpy dtype?
# Note: During compilation it warns me about double to float downcasts, but I do not see where
nodetype = [('x' , np.float64),('y', np.float64)]
def fun():
# Make 10 element recarray
# (Just looked it up. A point where 1-based indexing would save a look in the docs)
mynode1 = np.recarray(10,dtype=nodetype)
# Recarray with cdef struct
mynode1 = np.recarray(10,dtype=nodetype)
# Fill it with non-garbage somewhere
mynode1[2].x=1.0
mynode1[2].y=2.0
# Brave: give recarray element to a c function assuming its equivalent to the struct
ny = cfuny(mynode1[2])
assert ny==2.0 # works!
# Test memoryview, assuming type node
cdef node [:] nview = mynode1
ny = cfunyv(nview,2)
assert ny==2.0 # works!
# This sets the numpy recarray value with a c function the gts a memoryview
cfunyv_set(nview,5,9.0)
assert mynode1[5].y==9.0 # alsow works!
return 0
# return node element y from c struct node
cdef double cfuny(node n):
return n.y
# give element i from memoryview of recarray to c function expecting a c struct
cdef double cfunyv(node [:] n, int i):
return cfuny(n[i])
# write into recarray with a function expecting a memoryview with type node
cdef int cfunyv_set(node [:] n,int i,double val):
n[i].y = val
return 0
当然,我不是第一个尝试这个的人。
Here例如同样的事情已经完成,它甚至声明这种用法将成为手册here的一部分,但我无法在页面上找到它。我怀疑它在某个时刻存在。还有一些涉及在这种自定义类型中使用字符串的讨论(例如here),从我收集的答案中,在cstruct上进行重组的可能性是预期的行为 ,讨论中讨论了关于给定示例的回归测试并在某个时刻修复了字符串错误。
我的问题
我找不到任何文档说明除了论坛答案之外这应该有用。有人能告诉我记录的位置吗?
并且,为了一些额外的好奇心
答案 0 :(得分:2)
这似乎没有直接记录。我可以给你的最佳参考是这里输入的内存视图docs。
而不是对numpy结构化dtypes的特定cython支持,而不是支持PEP 3118缓冲区协议的结果。 numpy为其数组公开了一个Py_buffer
结构,cython知道如何将它们转换为结构。
包装是必要的。我的understanding是x86在itemsize字节边界上对齐,而numpy结构化dtype被打包到尽可能小的空间。可能最明显的例子是:
%%cython
import numpy as np
cdef struct Thing:
char a
# 7 bytes padding, double must be 8 byte aligned
double b
thing_dtype = np.dtype([('a', np.byte), ('b', np.double)])
print('dtype size: ', thing_dtype.itemsize)
print('unpacked struct size', sizeof(Thing))
dtype size: 9
unpacked struct size 16
答案 1 :(得分:1)
回答最后一个子问题:
从主题的其他论坛条目来看,似乎打包是必要的,一旦更多有趣的数据类型是结构的一部分,它就可以工作。我不是编译器专家,我从未使用过结构打包,但我怀疑结构是否打包取决于编译器设置。这是否意味着在没有打包结构的情况下编译numpy的人需要在没有打包的情况下编译这个cython代码?
Numpy的行为是在运行时而不是编译时决定的。它将计算结构可能需要的最小空间量并分配其中的块。它不会被任何编译器设置更改,因此应该是可靠的。
因此总是需要 alignas
来匹配numpy。但是,它不会生成符合标准的C代码。相反,它使用GCC,MSVC(和其他)的扩展名。因此,它在当前存在的主要C编译器上工作正常,但原则上可能在将来的编译器上失败。看起来应该可以使用C11标准java.lang.NullPointerException
at java.base/java.util.regex.Matcher.getTextLength(Matcher.java:1769)
at java.base/java.util.regex.Matcher.reset(Matcher.java:416)
at java.base/java.util.regex.Matcher.<init>(Matcher.java:253)
at java.base/java.util.regex.Pattern.matcher(Pattern.java:1147)
at java.base/java.util.regex.Pattern.split(Pattern.java:1264)
at java.base/java.util.regex.Pattern.split(Pattern.java:1335)
at sbt.IO$.pathSplit(IO.scala:797)
at sbt.IO$.parseClasspath(IO.scala:912)
at sbt.compiler.CompilerArguments.extClasspath(CompilerArguments.scala:6
6)
at sbt.compiler.MixedAnalyzingCompiler$.withBootclasspath(MixedAnalyzing
Compiler.scala:188)
at sbt.compiler.MixedAnalyzingCompiler$.searchClasspathAndLookup(MixedAn
alyzingCompiler.scala:166)
at sbt.compiler.MixedAnalyzingCompiler$.apply(MixedAnalyzingCompiler.sca
la:176)
at sbt.compiler.IC$.incrementalCompile(IncrementalCompiler.scala:138)
at sbt.Compiler$.compile(Compiler.scala:152)
at sbt.Compiler$.compile(Compiler.scala:138)
at sbt.Defaults$.sbt$Defaults$$compileIncrementalTaskImpl(Defaults.scala
:860)
at sbt.Defaults$$anonfun$compileIncrementalTask$1.apply(Defaults.scala:8
51)
at sbt.Defaults$$anonfun$compileIncrementalTask$1.apply(Defaults.scala:8
49)
at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
at sbt.$tilde$greater$$anonfun$$u2219$1.apply(TypeFunctions.scala:40)
at sbt.std.Transform$$anon$4.work(System.scala:63)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:22
8)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:22
8)
at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:17)
at sbt.Execute.work(Execute.scala:237)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:228)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:228)
at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestric
tions.scala:159)
at sbt.CompletionService$$anon$2.call(CompletionService.scala:28)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executo
rs.java:514)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoo
lExecutor.java:1167)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPo
以符合标准的方式实现相同的功能,因此如果需要,可以有希望修改Cython。