技术背景

前面我们写过几篇关于Cython的文章,例如Cython计算谐振势Cython与C语言的结合Cython调用CUDA Kernel函数。Cython有着非常Pythonic的编程范式,又具备着接近于C语言的性能,因此在很多对于性能有要求的Python软件中都会使用到Cython的性能优化。Cython的基本工作流程是,先将*.pyx文件转换为*.c的C语言代码,然后再使用gcc编译成一个*.so动态链接库文件,供Python或者其他语言的代码调用。

这里我们考虑一个较为特殊的场景:将Python端常用的Numpy数组,转换为C语言的结构体,然后执行相应的任务或者计算。

Cython结构体

在Cython中可以使用ctypedef struct来定义一个可以跟C语言通用的结构体,例如,我们可以定义一个原子坐标的结构体:

ctypedef struct CRD:
double x, y, z

这是一个三维空间中的原子坐标,在Python中就相当于一个shape为(3,)的数组。如果这是C++,那我们可以通过dynamic_cast等转换方式在数组和结构体之间进行转换。而C语言和Cython则是直接通过变量类型来进行转换,以下是一个完整的Cython示例:

ctypedef struct CRD:
double x, y, z cpdef int trans(double[:] crd):
cdef:
CRD* crd_s = <CRD*>&crd[0]
print (crd_s.y)
return 1

在这个示例中,我们输入给函数trans()的是一个shape为(3,)的数组,然后在cdef中将这个原子坐标转换为结构体的形式,最后在Cython中打印输出该原子的y坐标。我们用Cython编译这个文件之后,可以在Python中调用:

In [1]: from trans import trans

In [2]: import numpy as np

In [3]: a = np.array([1,2,3], dtype=np.float64)

In [4]: trans(a)
2.0
Out[4]: 1

需要注意的是,这种转换方式并不安全,这里我们仅仅演示一下这种转换方式的使用方法。

多原子坐标结构体

其实从C语言的角度还蛮好理解的,我们通过单个结构体可以定义一个原子的空间坐标,那么用一个指针,就可以定义多个原子的空间坐标。这里我们定义多原子坐标的结构体为:

ctypedef struct PATH:
CRD crds

其实这里还是表示一个单原子的空间坐标,但是从一维指向变成了二维指向,此时我们可以通过PATH来构造一个多原子坐标的指针:

ctypedef struct CRD:
double x, y, z ctypedef struct PATH:
CRD crds cpdef int trans(double[:] crd, double[:, :] path):
cdef:
int atoms = path.shape[0]
int i
CRD* crd_s = <CRD*>&crd[0]
PATH* path_s = <PATH*>&path[0][0]
print (crd_s.y)
for i in range(atoms):
print (path_s[i].crds.x, path_s[i].crds.y, path_s[i].crds.z)
return 1

同样的,我们可以在Cython编译之后,通过Python来调用这个trans函数:

from trans import trans
import numpy as np a = np.array([1,2,3], dtype=np.float64)
b = np.arange(12).reshape((4,3)).astype(np.float64) print (trans(a, b))

输出结果为:

2.0
0.0 1.0 2.0
3.0 4.0 5.0
6.0 7.0 8.0
9.0 10.0 11.0
1

当然,这里还是需要提醒一下,这种指针转换的方式并不安全,需要谨慎使用。

总结概要

这篇文章介绍了在Cython中定义结构体,并在Python的Numpy数组/MemoryView和自定义结构体之间进行数据转换的方法。Cython有着非常Pythonic的编程范式,又具有接近于C语言的性能,对于Python开发者而言确实是一个很棒的工具。

版权声明

本文首发链接为:https://www.cnblogs.com/dechinphy/p/cython-struct.html

作者ID:DechinPhy

更多原著文章:https://www.cnblogs.com/dechinphy/

请博主喝咖啡:https://www.cnblogs.com/dechinphy/gallery/image/379634.html

Cython将Numpy数组转为自定义结构体的更多相关文章

  1. Solidity的自定义结构体深入详解

    一.结构体定义 结构体,Solidity中的自定义类型.我们可以使用Solidity的关键字struct来进行自定义.结构体内可以包含字符串,整型等基本数据类型,以及数组,映射,结构体等复杂类型.数组 ...

  2. typedef和自定义结构体类型

    在自定义结构体类型时会用到typedef关键字.大家都知道typedef是取别名的意思,在C语言中跟它容易混淆的有const,#define等,其区别不在本篇文章讨论之列. /*定义单链表结点类型*/ ...

  3. qsettings 保存自定义结构体(QVariant与自定义结构体相互转化)

    参考博文:QVariant与自定义数据类型转换的方法. 这里摘取其关键内容: 1.将自定义数据类型使用Q_DECLARE_METATYPE宏进行声明,便于编译器识别. 2.在插入对象的时候,声明QVa ...

  4. iOS自定义结构体

    一.提要 通过以官方的CGSize为例,自定义Objective-C中的结构体,并使用. 二.CGSize 1.系统定义的CGSize结构体 struct CGSize { CGFloat width ...

  5. Qt--信号槽传递自定义结构体参数

    自定义结构体参数的信号槽连接 (1) 对于自定义的结构体参数,信号槽无法识别参数,导致信号槽连接不起作用.所以需要注册结构体参数.在结构体中声明结束的地方加上结构体注册. struct DealDet ...

  6. 传入的结构体指针强制转为实例化结构体*v

    struct val *v = (struct val *)arg;//传入的结构体指针强制转为实例化结构体*v struct val{ int num1; int num2; }; void *te ...

  7. matlab学习笔记12_2创建结构体数组,访问标量结构体,访问非标量结构体数组的属性,访问嵌套结构体中的数据,访问非标量结构体数组中多个元素的字段

    一起来学matlab-matlab学习笔记12 12_2 结构体 创建结构体数组,访问标量结构体,访问非标量结构体数组的属性,访问嵌套结构体中的数据,访问非标量结构体数组中多个元素的字段 觉得有用的话 ...

  8. MATLAB 单元数组 cell 和结构体 struct 的用法以及区别

    1. 前言 Matlab单元数组cell和结构体struct都可以将不同类型的相关数据集成到一个单一的变量中,使得大量的相关数据的处理变得非常简单而且方便.但是,需要注意的是,单元数组和结构体只是承载 ...

  9. 用set、map等存储自定义结构体时容器内部判别各元素是否相同的注意事项

    STL作为通用模板极大地方便了C++使用者的编程,因为它可以存储任意数据类型的元素 如果我们想用set与map来存储自定义结构体时,如下 struct pp { double xx; double y ...

  10. gin中绑定表单数据至自定义结构体

    package main import "github.com/gin-gonic/gin" type StructA struct { FieldA string `form:& ...

随机推荐

  1. CodeForces 1935A

    题目链接:Entertainment in MAC 思路 当当前操作次数n为偶数时,若原字符串大于反转字符串则可以将原字符串反转n - 2次,则得到的还是原字符串,此时反转一次,并将其再次反转的字符串 ...

  2. gitlab角色与权限

    用户在项目中的角色 Guest:访客.可以创建issue.发表评论,不能读写版本库.(就是看不了代码-) Reporter:Git项目测试人员.可以克隆代码,不能提交.QA.PM可以赋予这个权限. D ...

  3. 华为交换机配置端口模式时报错:Please renew the default configurations

    场景 在华为交换机上使用混杂端口时报这个错,原因是你之前已经将此端口加入了某个vlan 所以你需要undo之前配置的命令 解决方法 sys int G 0/0/1 #替换为报错的端口 undo por ...

  4. LVGL一键打包图片工具,全部图片打包成一个bin文件,支持nor flash XIP模式下直接访问数据显示

    最近做工程项目,需要用到LVGL,但是搜了很长时间没有看到合适的图片打包工具,大多都是生成数组或者单个的bin文件,这样烧录到nor flash很麻烦 后来看到一篇博客,博主的想法与我类似,不过他后面 ...

  5. Redis常见的16个使用场景

    1.缓存 String类型 例如:热点数据缓存(例如报表.明星出轨),对象缓存.全页缓存.可以提升热点数据的访问数据. 2.数据共享分布式 String 类型,因为 Redis 是分布式的独立服务,可 ...

  6. C#进行图片压缩(对jpg压缩效果最好)

    直接上代码 1 public static class ImageCompress 2 { 3 /// <summary> 4 /// 图片压缩 5 /// </summary> ...

  7. new操作符具体干了什么呢?

    new操作符的作用如下: 1.创建一个空对象2.由this变量引用该对象3.该对象继承该函数的原型4.把属性和方法加入到this引用的对象中5.新创建的对象由this引用,最后隐式地返回this.过程 ...

  8. Java BigDecimal 算术运算

    算术运算 BigDecimal bignum1 = new BigDecimal("10"); BigDecimal bignum2 = new BigDecimal(" ...

  9. Mybatis 快速入门(注解方式)

    导读 注解开发的方式只需要程序员开发Mapper接口即可,不需要编写映射文件(XML). 环境搭建 项目结构 SqlMapConfig.xml <!DOCTYPE configuration P ...

  10. 我跟你说@RefreshScope跟Spring事件监听一起用有坑!

    本文记录一下我在 Spring 自带的事件监听类添加 @RefreshScope 注解时遇到的坑,原本这两个东西单独使用是各自安好,但当大家将它们组合在一起时,会发现我们的事件监听代码被重复执行.希望 ...