Cython全教程2 多种定义方式

—— 本篇文章,主要讲述Cython中的四种定义关键字

全教程2 多种定义方式:

        在Cython中,关于定义的关键字有四个,分别是:

        cdefdefcpdefDEF

一、cdef定义关键字

        顾名思义,cdef关键字定义的是一个C函数/方法(CFunction),也用来定义C变量

        定义的东西只能Cython里调用而在Python里无法访问到。

        我相信,理解以下案例,即可掌握 (注意看代码旁的注释)

        (1)正确案例:

#cython: language_level=3
# -*- coding: UTF-8 -*-
# -*- file: test.pyx -*-###在Cython里: 可以单个定义变量/函数
cdef int cint_value1 = 66, cint_value2 = 88 #定义了两个int变量
cdef float cfloat_value = 10.0              #定义了一个float变量
cdef float *h = &cfloat_value               #定义了一个float指针变量cdef int* cint_list = [1, 2, 3]            #定义数组①:使用指针声明数组
cdef float[3] float_list1 = [1.0, 2.0]     #定义数组②:使用类Java声明数组
cdef list[3] float_list2 = [6.0, 7.0, 8.0] #定义数组③:使用python列表
cdef double double_list[2] = [12.2, 13.3]  #定义数组④:使用类C声明数组,不推荐cdef dict[int, str] dt = {}           #定义了一个字典,键为int,值为str。或者直接用dict也行cdef tuple tp = (1, 2, 3)
cdef tuple[3] tp = (1, 2, 3)
cdef tuple[int, int, int] _tp = (1, 2, 3)
cdef (int, int, int) __tp = (1, 2, 3) #上中下4种定义元组的方式都可以cdef tuple[list[3], dict[str, list[2]]] complex_tp  #定义复杂的也可以cdef void say_hello() noexcept: #声明这个函数里没有抛出错误print("Hello, Cython!")cdef int set_value(int* value) except *: #声明这个函数里抛出了错误if value == NULL:                    #在C函数参数列表里无需使用cdefraise Exception("野指针!")value[0] = 100return value[0]    #Cython里指针只能用下标表示cdef void say_more_hello() noexcept:cdef int _for _ in range(10):say_hello() #调用say_hello()函数###或者一次性大量定义
cdef:double d_value = 0.0 #double型bint is_ok = 1       #1/0,类似于bool型(其实就是bool型)unsigned int u_int = 0signed int s_int = -1void is_ok_say():print("我学会了" if is_ok else "我再想想")#定义了一个C++类
cdef class CppClass(object):cdef:int cppclassdef __cinit__(CppClass self) -> None: #注意1:__cinit__其实就是__init__self.cppclass = 100               #注意2:self最好也写上类型#注意3:Magic Method只能用def而不能用cdefcdef int get_cppclass(CppClass self) noexcept:return self.cppclasscdef object cppclass_plus1(CppClass self) noexcept: #C函数里也可以使用闭包cdef void inter_func():self.cppclass += 1return inter_func@staticmethodcdef void hello() noexcept:say_more_hello()@staticmethodcdef (int, int, int) get_tp() noexcept:return _tp

        结合以上,注意:

        :在C++类(cdef class)里,声明对象属性只能在类体里,也就是在cdef int cppclass那里,并且不能直接在声明的时候赋值(不能有默认值)。

        :在C++类(cdef class)里,魔法方法(特殊方法)不能使用cdef,只能使用def。

        :在C++类(cdef class)里,__cinit__方法类似于__init__方法,都属于初始化方法。但不同的是,__cinit__适合于给对象属性赋值,__init__适合调用函数/方法;__cinit__先于__init__执行(它们可以同时存在)。

        :定义的C变量/属性,能用的类型不外乎于(int, float, bint, list, dict, tuple, 自己定义的C类型, Cython自带的C类型),对于其他的类型,只能用object来声明。

        :在C++类(cdef class)里,C++类的父类只能是C++类或object类或Exception类,C++类不允许继承Py类。

        :对于C++类(cdef class),可以直接被Python访问到,但其里面的C函数不能被访问到

        (2)以下的是错误实例:

#cython: language_level=3
# -*- coding: UTF-8 -*-
# -*- file: test.pyx -*-cdef void* printf = print           #错误!只能用object来声明指针函数,或者说,Py函数只能用object接受,C函数可以用指针函数接受
cdef tuple[int] tp1 = (1, 2, 3)     #错误!声明的元组里面只能有一个int,即tuple[int]<->tuple[1]
cdef tuple tp2 = (1, 2, 3, 4, 5)    #正确!这样的话可以
cdef tuple[5] tp3 = (1, 2, 3, 4, 5) #正确!这样的话也可以from abc import ABC
cdef class CppClass(ABC): #错误!ABC为Py类,C++类只能仅能继承C++类/object/Exceptioncdef __cinit__(CppClass self) noexcept: #错误!特殊方法只能是def定义self.cppclass = 100 #错误!必须先在类体内定义才能当作对象属性使用def __repr__(CppClass self) -> str: #正确!特殊方法只能是def定义return ""

 (3)来个语境实例:

#cython: language_level=3
# -*- coding: UTF-8 -*-
# -*- file: test.pyx -*-#假设在D:/Test/test.pyx
cdef void say_hello() noexcept:print("Hello, Cython!")cdef class CppClass(object):def __cinit__(CppClass self) -> None:passcdef void say_more_hello1(CppClass self) noexcept:cdef int _for _ in range(10):say_hello()def say_more_hello2(CppClass self) -> None:cdef int _for _ in range(10):say_hello()#假设现在编译了,在D:/Test/main.py
from test import *say_hello() #报错!cdef定义的C函数只能在Cython里使用cpp: CppClass = CppClass() #允许!C++类直接可以在Python里使用cpp.say_more_hello1() #错误!cdef定义的C函数只能在Cython里使用,在Python里访问不到
cpp.say_more_hello2() #正确!def定义的Py函数可以使用,可以访问到

 (4)再举个实际的实例:

#cython: language_level=3
# -*- coding: UTF-8 -*-
# -*- file: test.pyx -*-import pygame
import tkintercdef class PygameRun(object):cdef object screen  #注意看此处,Py类声明的对象只能用object!cdef PygameRun run  #PgameRun是C++类,就是C类型,当然可以不用object了def __cinit__(PygameRun self) -> None:pygame.init()self.screen = pygame.display.set_mode((100, 100), RESIZABLE|SCALED, vsync=1)self.run = self...cdef object get_image(PygameRun self, str file) noexcept: #注意看此处,Py类声明的对象只能用object!return pygame.image.load(file).convert_alpha()cdef PygameRun get_pygamerun(PygameRun self) noexcept: #PygameRun是C++类,就是C类型return self.runcdef object get_pygamescreen(PygameRun self) noexcept: #Py类声明的对象就只能用object了return self.screencdef class TkinterRun(tkinter.Tk): #错误!C++类不能继承Py类!pass

二、def定义关键字

        就如在Python类似,def关键字是定义一个函数/方法(PyFunction),只不过在Cython里应该说为“定义一个Py函数/方法”。Py函数可以被Python调用,当然也能被Cython所调用。

        但需要注意以下操作:

       :Py函数里不能完成非Py函数的定义,也就是不能完成非Py函数的闭包

       :Py函数的参数列表不能出现指针类型

        ⭐:其实整个项目里几乎不怎么会出现Py函数,因为各个功能都是C函数实现的。可以说,在整个项目里,唯一的一个Py函数就是最后的主函数,以此汇总各个C类型C对象,来供Python调用。

        (1)正确案例:

#cython: language_level=3
# -*- coding: UTF-8 -*-
# -*- file: test.pyx -*-#假设在test.pyx
from typing import Anycdef class MyClass(object):cdef bint myclasscdef bint say_hello() noexcept:print("Hello, Cython!", end = ' ')return 1def main(*args: tuple, **kwargs: dict) -> Any:cdef MyClass my = MyClass()my.myclass = say_hello()return my#经过编译后:在test0.py
from test import *print(main().myclass) #最后输出 Hello, Cython 1

         (2)错误实例:

#cython: language_level=3
# -*- coding: UTF-8 -*-
# -*- file: test.pyx -*-cdef object CFunction1() noexcept:  #正确!cdef void inter() noexcept:print("This is CFuntion1's inter")return intercdef object CFunction2() noexcept:  #正确!def void inter() -> None:print("This is CFuntion2's inter")return interdef PyFunction1() -> object:  #正确!def inter() -> None:print("This is PyFuntion1's inter")return interdef PyFunction2() -> object:  #错误!cdef void inter() noexcept:print("This is PyFuntion2's inter")return inter

三、cpdef定义关键字

         顾名思义,cpdef关键字定义的是一个CP函数/方法(CpFunction)既能被Cython调用又能被Python函数调用的函数。

        虽然它叫CpFunction,其实它的规则就和CFunction类似

        一般什么时候使用呢?就是一个函数,又需要在Python里使用,又需要在Cython里使用,那么它就可以派上用场了。。使用条件比较苛刻,也不利于性能

        注意:

        ①:cpdef声明的函数都是CpFunction。

        :将其修饰class则声明成CFunction。

        就现阶段,我们仅仅需要知道如此就可以了,它用的不是很多。

四、DEF定义关键字:

        DEF关键字,一开始我遇到的时候是我在定义一个属性叫DEF(防御力)的时候,结果说什么也不让我命名,我一看好家伙都高亮了,结果发现还有这个关键字

        其实,这就类似于C语言里的预处理(宏),就是#define预处理语句。

        值得注意的是:

        :类似于C语言的#define语句,不需要写类型,在编译的时候会替换。

        :但也不如C语言的,因为仅仅只能定义基本的数据(str/ int/ float/ bytes)

        当然还有其他的预处理指令比如IF/ ELSE,这些以后我会出专门的章节来讲解的。

        最后这些常量会被归为Literal类型。 

五、编译步骤

        ①:先编写源文件.pyx: 创建Test.pyx

# cython language_level=3
# -*- coding: utf-8  -*-
# -*- file: Test.pyx -*-
# -*- CSDN: Daisy-Mo -*-
# -*- Git:  Rosysuki -*-cdef class Steps(object):cdef Steps say1(Steps self) noexcept:print("先编写源文件")return selfcdef Steps say2(Steps self) noexcept:print("再编译文件")return selfcdef Steps say3(Steps self) noexcept:print("最后调用扩展")return selfdef main(*args: tuple, **kwargs: dict) -> None:cdef Steps steps = Steps()(steps.say1().say2().say3())

        ②:再编写setup.py文件: 

# -*- coding: utf-8  -*-
# -*- file: setup.py -*-from setuptools import setup
from Cython.Build import cythonizesetup(ext_modules = cythonize(["Test.pyx"])
)

        ③:然后编写run.bat文件: 或者用cmd代替也可以

setup.py build_ext --inplace
PAUSE

        点击run.bat/在cmd里回车 之后运行,可得:  就是那个.pyd文件

         

         ④:检测是否可用: 编写main.py测试

from Test import mainmain()

        结果是: 

 

-*- 休息线 -*-

我相信,通过我的这些总结和分享,大家能够更加深入地了解Cython这个朋友,从而更有效地与它来一同优化自己的代码。同时,我也期待能够在这个过程中,与更多志同道合的朋友一起交流、学习和进步。

新春快乐🎇

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/65963.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Web开发(一)HTML5

Web开发&#xff08;一&#xff09;HTML5 写在前面 参考黑马程序员前端Web教程做的笔记&#xff0c;主要是想后面自己搭建网页玩。 这部分是前端HTML5CSS3移动web视频教程的HTML5部分。主要涉及到HTML的基础语法。 HTML基础 标签定义 HTML定义 HTML(HyperText Markup Lan…

MATLAB学习笔记目录

MATLAB学习笔记-生成纯音并保存-CSDN博客 MATLAB学习笔记-各种格式之间的转换 - 知乎 MATLAB学习笔记-胞组&#xff08;cell array&#xff09;转换为矩阵&#xff0c;cell2mat_matlab如何把元胞数组改为矩阵-CSDN博客MATLAB学习笔记-判断数组、结构体、数值、字符串是否相同…

Java-数据结构-栈与队列(常考面试题与单调栈)

在上一篇的学习中&#xff0c;我们学习了栈和队列的基本知识&#xff0c;以及它们对应都有哪些方法&#xff0c;在什么应用场景下如何使用&#xff0c;并且还对它们进行了模拟实现&#xff0c;而其实对于栈和队列的相关知识还远不止于此&#xff0c;而今天我们就对栈与队列进行…

JSON.stringify(res,null,2)的含义

JSON.stringify(res, null, 2) 是 JavaScript 中将对象转换为 JSON 字符串的方法&#xff0c;具体说明如下&#xff1a; 参数解释 res&#xff1a;要转换的对象。它可以是 JavaScript 中的任意类型&#xff0c;如对象、数组、字符串、数字等。例如&#xff0c;{name: "K…

Spring 项目 基于 Tomcat容器进行部署

文章目录 一、前置知识二、本地Idea运行Spring项目1. 将写好的 Spring 项目先打包成 war 包2. 查看项目工件&#xff08;Artifact&#xff09;是否存在3. 配置 Tomcat3.1 添加一个本地 Tomcat 容器3.2 将项目部署到 Tomcat 4. 运行项目 三、基于 Tomcat 部署及多实例部署1. Spr…

usbredir学习

文章目录 背景典型场景编译usbredirparserusbredirfilterusbredirparser/usbredirproto usbredirhostusbredirect/usbredirtestclient参考 背景 usbredir 是一种用于通过网络转发 USB 设备流量的网络协议。它也是一个软件包的名称&#xff0c;该软件包提供了一个解析库、一个 …

ESXI 安装教程(3) ---​vCenter Server 安装

不涉及复杂的操作此项可不安装 1.镜像加载到虚拟光盘 对应的网盘文件 2.打开文件路径 双击运行文件installer.exe 3.调整安装语言 4.点击安装 5. 6. 证书,有效问题导致此提示,非专业网络管理人员,不知道如何处理,此处点是即可 证书有效开始时间是安装时间8小时 证书有效结束…

【初识扫盲】逆概率加权

我们正在处理一个存在缺失数据的回归模型&#xff0c;并且希望采用一种非参数的逆概率加权方法来调整估计&#xff0c;以应对这种缺失数据的情况。 首先&#xff0c;我们需要明确问题的背景。我们有样本 { ( Y i , X i , r i ) : i 1 , … , n } \left\{\left(Y_i, \boldsym…

极客说|Azure AI Agent Service 结合 AutoGen/Semantic Kernel 构建多智能体解决⽅案

作者&#xff1a;卢建晖 - 微软高级云技术布道师 「极客说」 是一档专注 AI 时代开发者分享的专栏&#xff0c;我们邀请来自微软以及技术社区专家&#xff0c;带来最前沿的技术干货与实践经验。在这里&#xff0c;您将看到深度教程、最佳实践和创新解决方案。关注「极客说」&am…

【集成学习】Boosting算法详解

文章目录 1. 集成学习概述2. Boosting算法详解3. Gradient Boosting算法详解3.1 基本思想3.2 公式推导 4. Python实现 1. 集成学习概述 集成学习&#xff08;Ensemble Learning&#xff09;是一种通过结合多个模型的预测结果来提高整体预测性能的技术。相比于单个模型&#xf…

小米vela系统(基于开源nuttx内核)——如何使用信号量进行PV操作

如何使用信号量进行PV操作 前言信号量1. 信号量简介2. NuttX中信号量的创建与使用2.1 Nuttx信号量的初始化和销毁2.2 信号量的等待和发布 3. 信号量的实际应用&#xff1a;下载任务示例3.1 实际代码3.2 代码说明3.3 执行说明 4. 信号量的优势与应用场景5. 常见应用场景&#xf…

CMake学习笔记(2)

1. 嵌套的CMake 如果项目很大&#xff0c;或者项目中有很多的源码目录&#xff0c;在通过CMake管理项目的时候如果只使用一个CMakeLists.txt&#xff0c;那么这个文件相对会比较复杂&#xff0c;有一种化繁为简的方式就是给每个源码目录都添加一个CMakeLists.txt文件&#xff…

旅游网站设计与实现

文末附有完整项目代码 在当今数字化时代&#xff0c;旅游网站成为人们获取旅游信息的重要途径。本文将详细介绍旅游网站的设计与实现&#xff0c;让你轻松了解其中的技术奥秘&#xff01; 一、项目背景 随着社会经济的发展&#xff0c;人们对精神消费愈发重视&#xff0c;旅游…

【C++】size_t究竟是什么?全面解析与深入拓展

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;一、什么是size_t&#xff1f;为什么需要size_t&#xff1f; &#x1f4af;二、size_t的特性与用途1. size_t是无符号类型示例&#xff1a; 2. size_t的跨平台适应性示例对…

【物流管理系统 - IDEAJavaSwingMySQL】基于Java实现的物流管理系统导入IDEA教程

有问题请留言或私信 步骤 下载项目源码&#xff1a;项目源码 解压项目源码到本地 打开IDEA 左上角&#xff1a;文件 → 新建 → 来自现有源代码的项目 找到解压在本地的项目源代码文件&#xff0c;点击确定&#xff0c;根据图示步骤继续导入项目 查看项目目录&#xff…

ssh2-sftp-client和ssh2配合使用js脚本快速部署项目到服务器

有时候因为服务器不能实现github或者gitlab的自动部署服务&#xff0c;所以就需要使用脚本来实现自动部署&#xff0c;可以省时省力&#xff0c;一劳永逸。这里就使用ssh2-sftp-client和ssh2来实现&#xff0c;即便是需要sudo权限&#xff0c;也是可以的。 1.先将本地打包后的…

深度解析Linux中的调试器gdb/cgdb的使用

Linux下我们编译好的代码&#xff0c;无法直接调试 gcc/g默认的工作模式是realse模式 程序要调试的话&#xff0c;必须是debug模式&#xff0c;也就是说编译的时候要加-g选项 gdb携带调试信息的exe 我们现在在文件夹里面创建一个文件lesson11 里面创建一个累加的代码&…

【Maui】动态菜单实现(绑定数据视图)

前言 .NET 多平台应用 UI (.NET MAUI) 是一个跨平台框架&#xff0c;用于使用 C# 和 XAML 创建本机移动和桌面应用。 使用 .NET MAUI&#xff0c;可从单个共享代码库开发可在 Android、iOS、macOS 和 Windows 上运行的应用。 .NET MAUI 是一款开放源代码应用&#xff0c;是 X…

Bash语言的语法糖

Bash语言的语法糖 引言 在现代编程语言中&#xff0c;“语法糖”是一个非常常见的术语&#xff0c;它指的是那些使代码更加易读、易写的语法特性。尽管这些特性并不改变语言的功能&#xff0c;但它们能显著提升开发者的编程体验。在众多编程语言中&#xff0c;Bash&#xff0…

linux---Nginx详细教程(包含安装,网站部署)

Nginx是一个高性能的HTTP和反向代理服务器&#xff0c;也可以用作邮件代理服务器&#xff0c;其以占有内存少、并发能力强、稳定性高、丰富的功能集、低系统资源消耗而闻名。以下是对Nginx的详细教程&#xff1a; 一、Nginx简介 Nginx由俄罗斯人开发&#xff0c;第一个公开版…