• [经验分享] 行李箱安检边缘套件开发经验分享
    bilibili视频链接:【行李箱安检识别】 https://www.bilibili.com/video/BV12A41197HJ/?share_source=copy_web&vd_source=c70245f8912fa536541e7d4ea81c352f1.MindStudio介绍MindStudio是一套基于华为自研昇腾AI处理器开发的AI全栈开发工具平台,该IDE上功能很多,涵盖面广,可以进行包括网络模型训练、移植、应用开发、推理运行及自定义算子开发等多种任务。MindStudio除了具有工程管理、编译、调试、运行等一般功能外,还能进行性能分析,算子比对,可以有效提高工作人员的开发效率。除此之外,MindStudio具有远端环境,运行任务在远端实现,对于近端的个人设备的要求不高,用户交互体验很好,可以让我们随时随地进行使用。2.案例模型本项目目的是利用MindStudio开发基于Pytorch的训练模型和基于MindX SDK的推理项目。项目对x光安检图象进行推理,利用目标检测框架,对警棍、老虎钳、榔头、充电宝、剪刀、扳手、枪支、子弹、喷罐、手铐、小刀、打火机以上目标进行检测,将检测得到的不同类的目标用不同颜色的矩形框标记。支持硬件平台:本项目以昇腾Atlas310卡、Atlas 200DK为主要的硬件推理平台。3.环境搭建3.1远端环境搭建在服务器Linux端(aarch64架构):1)下载好 MindX SDK mxvision 2.0.4 下载参考链接。在远端任意用户文件夹下,将Ascend-mindxsdk-mxvision_2.0.4_linux-aarch64.run文件上传chmod +x Ascend-mindxsdk-mxvision_2.0.4_linux-aarch64.run ./Ascend-mindxsdk-mxvision_3.0.RC2_linux-x86_64.run --install安装完成后,使环境变量生效:export DDK_PATH=$HOME/Ascend/ascend-toolkit/latestexport NPU_HOST_LIB=$DDK_PATH/acllib/lib64/stubsource ~/Ascend/ascend-toolkit/set_env.shcd ~/software/mxVision/./set_env.sh下载好CANN 5.0.4,下载参考链接。同样在任意用户文件夹下,上传Ascend-cann-toolkit_5.1.RC2.2_linux-aarch64.runchmod +x Ascend-cann-toolkit_5.1.RC2.2_linux-aarch64.run./Ascend-cann-toolkit_5.1.RC2.2_linux-aarch64.run --install显示如下则CANN 5.0.4安装完成。安装完成后,可以创建一个env.txt 文件将文档中红框路径保存以下。3.2 本地(windows端)环境搭建1)windows版本MindStudio。按照官方步骤进安装,同时安装相应依赖。2)安装任意版本的Anoconda。3)按照官方教程进行vpn连接。进入众智实验室容器IP。4)同步CANN。打开MindStudio,在File中选择File > Settings > Appearance & Behavior > System Settings > CANN点击change CANN进入下图界面,选择远端CANN安装的位置配置好后返回上一界面显示如图。5)在File > Settings > Appearance & Behavior > System Settings > MindX SDK,进入MindX SDK管理页面,点击Install进入远程配置界面。在Remote Connection一栏点击加号,配置远程连接,输入申请的账号密码等相关信息。在Remote CANN Location 一栏选择远端安装CANN Toolkits的路径,具体到版本,这里选择的是5.0.4版本。在Remote SDK Location 一栏选择远端安装MindX SDK的路径,这里选择的是Mxvision 2.0.4 版本。Local SDK location为本地默认的SDK安装位置,会将远端的SDK同步过来。点击ok后开始同步。配置完成后,界面如下图所示。4.Pytorch yolox模型训练流程点击File >New >Project 创建一个空训练工程。选择Pytorch项目。创建好工程后将YOLOX训练代码git 到本地。git clone cid:link_5注:由于网络问题,github上的代码经常可能克隆失败,可以直接去原网页下载好代码解压到目录中。下载好的文件目录如图所示。接下来在终端使用conda命令为此工程配置一个虚拟环境。需要的版本python=3.9conda create -n YOLOX_pt python=3.9执行后命令行如图:按y生成环境。之后安装工程所要求的包。pip install -r requirements.txt显示安装成功,这里如果显示安装onnx失败,将requirements中的onnx版本删除,再次运行安装命令即可。此处onnx版本不影响训练。我们还需要安装gpu版本的pytorch才能进行训练,执行下面命令conda install pytorch torchvision torchaudio cudatoolkit=11.3 -c pytorch安装完毕后conda list #查看当前已安装包将数据集下载后解压到本地。开始配置exp文件。使用yolox-m模型标准进行训练。在项目的exps> default中找到yolox-m默认配置文件,对文件中路径、参数进行修改。 配置好之后将tools > train.py文件拷贝到文件根目录下,运行python train.py -f ./exps/default/yolox_m.py -d 0 -b 2 --fp16 -o其中标蓝为你的exp文件位置如下界面表示开始训练。最终训练文件会保存在YOLOX_outputs >yolo-m中Train_log会记录训练时的全部信息。我们可以得到best_cpkt.pth权重文件。再将pth文件转换成为onnx权重文件,便于后续离线模型转换。python export_onnx.py --output-name yoloxray1.onnx -n yolox-m -c D:/project/YOLOX2/YOLOX_outputs/yolox_m/best_ckpt.pth5.模型推理App开发流程1)创建工程接下来进行app边缘开发任务,需先创建一个推理工程,点击File >New >Project,选择Ascend APP工程之后建立一个MindX SDK for Python空工程。2)选择编译器点击File >Project structure为项目配置远端python编译器。在SDK一栏点击下拉菜单,点击Add Python SDK进入选择编译器页面,选择SSH,在Interpreter一栏选择一个远端python路径。选择好后分别点击左边Project、Modules、SDKs,可以看到刚才添加的编译器。点击Apply应用配置。环境配置完成,接下来就可以在本地进行开发工作了。3)创建项目目录本次工程目录结构如下图所示在python目录下Main目录放置程序的主要函数test目录,放置测试数据相关内容(测试数据的名称label文件)test_img目录,放置测试图片pipeline目录,放置pipeline文件在config目录下放置各种参数设置文件,包括流的推理日志参数文件sdk.conf、logging.conf。在postprocess目录下放置现成的yolox后处理插件的代码接下来将目录先上传到远端。进入Files >settings界面,选择左方的tools下的Deployment界面在Mappings下选择项目的远端同步路径在Excluded Paths下,点击左下角加号减号,还可以删改不进行同步的文件,我们可以排除掉模型文件等较大文件,这样可以加快流程开发速度。我们排除掉除了项目中Python/Main路径下的主函数文件外,其余所有的文件路径,可以减少文件上传和下载的时间。之后右键文件根目录,点击Deployment >Upload to将项目整体同步一次到远端。4)onnx 模型转换成 om离线模型1. 预处理参数设置利用官方提供的aipp转换方式对模型转换参数进行设置。这里介绍一下aipp预处理方法,AIPP(Artificial Intelligence Pre-Processing)人工智能预处理,用于在AI Core上完成图像预处理,包括改变图像尺寸、色域转换(转换图像格式)、减均值/乘系数(改变图像像素),数据处理之后再进行真正的模型推理。该模块功能与DVPP相似,都是用于图像数据预处理,但与DVPP相比,由于DVPP各组件基于处理速度和处理占有量的考虑,对输入、输出有特殊的限制,如对输出图片的宽高有对齐要求,且其输出格式通常为YUV420SP等格式。这样的设定虽在视频分析的场景下有非常广阔的输入,但深度学习模型的输入通常为RGB或BGR,且输入图片尺寸各异,因此ATC工具流程中提供了AIPP功能模块。创建一个空cfg文件。根据官方的文档说明设置参数。原模型图片格式为YUV420SP_U8,转换成BGR格式模型,详细参数需按照以下设置。选择静态aipp。所有参数如图编写成的yolox_bgr.cfg,放于根目录的config文件夹下。可视化模型转换将第四节训练好的onnx模型上传到远端服务器上,点击Ascend >Model convert进入模型转换界面,选择服务器上的onnx模型。Output Path选择本地任意位置。Type为UINT8。之后点击next附:点击模型右边的眼睛按钮还可以可视化的查看模型选择aipp参数文件选择图片格式为BGR之后点击next。环境变量在之前已经设置好了,所以这里不配置也可以转换成功。点击finish,等待模型开始转换,最终结果如下,表示模型转换成功。如果转换失败,则需要手动添加以下环境变量 insall_path=/usr/local/Ascend/ascend-toolkit/latestLD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATHASCEND_OPP_PATH=${install_path}/oppASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest/然后再次进行转换最后,将生成好的om模型文件上传到远端Python/models路径下。5)后处理的标签文件、后处理插件配置。标签文件coco.names 生成创建一个coco.names文件,将标签内容填入保存。放在Python/models路径下,上传至远端。配置后处理参数文件yolox_eval.cfg。以下为各参数介绍,可以根据模型需要来选择。CLASS_NUM类别数量。80OBJECTNESS_THRESH是否为目标的阈值,大于阈值即认为是目标。0.3IOU_THRESH两个框的IOU阈值,超过阈值即认为同一个框。0.45以yolox_eval.cfg保存,放在configs路径下,上传至远端。3.后处理插件(.so文件)生成点击Tools >Start SSH,进入远端的终端cd 到postprocess目录下,执行bash build.sh会在远端当前路径下,生成yolox后处理插件。注:在这里注意如果编译失败,需要在终端通过export重新配置编译环境,包括MindX SDK路径和CANN路径。6)pipeline编排此次插件处理流程如下点击Ascend > MindX SDK pipeline进入可视化设计界面。根据流程编排插件在左边search界面搜索需要的插件拖动插件名称到右方,生成一个插件。按照此方法依次将需要的插件拖动至右方。点击每个插件右边的小点,将插件顺次连接。如果觉得排列不整齐,可以点击Format按钮让他们变整齐>> 最终所有插件依次连接效果如下。点击每个插件,可以在右方设置好每个插件的的参数。具体每个插件的功能和参数说明在官方文档中。decoder的参数。resizer的参数。在tensorinfer中选择刚才转换好的推理模型路径。在postprocessor插件中配置好远端cfg、names、so文件路径参数点击save之后会生成一个new.pipeline文件,我们将文件放于Python/pipeline中。将pipeline文件命名为pre_post.pipeline,上传至远端。7)main函数编写首先创建流:若创建失败则退出。运用StreamManagerApi 读取pipeline。载入图片,进行推理,获得带有框的图片输出。获得框向量和物体名称以及置信度,进行画框,并将结果写入test_img文件,保存名称为pre_post_bgr.jpg最后不要忘了销毁流至此主函数编写完毕,命名为pre_post.py,放到python/Main目录下。6.编译执行在主界面点击图示Edit configurations配置运行参数。Executable :选择需要执行的Main函数文件Command Arguments:如果在运行时有arg参数可以进行配置,本项目主函数中参数已经设置好了所以不用配置。Environment variables:一栏配置远端的环境变量,请确保配置好以下路径:SDK-path: mxVision SDK 安装路径ascend-toolkit-path: CANN 安装路径点击apply然后关闭界面。配置好后点击旁边的三角键,我们的主函数就可以传输到远端进行编译了。编译成功,等待远端output文件夹传输至本地后,在目录下查看结果。7.性能验证1.下载验证数据集将数据集上传到远端,进行性能验证。小提示:建议将工程文件的数据集和模型文件之类大型文件都排除在同步列表之外。2.运行路径``python/test``下的文件 parse_coco.py 参数:--json_file=data/annotations/instances_test2017.json--img_path=data/test2017注:这里路径最好换成你上传的数据集所在的绝对路径 若运行成功,会在该目录下生成文件夹ground_truth,其中包含每张图像上提取的目标框真实位置与类别的txt文件。3.接下来将每张图的预测结果转为txt文件,并保存在同一文件夹下,其步骤如下:打开MindX SDK安装路径下的日志配置文件vim ${MX_SDK_HOME}/config/sdk.conf之后修改参数 enable_ps=true,开启日志记录,之后pipeline运行时会在指定文件夹生成运行日志。修改完毕后,运行该路径下文件python/Main/python3 eval_nopre_post.py 若运行成功,会在``python/test`` 路径下生成 test_nopre_post 文件夹,该目录下包含有每张图像上的检测结果的 txt 文件。同时会得到fps为32 > 20,满足性能要求运行命令: python/test/python3 map_calculate.py 参数:--npu_txt_path="./test_nopre_post" 得到以上结果,使用MindX SDK环境推理精度为47.43%,与原模型精度一致。8.FAQ1)ModuleNotFoundError:No module named XXX大多是因为在运行程序前未配置好路径,请检查CANNToolKits和MindX SDK路径配置问题。配置远端CANNToolsKits包时提示permission denied建议非root权限用户选择非usr/local路径下的CannTooKits包进行配置,否则会出现权限不够的问题。模型转换时无法使用前处理问题按照提示,模型的输入必须满足type为utf8的格式,之后才可以进行模型转换。详情可以参照官方模型参数说明。色域转换配置说明 - CANN 5.0.4 ATC工具使用指南 01 - 华为 (huawei.com)9.从昇腾论坛获得更多支持如上述步骤中在在实践中仍然遇到其他问题,包括om模型参数设置问题,调用streamMannagerApi时的问题,都可以在论坛中提出自己的问题或者查找相关问题,我的很多问题都是在这里解决的。也非常推荐大家一期建设这个论坛。昇腾社区-官网丨昇腾万里 让智能无所不及 (hiascend.com)
  • [经验分享] 使用MindStudio完成EAST_ResNet50_vd模型开发
    目录一、MindStudio介绍 二、MindStudio工程创建 1.1 主界面功能介绍 1.2 创建工程 1.3 工程配置 三、模型代码获取 3.1 模型介绍 3.2 添加工程代码 3.3 模型代码获取 3.4 模型权重获取 3.5 推理工具获取 3.6 同步代码 3.7 配置远程环境 四、模型转换 4.1 获取推理权重 4.3 转om模型 五、文本检测 六、总结 本文主要给大家介绍使用MindStudio进行EAST_ResNet50_vd模型离线推理开发,完成图像文本检测,主要内容包括MindStudio安装、MindStudio工程创建、模型介绍与获取、模型转换、模型推理5个部分。一、MindStudio介绍MindStudio是一套基于华为昇腾AI处理器开发的AI全栈开发平台,包括基于芯片的算子开发、以及自定义算子开发,同时还包括网络层的网络移植、优化和分析,另外在业务引擎层提供了一套可视化的AI引擎拖拽式编程服务,极大的降低了AI引擎的开发门槛。本文使用MindStudio版本为:5.0.RC3,MindStudio功能框架如图1所示,集成开发环境包括:工程管理、编译、运行、模型转换、应用开发、精度比对、自定义算子、性能分析、仿真器、Debug、CANN-Toolkit功能。图1离线推理开发主要使用的是模型转换功能,将训练好的第三方网络模型可以直接通过离线模型工具导入并转换成离线模型,并可一键式自动生成模型接口,方便开发者基于模型接口进行编程,同时也提供了离线模型的可视化功能。MindStudio的安装过程可以参考官方指导手册,链接为:cid:link_0安装指南部分详细介绍了安装相关步骤,如图2所示。图2二、MindStudio工程创建1.1 主界面功能介绍首次启动MindStudio会提示是否导入配置,如图3所示,可以选择不导入配置,点击OK进入MindStudio主界面。图3MindStudio欢迎界面比较简洁,相关功能如下:a.工程管理功能,如图4所示,包括新建工程,打开、导入工程。图4b.用户设置功能,可以设置主题、字体等,如图5所示,将界面颜色设置为IntelliJ Light。图5c.插件管理功能,如图6所示,可以安装、卸载一些常用的插件。图6d.学习功能,如图7所示,可以进入到MindStudio用户帮助界面。图71.2 创建工程使用MindStudio主界面的工程管理功能创建一个新的工程,具体步骤为:a.点击New Project开始创建一个新的工程,如图8所示。图8b.New Project界面如图9所示,选择Ascend App,点击Change进行CANN配置。图9c.CANN配置界面如图10所示,点击Remote Connection的+号图标添加远程服务器链接,点击SSH Configurations中的+号,输入远程服务器相关信息,点击OK。图10d.如图11所示,点击Remote CANN location中的文件夹图标,选择远程服务CANN安装路径,点击OK确认,点击Finish结束配置。图11e.CANN配置结束后会自动同步远程CANN信息,如图12所示。图12f.同步完成后自动返回New Project界面,如图13所示,选择ACL Project(Python),点击Next继续。图13g.设置工程名称和位置,如图14所示,点击Finish继续。图14h.如图15所示,自动打开新建工程,此时会弹出提示信息,点击Close关闭,也可以选择不再提示。图15通过以上步骤完成工程创建。1.3 工程配置工程创建完成后需要进行相关配置,包括SDK、Deploy。具体步骤如下:a.如图16所示,点击File->Project Structure进入工程结构配置界面。图16b.工程结构界面如图17所示,选择SDKs,点击+号,选择Add Python SDK添加Python解释器。图17c.在添加Python解释器界面,如图18所示,选择SSH Interpreter,然后选择Deploy后会自动识别远程Python相关信息,点击OK完成。图18d.返回工程结构界面,如图19所示,选择Project,在SDK列表选择Remote Python,点击OK完成。图19e.进入Deploy设置界面,如图20所示,点击Tools-Deployment-Configuration。图20f.Deploy设置界面如图21所示,选择Deployment,点击远程服务器,点击Mappings标签,输入远程开发映射路径,点击OK完成。图21通过以上步骤激活完成工程配置。1.4 激活远程终端a.激活远程终端,如图22所示,点击Tools,选择Start SSH session。图22b.如图23所示,在弹出的对话框中选择远程服务器,启动Remote Terminal窗口。图23三、模型代码获取3.1 模型介绍EAST是一个高效准确的场景文本检测器,通过两步进行文本检测:先是一个全卷积的网络直接产生一个字符或者文本行的预测(可以是旋转的矩形或者不规则四边形),然后通过NMS(Non-Maximum Suppression)算法合并最后的结果。参考论文:cid:link_5EAST模型结构如图24所示,主要包括:(1) 特征提取层:使用的基础网络结构是PVANet,分别从stage1,stage2,stage3,stage4抽出特征,一种FPN(feature pyramid network)的思想。(2) 特征融合层:第一步抽出的特征层从后向前做上采样,然后Concat。(3) 输出层:输出一个score map和4个回归的框+1个角度信息,或者输出,一个scoremap和8个坐标信息。图243.2 添加工程代码完成推理功能需要开发的代码如图25所示,其中包括:EAST_ResNet50_vd.patch:模型补丁文件EAST_ResNet50_vd_det.py:模型推理脚本requirements.txt:工程依赖信息图25a.EAST_ResNet50_vd.patch:模型补丁文件主要是将使用gpu关闭,如图26所示。图26b. EAST_ResNet50_vd_det.py:模型推理脚本用于推理过程,业务流程及注释如图27所示。​图27c. requirements.txt:工程依赖信息,如图28所示。图283.3 模型代码获取在本地终端窗口可以通过以下命令获取模型代码:git clone -b release/2.5 https://github.com/PaddlePaddle/PaddleOCR.gitcd PaddleOCRgit reset --hard a40f64a70b8d290b74557a41d869c0f9ce4959d5git apply ../EAST_ResNet50_vd.patchrm .\applications\cd ..模型代码目录结构如科29所示。图293.4 模型权重获取模型权重链接为:https://paddleocr.bj.bcebos.com/dygraph_v2.0/en/det_r50_vd_east_v2.0_train.tar本地下载后,解压到EAST_ResNet50_vd\checkpoint目录下,如图30所示。图303.5 推理工具获取推理工具使用的是 ais_infer,该工具的获取、编译、安装说明链接为:cid:link_1下载后将 ais_infer 工具代码放到本地工程路径下,推理工具目录如图31所示。图313.6 同步代码整个工程代码结构如图32所示,选中工程名称,点击Tools->Deployment->Upload to将代码同步到远程服务器。图32在图33中弹出的对话框中选择远程服务器名称,开始同步文件。图333.7 配置远程环境在远程终端窗口中需要通过以下步骤配置远程服务器环境a.进入远程映射目录,命令为:cd /home/mindstudio_prj/EAST_ResNet50_vd/b.安装依赖,命令为:pip3 install -r requirements.txt --userc.进入ais_infer编译目录,命令为:cd ais_infer/backend/d.进行编译,命令为:pip3 wheel ./e.安装编译好的python包,命令为:pip3 install aclruntime-0.0.1-cp37-cp37m-linux_x86_64.whlf.返回到远程项目目录,命令为:cd ../../通过以上步骤完成代码获取以及远程环境配置。四、模型转换4.1 获取推理权重a.首先需要可执行命令将训练权重转为推理权重,创建可执行命令如图34所示,点击Add Configuration。图34b.如图35所示,在弹出的命令配置界面点击+号,选择Python。图35c.Python命令配置界面如图36所示,需要填入的参数信息如下:1.Name:可执行命令的名称。2.Scrip path:可执行脚本,如本次需要执行的是:EAST_ResNet50_vd\PaddleOCR\tools\export_model.py。3.Parameters:命令参数,如本次的命令参数为:-c /home/mindstudio_prj/EAST_ResNet50_vd/PaddleOCR/configs/det/det_r50_vd_east.yml -o Global.pretrained_model=/home/mindstudio_prj/EAST_ResNet50_vd/checkpoint/det_r50_vd_east_v2.0_train/best_accuracy Global.save_inference_dir=/home/mindstudio_prj/inference/det_r50_eas其中-c表示模型配置文件,-o表示用户参数,Global.pretrained_model为模型训练权重路径,Global.save_inference_dir模型推理权重路径。4.Use specified interpreter:选择Python解释器,如本次选的是Remote Python3.7.5。配置以上信息后点击OK。图36d.执行命令,如图37所示,点击可执行按钮开始执行命令。图37e.执行完成后得到推理模型,如图38所示。图384.2 转onnx模型a.在远程终端使用paddle2onnx工具命令将推理权重转为onnx模型,命令为:paddle2onnx \--model_dir ../inference/det_r50_eas \--model_filename inference.pdmodel \--params_filename inference.pdiparams \--save_file ../EAST_ResNet50_vd.onnx \--opset_version 11 --enable_onnx_checker True \--input_shape_dict="{'x':[1,3,544,960]}"成功转出onnx模型如图39所示,模型名称为:EAST_ResNet50_vd。图39b.使用onnxsim工具简化onnx模型,onnxsim工具说明链接为:cid:link_3onnxsim命令为:onnxsim ../EAST_ResNet50_vd.onnx ../EAST_ResNet50_vd_sim.onnx4.3 转om模型将onnx转为om模型需要用到MindStudio的模型转换功能,具体步骤如下:a.打开模型转换功能,如图40所示,点击Model Converter按钮。图40b.进入Model Converter界面,如图41所示,点击Model File文件夹图标,然后选择远程环境中的onnx模型,点击OK。 图41c.开始自动解析onnx模型信息,如图42所示。图42d.模型解析完成后,如图43,补全模型转换信息包括如下:1.Model Name:输出om模型的名称。2.Target SoC Version:远程环境设备芯片型号,本文环境使用的是Ascend310P3。3.Output Path:om模型保存路径。4.Input Format:输入数据的格式,本文模型的输入为NCHW,表示图片格式的数据。5.Input Nodes:模型输入节点信息,包括输入节点Name、Shape和Type。6.Output Nodes:可以选择模型输出节点信息。本文使用默认输出节点。补全模型转换信息后点击Next继续。图43e.开始校验模型转换参数,如图44所示图44f.校验完成后如图45所示,是否进行数据预处理,本文不需要数据预处理,关闭后点击Next继续。图45g.再次确认模型转换命令,如图46所示,点击Finish完成,并开始进行模型转换。图46h.模型转换完成后如图47所示,在本地生成om模型。图47五、文本检测获取EAST_ResNet50_vd_sim.om后,可以进行离线推理,步骤如下:a.创建离线推理命令,如图48所示,点击OK完成,命令参数为:--image_dir="./PaddleOCR/doc/imgs_en/img_10.jpg" --det_model_dir="/home/mindstudio_prj/inference/det_r50_eas" --det_algorithm="EAST"其中--image_dir表示图片路径,--det_model_dir表示推理权重路径,--det_algorithm表示检测算法。图48b.执行推理后,如图49所示,得到推理结果。图49c.将推理结果同步到本地,如图50所示,点击Tools->Deployment->Download from。图50d.打开推理结果图像,文本检测效果如图51所示。图51六、总结使用MindStudio进行EAST_ResNet50_vd模型图像文本检测过程,相关参考学习资料如下:1.MindStudio用户手册:cid:link_02.MindStudio开发者社区:cid:link_23.MindStudio B站:cid:link_4
  • [执行问题] 为什么Mindspore.numpy不支持tensor转换
    如图我想把numpy创建的变量转换成Tensor但是报错如图
  • [技术干货] python常见运算符及用法小结【转】
    算术运算符运算符描述+两个数相加两个数相加,或是字符串连接-两个数相减*两个数相乘,或是返回一个重复若干次的字符串/两个数相除,结果为浮点数%取模,返回两个数相除的余数//两个数相除,返回商的整数部分**幂运算,返回乘方结果1234567print(1 + 2)  # 3print(2 - 1)  # 1print(2 * 3)  # 6print(3 / 2)  # 1.5print(6 % 5)  # 1print(8 // 2)  # 4print(3 ** 2)  # 9如果想同时得到商和余数,可以用divmod这个方法该方法的返回值是tuple (x//y, x%y).1print(divmod(10,3)) # (3,1)因为浮点数精度的问题,Python还存在一些计算方面的小问题1print(0.1+0.1+0.1-0.3)  # 5.551115123125783e-17要解决这个问题,可以导入decimal模块123from decimal import Decimal# 计算结果:0.0print(Decimal('0.1')+Decimal('0.1')+Decimal('0.1')-Decimal('0.3'))关系运算符运算符描述==比较对象是否相等!=比较对象是否不相等>大于,例如a>b,将比较a与b的大小,a>b返回True,否则返回False<小于,例如a<b,将比较a与b的大小,a<b返回True,否则返回False>=大于等于,例如a>=b,将比较a与b的大小,a>=b返回True,否则返回False<=小于等于,例如a<=b,将比较a与b的大小,a<=b返回True,否则返回False12345678a = 10b = 20print(a == b)  # Falseprint(a != b)  # Trueprint(a > b)  # False print(a < b)  # Trueprint(a >= b)  # Falseprint(a <= b)  # True1.返回值为bool值12print(True == 1)  # Trueprint(False == 0)  # True==比较数值(int与str不能直接比较)12print(2.0 == 2)  # Trueprint('2' == 2)  # False字符串与字符串之间是比较ASCII值12# Trueprint('abc' < 'xyz') # 97 98 99 < 120 121 122连续比较,python的解释机制123print(3 > 2 > 1)  # Trueprint(3 > 2 > 2)  # Falseprint((3 > 2) > 1) # False赋值运算符运算符描述=常规赋值运算符,将运算结果赋值给变量+=加法赋值运算符,例如 a+=b 等效于 a=a+b-=减法赋值运算符,例如 a-=b 等效于 a=a-b*=乘法法赋值运算符,例如 a*=b 等效于 a=a*b/=除法赋值运算符,例如 a/=b 等效于 a=a/b//=取整除赋值运算符,例如 a//=b 等效于 a=a//b%=取模赋值运算符,例如 a%=b 等效于 a=a%b**=幂运算赋值运算符,例如 a**=b 等效于 a=a*b123a = 1       # 将等号右边 赋值 等号左边a = a + 1   # 先等号右边计算 再赋值给 等号左边a += 1      # a = a + 1逻辑运算符运算符描述and与运算,如果a 为False,a and b返回False 否则返回y的计算值or或运算,如果a非0,返回a的值,否则返回b的值not非运算,如果a为True,返回False,如果a为False,返回True12345a = 10b = 20print(a and b)  # 20print(a or b)  # 10print(not a)  # Falsea and b 两者都为True时结果才为Truea or b 两者有一个为True则结果就为True短路(懒惰)原则False and True 当and运算符时,遇到第一个为False则不会往后了True or False 当or运算符时,遇到第一个为True则不会往后了成员运算符运算符描述in如果在指定的序列中找到值返回True,否则返回Falsenot in如果在指定的序列中找到值返回True,否则返回False123456list1 = [1, 2, 3, 4, 5]a = 1if a in list1:    print("a是list1的元素之一")else:    print("a不是list1的元素")身份运算符运算符描述is判断两个标识符是不是引用自一个对象is not判断两个标识符是不是引用自不同对象 is 和比较运算符 == 的区别 is 用于判断两个变量是否引自同一个对象(可使用id()查看),而 ==用于判断变量的值是否相等!1234567a = [1, 2, 3]b = [1, 2, 3]# 可通过id()查看内存地址print(id(a))  # 2042443551304print(id(b))  # 2042443551816print(a is b)  # Falseprint(a == b)  # True1234567a = 2b = 2.0# 可通过id()查看内存地址print(id(a))  # 140722443350320print(id(b))  # 2336678499216print(a is b)  # Falseprint(a == b)  # True三目运算符三目运算符的表示方法:True_statements if expression else False_statements1234a = 1b = 2# a+b不大于3执行后面的else语句 b-a = 1print(a+b if a+b>3 else b-a)运算符优先级运算符描述**指数(最高优先级)*/%//乘,除,取模和取整除±加法减法<= >=比较运算符== !=等于运算符= %= 、= 、、=-= += *= **=赋值运算符is is not身份运算符in not in成员运算符not or and逻辑运算符
  • [新手课堂] 算数运算符
    基本四则与算符+   -   *   /   %注意事项:1、0不能作为除数;2、%表示取余,不仅可以对int求模,也可对double求模;增量赋值运算符又叫复合运算符,会自动进行类型转换;+=    -=    /=    *=    %=自增自减运算符自增或自减符号在前先自增或自减再参他运算;自增或自减符号在后先参与运算再自增或自减;如果自增自减符号在前则取的返回值是自增或自减之后的返回值,反之则取原返回值;++   --
  • [技术干货]  calc(四则运算)不起作用
    用于动态计算长度值。需要注意的是,运算符前后都需要保留一个空格,例如:width: calc(100% - 10px);任何长度值都可以使用计算值()函数进行计算;calc()函数支持“+”,“ - ”,“*”,“/”运算;计算值()函数使用标准的数学运算优先级规则;calc()不起作用应该是运算符前后没留空格导致,可以加空格测试
  • [技术干货] 新手小白学JAVA 面向对象之多态[转载]
    1. 概念多态是面向对象程序设计(OOP)的一个重要特征,指同一个实体同时具有多种形式,即同一个对象,在不同时刻,代表的对象不一样,指的是对象的多种形态。可以把不同的子类对象都当作父类来看,进而屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,统一调用标准。比如,你的女盆友让你买点水果回来,不管买回来的是苹果还是西瓜,只要是水果就行,这个就是生活中多态的体现再比如,小猫、小狗、小猪我们可以把他们都归纳成小动物,每种小动物都需要吃东西,所以我们可以统一设置他们都必须吃,但是每种小动物的习性不一样,那这个就可以设置成小动物自己特有的功能,多态对象只能调用父类中定义子类中重写的功能,并不能调用子类的特有功能,这样就实现了代码的统一2 . 特点多态的前提1:是继承多态的前提2:要有方法的重写父类引用指向子类对象,如:Animal a = new Cat();多态中,编译看左边,运行看右边3. 练习:多态入门案例创建包: cn.tedu.oop创建类: TestDemo.javapackage cn.tedu.oop2;/*本类用作多态的入门案例*/public class TestDemo {    public static void main(String[] args) {        //6.创建“纯纯的”对象用于测试        Animal a = new Animal();        Cat c = new Cat();        Dog d = new Dog();        a.eat();//小动物Animal吃啥都行~调用的是父类自己的功能        c.eat();//小猫爱吃小鱼干~调用的是子类重写后的功能        d.eat();//小狗爱吃肉骨头~调用的是子类重写后的功能        /*2.父类对象不可以使用子类的特有功能*/        //a.jump();//报错,Animal类里并没有这个方法        //a.run();//报错,Animal类里并没有这个方法        c.jump();//小猫Cat跳的老高啦~,子类可以调用自己的功能        d.run();//小狗Dog跑的老快啦~,子类可以调用自己的功能        //7.创建多态对象进行测试        /*3.口诀1:父类引用指向子类对象        * 解释:创建出来的子类对象的地址值,交给父类类型的引用类型变量来保存*/        Animal a2 = new Cat();//Cat类对象的地址值交给父类型变量a2来保存        Animal a3 = new Dog();//Dog类对象的地址值交给父类型变量a3来保存        //8.测试多态对象        /*4.口诀2:编译看左边,运行看右边        * 解释:必须要在父类定义这个方法,才能通过编译,把多态对象看作是父类类型        *      必须要在子类重写这个方法,才能满足多态,实际干活的是子类*/        a2.eat();//小猫爱吃小鱼干~,多态对象使用的是父类的定义,子类的方法体    }}/*1.多态的前提:继承+重写*///1.创建父类class Animal{    //3.创建父类的普通方法    public void eat(){        System.out.println("小动物Animal吃啥都行~");    }}//2.1创建子类1class Cat extends Animal{    //4.1添加重写的方法    public void eat(){        System.out.println("小猫爱吃小鱼干~");    }    //5.1添加子类的特有功能    public void jump(){        System.out.println("小猫Cat跳的老高啦~");    }}//2.2创建子类2class Dog extends Animal{    //4.2添加重写的方法    @Override    public void eat(){        System.out.println("小狗爱吃肉骨头~");    }    //5.2添加子类的特有功能    public void run(){        System.out.println("小狗Dog跑的老快啦~");    }}4. 多态的好处多态可以让我们不用关心某个对象到底具体是什么类型,就可以使用该对象的某些方法提高了程序的可扩展性和可维护性5. 多态的使用前提:多态对象把自己看做是父类类型成员变量: 使用的是父类的成员方法: 由于存在重写现象,所以使用的是子类的静态成员: 随着类的加载而加载,谁调用就返回谁的6. 练习:多态成员使用测试创建包: cn.tedu.oop创建类: TestDemo2.javapackage cn.tedu.oop2;/*本类用于测试多态成员的使用情况*/public class TestDemo2 {    public static void main(String[] args) {        //7.创建纯纯的子类对象        Dog2 d = new Dog2();        System.out.println(d.sum);//20,子类自己的属性        d.eat();//小狗爱吃肉包子,子类自己的方法        //8.创建多态对象        /*口诀1:父类引用指向子类对象*/        /*口诀2:编译(保存)看左边,运行(效果)看右边*/        Animal2 a = new Dog2();        /*多态中,成员变量使用的是父类的*/        System.out.println(a.sum);//10        /*多态中,方法的声明使用的是父类的,方法体使用的是子类的*/        a.eat();//小狗爱吃肉包子        /*多态中,调用的静态方法是父类的,因为多态对象把自己看作是父类类型        * 直接使用父类中的静态资源*/        a.play();//没有提示,玩啥都行~        Animal2.play();    }}//1.创建父类class Animal2{    //3.创建父类的成员变量    int sum = 10;    //4.创建父类的普通方法    public void eat(){        System.out.println("吃啥都行~");    }    //9.1定义父类的静态方法play    public static void play(){        System.out.println("玩啥都行~");    }}//2.创建子类class Dog2 extends Animal2{    //5.定义子类的成员变量    int sum = 20;    //6.重写父类的方法    @Override    public void eat(){        System.out.println("小狗爱吃肉包子");    }    //9.2创建子类的静态方法play    //@Override    /*这不是一个重写的方法,只是恰巧在两个类中出现了一模一样的两个静态方法    * 静态方法属于类资源,只有一份,不存在重写的现象    * 在哪个类里定义,就作为哪个类的资源使用*/    public static void play(){        System.out.println("小狗喜欢玩皮球~");    }}7 拓展7.1 设计汽车综合案例创建包: cn.tedu.oopexec创建类: DesignCar.javapackage cn.tedu.oop2;/*本类用于完成汽车设计案例*/public class DesignCar {    public static void main(String[] args) {        //9.创建一个纯纯的父类对象进行测试        Car c = new Car();        System.out.println(c.getColor());//null        c.start();        c.stop();        //c.swim();//报错,父类对象不可以调用子类的特有功能        //10.创建纯纯的子类对象做测试        BMW b = new BMW();        System.out.println(b.color);//五彩斑斓的黑        System.out.println(b.getColor());//null        b.start();//都让开,我的车要起飞啦~        b.stop();//唉呀妈呀熄火了~        //11.创建多态对象进行测试        Car c2 = new TSL();        //System.out.println(c2.color);        System.out.println(c2.getColor());        c2.stop();        c2.start();        //c2.swim();    }}//1.通过分析,抽象形成一个汽车类class Car{    //2.定义并封装汽车类的属性--成员变量    private String brand;//品牌    private String color;//颜色    private int id;//编号    private double price;//价格    //3.定义功能    public void start(){        System.out.println("我的小车车启动啦~");    }    public void stop(){        System.out.println("唉呀妈呀熄火了~");    }    public String getBrand() {        return brand;    }    public void setBrand(String brand) {        this.brand = brand;    }    public String getColor() {        return color;    }    public void setColor(String color) {        this.color = color;    }    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }    public double getPrice() {        return price;    }    public void setPrice(double price) {        this.price = price;    }}//4.创建子类class BMW extends Car{    String color = "五彩斑斓的黑";    //5.重写父类的方法    @Override    public void start(){        System.out.println("都让开,我的车要起飞啦~");    }}//6.创建子类2class TSL extends Car{    //7.重写父类的方法    @Override    public void stop(){        System.out.println("唉呀妈,怎么停不下来呢");    }    //8.添加子类的特有功能    public void swim(){        System.out.println("没想到吧,我还是个潜水艇");    }}7.2 多态为了统一调用标准package cn.tedu.oop2;public class TestFruit {    public static void main(String[] args) {        Fruit f = new Fruit();        Apple a = new Apple();        Orange o = new Orange();        get(f);        get(a);        get(o);    }    //只需要创建一个方法,就可以执行截然不同的效果    //忽略子类对象的差异统一看作父类类型    public static void get(Fruit f){        f.clean();    }}class Fruit{    public void clean(){        System.out.println("水果要洗洗再吃");    }}class Apple extends Fruit{    @Override    public void clean(){        System.out.println("苹果需要削皮");    }}class Orange extends Fruit{    @Override    public void clean(){        System.out.println("橙子需要剥皮");    }}7.3 静态变量和实例变量的区别在语法定义上的区别:静态变量前要加static关键字,而实例变量前则不加。在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。7.4 向上转型和向下转型在JAVA中,继承是一个重要的特征,通过extends关键字,子类可以复用父类的功能,如果父类不能满足当前子类的需求,则子类可以重写父类中的方法来加以扩展。那么在这个过程中就存在着多态的应用。存在着两种转型方式,分别是:向上转型和向下转型。向上转型:可以把不同的子类对象都当作父类来看,进而屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,统一调用标准。比如:父类Parent,子类Child父类的引用指向子类对象:Parent p=new Child();说明:向上转型时,子类对象当成父类对象,只能调用父类的功能,如果子类重写了父类中声明过的方法,方法体执行的就是子类重过后的功能。但是此时对象是把自己看做是父类类型的,所以其他资源使用的还是父类型的。比如:花木兰替父从军,大家都把花木兰看做她爸,但是实际从军的是花木兰,而且,花木兰只能做她爸能做的事,在军营里是不可以化妆的。向下转型(较少):子类的引用的指向子类对象,过程中必须要采取到强制转型。这个是之前向上造型过的子类对象仍然想执行子类的特有功能,所以需要重新恢复成子类对象Parent p = new Child();//向上转型,此时,p是Parent类型Child c = (Child)p;//此时,把Parent类型的p转成小类型Child其实,相当于创建了一个子类对象一样,可以用父类的,也可以用自己的说明:向下转型时,是为了方便使用子类的特殊方法,也就是说当子类方法做了功能拓展,就可以直接使用子类功能。比如:花木兰打仗结束,就不需要再看做是她爸了,就可以”对镜贴花黄”了————————————————版权声明:本文为CSDN博主「程序媛 泡泡」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/weixin_43884234/article/details/116593803
  • [技术干货] 初识C语言(中篇)[转载]
    10. 操作符算数操作符+        -        *        /        %算数操作符中的+ - *和平常运算方法相似,我们在这边重点介绍 / 和 %运算符/ 操作符为了让我们的讲解更加具有针对性,我们分正数和负数两部分进行讲解:/ 操作符对正数#include<stdio.h>int main(){    int a = 7 / 2;    printf("%d\n", a);//3}分析:对于上方代码当我们用平时的逻辑,那么这个答案应该是3.5,可在程序中编译运行,结果是 3,我们不禁产生疑惑是不是因为你打印的结果是整形的缘故,其实本身结果还是3.5呢?让我们用代码验证:#include<stdio.h>int main(){    float f = 7 / 2;    printf("%f\n",f);//3.000000}可当我们再次进行编译运行时,结果是3.000000,因此我们可以得出结论:除号两端的操作数如果都是整数,执行的是整数除法,至少有一个操作数是浮点数,执行的才是浮点数的除法!!!对于正数是这样进行运算的,那么负数呢?/ 操作符对负数#include<stdio.h>int main(){    int i = -2.9;    int j = 2.9;    printf("%d\n",j);//-2    printf("%d\n",j);//2    return 0;}对于负数运算,我们打印 j 的值,结果为 -2 ,和正数运算规律相似,我们可以看出它们运算都是向0取整的,那么如何理解呢?对于取整,当正负数进行运算时,并不会出现四舍五入的情况,无论正数负数都是向0方向取整!(-2.9向零取整得到2)如下图所示:小科普在C语言中,是不是只有一种取整方式?如果有它们分别是怎么实现的?接下来我们来一一了解:trunc - 取整函数#include<math.h>int main(){     printf("%d\n",(int)trunc(-2.9));//-2      printf("%d\n",(int)trunc(2.9));//2  }Tips:由于trunc函数默认接收的返回值为%f,但是我们这边想输出的是整数所以强制类型转化成int类型。floor - 地板取整#include<stdio.h>#include<math.h>int main(){    printf("%.lf\n",floor(-2.9));//-3    printf("%.lf\n",floor(-2.1));//-3    printf("%.lf\n",floor(2.9));//2    printf("%.lf\n",floor(2.1));//2}因为其取整方式和函数名,我们称它为地板取整,什么意思呢,我们编译结果发现负数-2.9的值变成了-3,对于正数2.9的值变成了2。我们可以观察到无论是正数还是负数,在用floor函数进行取整的时候都是变小,我们观察其本质可以总结为-∞取整,如下图所示:ceil - +∞取整#include<stdio.h>int main(){    printf("%.lf\n",ceil(-2.9));//-2    printf("%.lf\n",ceil(-2.1));//-2    printf("%.lf\n",ceil(2.9));//3    printf("%.lf\n",ceil(2.1));//3}当我们编译运行程序,可以观察到负数-2.9变为-2,-2.1变为-2,正数2.9变为3,2.1变为3。我们可以观察到ceil函数的取整,结果都会在原来的基础上变大一个整数位,我们总结出该取整方式为+∞取整,如下图所示:round - 四舍五入取整是的你没有看错,与我们平常思维方式相同的四舍五入取整来了,上代码:#include<math.h>int main(){    printf("%.lf\n",round(-2.9));//-3    printf("%.lf\n",round(-2.1));//-2    printf("%.lf\n",round(2.9));//3    printf("%.lf\n",round(2.1));//2}对于这种取整方式,没什么好说的,就是按照我们平时的思路来,例如当值2.9时,值为3,当值为2.1时,值为2。在当前情况下,凡取整的值大于等于2.5,得出的结果都会变为3。% 操作符概念:如果a和d是两个自然数,d非零,可以证明存在两个唯一的整数 q 和 r,满足 a = q*d + r 且0 ≤ r < d。其中,q 被称为商,r 被称为余数。对于此部分我们依旧是从正数和负数两方面进行剖析:% 操作符对正数#include<stdio.h>int main(){    int a = 10;    int d = 3;    printf("%d\n",a%d);//1    //因为:a=10,d=3,q=3,r=1 0<=r<d(3)    //所以:a=q*d+3 -> 10=3*3+1    return 0;}-代码:基于概念,我们可以理解当前代码的意思(详情见注释)。但我们还有另一种理解方式:% 操作符,关注的是除法后的余数,例如代码中的10%3,我们也可以理解为商3余1,相对于概念,这种方式更加容易接受一些。Warning:操作符两端的操作数必须是整数!!!% 操作符对负数int main(){    int a = - 10;    int d= 3;    printf("%d\n",a%d);//-1} 很显然,结果不满足定义中的0<=r<d,故后来就有了一个修订版的定义:如果a和d是两个自然数,d非零,可以证明存在两个唯一的整数 q 和 r,满足 a = q*d + r , q 为整数,且0 ≤ |r| < |d|。其中,q 被称为商,r 被称为余数。根据定义,这里的结果也能解释了,即-10 = (-3)*3+(-1)。在C语言中,%本质为取余,余数的大小,本质取决于商q的,而商都取决于除法运算的取整规则。在对于正数的取余和取模在C语言中是相同的,我们发现对于向0取整和向-∞的取整在正数上是同向的,但是对于负数上就完全不同了,因此我们平时遇到的大多都是整数取模,并没有做太多解释。移位操作符>>        <<(以后讲解)位操作符&         ^(以后讲解)赋值操作符=        +=        -=        *=        /=        &=        ^=        |=        >>=由于赋值操作符便于理解,我们挑两个讲一下(详情见注释):int main(){    int a = 10;//创建变量,并初始化    a = 20;//赋值    a = a+5//等价于 a+=5    a = a-5//等价于 a-=5}单目操作符!                 逻辑反操作-                 负值+                正值&                取地址sizeof         操作数的类型长度(以字节为单位)~                对一个数的二进制按位取反--                前置、后置--++              前置、后置++*                 间接访问操作符(解引用操作符)(类型)         强制类型转换我们常见的操作符比如+都有两个操作数,表示为左操作数+右操作数,这种操作符叫做双目操作符。单目操作符其实就是只有一个操作数的。在这里,对于!,-,+等操作符都便于理解,而对于&和*我打算之后在指针部分讲解,这里我们着重讲一下--,和++操作符(详情见注释):#include<stdio.h>int main(){    int a = 10;    int b = ++a;//前置++,先++后使用    //a=a+1,b=a    printf("a=%d b=%d\n",a,b);//11 11    ---------------------------------    int a = 10;    int b = a++;//后置++,先使用,后++    //b=a,a=a+1    printf("a=%d b=%d\n",a,b);//11 10    ---------------------------------    int a = 10;    int b = --a;//前置--,先--后使用    //a=a-1,b=a    printf("a=%d b=%d\n",a,b);//9 9    ---------------------------------    int a = 10;    int b = a--;//后置--,先使用,后--    //b=a,a=a-1    printf("a=%d b=%d\n",a,b);//10 9}关系操作符>         >=         <        <=        !=(不相等)        ==(相等)前几个操作符,也就是对应的大于,大于等于,小于,小于等于等比较关系的操作符,这里我们讲一下后两个操作符。例1int main(){    int a = 3;    int b = 3;    if(a!=b)    {        printf("hehe\n");        }    if(a==b)    {        printf("haha\n");        }    //结果为hehe}运行结果如下: 观察代码,很简单,判断a和b是否相等,如果相等则输出haha,若不相等输出hehe,因为c此处a和b都等于3,所以打印结果为hehe。例2#include<stdio.h>int main(){    char arr1[] = "abcdef";    char arr2[] = "abcdef";    if(arr1==arr2)    {        printf("==\n");        }    else    {        printf("!=\n");        }}我们知道用==和!=可以判断是否相等,那么对于字符串呢?他们是否相等,当我们编译后,发现它们是不相等的!因为arr1和arr2是字符串首元素地址,开辟的空间不同,所以地址当然不同,如果要比较两个字符串的大小可以用strcmp函数,接下来看修改后的代码:#include<stdio.h>#include<string.h>int main(){    char arr1[] = "abcdef";    char arr2[] = "abcdef";    if(strcmp(arr1,arr2)==0)    {        printf("==\n");        }    else    {        printf("!=\n");        }}再次运行:对于strcmp这个函数使用时需要应用头文件#include<string.h>,如果返回的值为0,则两个字符串相等。 逻辑操作符&& - 逻辑与 - 并且        || - 逻辑或 - 或者int main(){    int a= 3;    int b = 0;    int c = a && b;    printf("%d\n",c);//真为1,假为0    if(a&&b)    {        printf("hehe\n");        }    if(a||b)    {        printf("haha\n);    }}运行得:分析:&&的返回值是这样规定的,如果两个数都为真,则值为1,反之则为0。对于本代码由于a&&b为0,故不打印hehe,||的值是有一个为真则为真,值为1,反之为0。这里由于a||b为真,所以打印haha。条件操作符exp1?exp2:exp3#include<stdio.h>int main(){    int a = 10;    int b = 0;    b = (a>5?3:-3);    printf("%d\n",b);//3    return 0;}分析:条件操作符使用时先判断表达式1,如果表达式1结果为真,则输出第一个值,否则为第二个值,改题中因为a>10,所以打印结果为3。当然,这段代码也可以用if        else语句来表示:#include<stdio.h>int main(){    int a = 10;    int b = 0;    if(a>5)    {        b=3;        }    else    {        b=-3;        }    printf("%d\n", b);}逗号表达式exp1, exp2, exp3, …expN#include<stdio.h>int main(){    int a=3;    int b=5;    int c=0;    int d= (a+=2,b=b-c+a,c=a+b);    //      a=5   b=10   c=5+10             printf("%d\n",d);}分析:对于逗号表达式其特点为从左往右依次计算,整个表达式的结果是最后一个表达式的结果,因此在代码中d的值也就是15。下标引用、函数调用和结构成员[]        ()        .        ->对于这类操作符我们讲解一下[ ]操作符:#include<stdio.h>int main(){    int arr[10] = {0};    arr[4]=5;    return 0;}分析:对于上述代码就是引用下标4,将arr[4]的位置上赋值5。和一些操作符相同,[ ]也有两个操作数,例如arr 和 4是两个操作数,对于这个代码写成4[arr]也可以,但是这种写法不仅让人难以理解,而且比较挫,我们可千万不要写出这样的代码!!!11. 常见关键字C 语言标准中规定了32个关键字,而在之后C99的标准下又增加了五个关键字,anduin这次对大家进行归纳的是C标准中的32个关键字,我们根据其特性,可以把它分为几类:  数据类型关键字(12个)char:声明字符型变量或函数short:声明短整型或函数Int :声明整型变量或函数long :声明长整型变量或函数signed:声明有符号类型变量或函数unsigned:声明无符号整形变量或函数foat:声明浮点型变量或函数double:声明双精度变量或函数struct:声明结构体变量或函数union:声明共用体(联合)数据类型enum:声明枚举类型void:声明函数无返回值或无参数,声明无类型指针控制语句关键字(12个)1.循环控制(5个)for:一种循环语句do:循环语句的循环体while :循环语句的循环条件break:跳出当前循环continue:结束当前循环,开始下一轮循环2.条件语句(3个)if:条件语句else:条件语句否定分支goto:无条件跳转语句3.开关语句(3个)switch:用于开关语句case:开关语句分支default:开关语句中的"其他"分支4.返回语句(1个)return:函数返回语句(可以带参数,也可以不带参数)5.存储类型关键字(5个)auto:声明自动变量,一般不使用extern:声明变量实在其他文件中声明register:声明寄存器变量static:声明静态变量typedef:用以给数据类型取别名(但是该关键字被分到存储关键字分类中,虽然看起来没什么相关性)注意:存储关键字,不可以同时出现,也就是说,在一个变量定义的时候,只能有一个。6.其它关键字(3个)const:声明只读变量sizeof:计算数据类型长度volatile:说明变量在程序执行中可被隐含地改变这里anduin带大家有选择性的,讲解几个关键字,若没有讲到日后我们一一讲解:autoauto 从字面意思来看就是自动的意思 它也被成为自动变量局部变量都是自动创建,自动销毁的,所以局部变量都是auto修饰的。int main(){    auto int a = 10;//局部变量都是auto类型的,因此auto基本会被省略    return 0;}typedef本质本质:类型重命名使用方法#include<stdio.h>typedef unsignde int u_int;int main(){    u_int x = 0;     return 0;}分析:当我们在写代码时,一些代码类型很长,例如无符号整型unsigned int或者结构体,指针等,这时我们就可以用typedef对它进行类型重命名,本段代码中就是用了typedef来重命名unsigned int为u_int。作用对类型重命名的一种解决方案,让我们在面临冗长的类型命名方面上更加简便,可以对一些不太好理解的数据类型进行简化。register我们先想想,数据在计算机上可以存放在哪里呢?1.内存2.硬盘3.高速缓存4.寄存器存储金字塔寄存器存在的本质从硬件层面上,提高计算机的运算效率。当读取数据时,计算器先去寄存器中读取,如果没有读取到,再去高速缓存区中读取,最后才是内存,而且在cpu再读取寄存器中的数据时,内存->高数缓存区(cache),cache->寄存器,这个数据传递过程会持续进行,大大提高效率!register 修饰变量也就是相同的原理,尽量把所修饰变量,放入CPU寄存区中,从而达到提高效率的目的。#include<stdio.h>int main(){    register int a = 10;    return 0;}register 修饰什么变量register可不是什么变量都适合修饰的,要知道寄存器的价格是很昂贵的,register所修饰的变量也得"精挑细选"一番。局部变量(全局变量由于其特性会导致CPU寄存器被长时间占用)不会被写入的(写入就需要写回内存,register本身就是快速读取,后续还要读取检测的话,就与原目的背道而驰了)高频被读取的变量(俗话说把钱用在刀刃上,存入了寄存器,当然要经常使用的)如果要使用,不要大量使用,寄存器的数量是有限的!小科普register修饰的变量,不能取地址!!!#include<stdio.h>int main(){    register int a = 0;     printf("&a = %p\n", &a);    return 0;}编译运行: 分析:因为register的作用,变量a已经被放入寄存器中了,你怎么取地址呢?结语以上就是初识C语言中篇的内容,虽然只有两个专题,但是内容其实也是很多的,希望我的文章对你有帮助,如果大家觉得anduin写的还可以的话,请点赞+收藏哦!你们的肯定就是对我最大的鼓励!今天也是高考第一天,祝广大学子辛勤奋战在学海,汗水扬起成功帆!愿大家都可以金榜题名!————————————————版权声明:本文为CSDN博主「ExplorerAnduin」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/m0_67867172/article/details/125163589
  • [技术干货] C语言-指针作为函数形参类型
    ## 1. 前言 C语言函数里最常用就是指针传参和返回地址,特别是字符串处理中,经常需要封装各种功能函数完成数据处理,并且C语言标准库里也提供了`string.h` 头文件,里面包含了很多字符串处理函数;这些函数的参数和返回值几乎都是指针类型。这篇文章就介绍如何使用指针作为函数参数、并且使用指针作为函数返回值。 下面通过几个示例代码来演示用法。 ## 2. 通过指针间接修改主函数里局部变量空间的值 ```cpp #include #include void func(int *p); int main() { int a=100; func(&a); printf("a=%d\n",a); //200 return 0; } void func(int *p) { printf("p=%d\n",*p); *p=200; } ``` ## 3. 在子函数里通过指针类型间接交换main函数里局部变量空间的值 ```cpp #include #include void func(int *a,int *b); int main() { int a=100,b=200; func(&a,&b); //func(100,200) printf("a=%d,b=%d\n",a,b); return 0; } void func(int *a,int *b) { int c; c=*a; *a=*b; *b=c; } //return语句只能返回一个值 //如果函数想返回多个值,可以使用指针(形参)实现。 ``` ## 4. 函数返回指针类型 ```cpp #include #include char *func(char *p); int main() { char str[]="1234567890"; char *p; p=func(str); printf("%s\n",p); // return 0; } char *func(char *p) { p+=3; //p向后偏移3个字节 return p; } ``` ## 5. 编写一个计算字符串长度的函数 函数功能: 传入字符串,返回字符串的长度。 与strlen函数功能一样即可。 ```cpp #include #include int my_strlen(char *p); //函数声明 int main() { char buff[100]; int len; printf("请输入字符串:"); scanf("%s",buff); len=my_strlen(buff); printf("len=%d\n",len); return 0; } //每个函数的功能要单一 //计算字符串长度。 字符串特点结尾是有'\0' //"1234567890" int my_strlen(char *p) { char *str=p; while(*str++!='\0'){} return str-p-1; } ``` ## 6. 编写一个字符串排序函数 函数功能: 传入字符串,在函数里实现字符串从大到小或者小到大排序。 注意: 从大到小或者小到大排序可以通过函数形参区分。 ```cpp #include #include int my_strlen(char *p); //函数声明 void str_sort(char *p,char flag);//函数声明 int main() { char buff[100]; int len; printf("请输入字符串:"); scanf("%s",buff); //进行排序 str_sort(buff,0); printf("从小到大排序=%s\n",buff); str_sort(buff,1); printf("从大到小排序=%s\n",buff); return 0; } //每个函数的功能要单一 //计算字符串长度。 字符串特点结尾是有'\0' //"1234567890" int my_strlen(char *p) { char *str=p; while(*str++!='\0'){} return str-p-1; } /* 函数功能: 实现字符串排序.支持从小到大或者大到小 函数形参: char *p 将要排序的字符串 char flag 选择排序方式 0表示从小到大排序 1表示大到小排序 */ void str_sort(char *p,char flag) { int len; int i,j,tmp; len=my_strlen(p); for(i=0;i/1表示大到小排序 { if(p[j]p[j+1]=tmp; } } else//0表示从小到大排序 { if(p[j]>p[j+1]) { tmp=p[j]; p[j]=p[j+1]; p[j+1]=tmp; } } } } } //unsigned char a; // 0~255 占1 =8位 1111 11111 //char a; //-128 ~ +127 ``` ## 7.变量默认的系统初始化值 ```cpp #include #include int a1; int main() { int a2; static int a3; printf("a1=%d\n",a1); //0 printf("a2=%d\n",a2); //随机值 printf("a3=%d\n",a3); //0 return 0; } /* 全局变量默认值是0 局部变量默认值是随机值(系统没有赋值) 静态变量默认值是0 */ ```
  • [技术干货] C语言-函数的定义、声明、传参
    ## 1. 前言 C语言里函数是非常重要的知识点,一个完整的C语言程序就是由主函数和各个子函数组成的,主函数调用子函数完成各个逻辑功能。 ## 2. 函数在C语言里是什么概念? 函数相当于打包代码的过程,程序代码里如果有很多重复代码,可以将重复代码写成一个函数,进行调用。 C语言程序里除了main函数(主)之外的函数都叫子函数,都属于自定义函数。 ## 3. 函数如何定义?如何编写一个函数? 函数定于分为几种情况:1. 有形参 2.无形参 3.有返回值 4. 无返回值 ```cpp /* 函数返回值类型> [函数的名称](函数的形参类型) { 函数体 } */ void func1(void) { } int func2(int a) { return 12; } int func3(int a,int b,int c,.....) { return 12; } void func4(char *p) { } ``` ## 4.自定义的函数如何调用和声明? ```cpp #include #include void func1(void); //提前声明函数 int main() { func1(); //调用函数 return 0; } //定义函数 void func1(void) { printf("hello\n"); } ``` 如果在调用函数之前编写函数体,就不需要声明: ```cpp #include #include //定义函数 void func1(void) { printf("hello\n"); } int main() { func1(); //调用函数 return 0; } ``` ## 5. 函数如何传入形参并接收返回值? ```cpp #include #include //函数声明 int func(int a,int b); //int func(int,int); int main() { int a; a=func(10,20); //调用函数 printf("a=%d\n",a); return 0; } //计算a+b结果值 int func(int a,int b) { int c; c=a+b; return c; //返回结果,并终止函数执行 } ``` ## 6. return 语句作用 return 本身功能终止函数执行,顺带返回一个值给调用者。 语法: `return [值或者是表达式或者不填];` `表达式: 1234` 并且return 函数每次只能返回一个值。 ```cpp #include #include //函数声明 void func(void); int main() { func(); return 0; } void func(void) { printf("1234567890\n"); return; //直接结束函数 printf("ABCD\n"); } ``` ## 7. 变量的作用域:局部变量、全局变量、块级变量 全局变量: 将变量定义在函数体外就属于全局变量。 局部变量: 将变量定义在函数体内就是属于局部变量。 块级变量: 就是在语句范围内定义的变量。 `if(a>b){int c;…. }` 生命周期: 全局变量生命周期和main函数共存。 ```cpp #include #include int a=100; void func(void); int main() { int a=200; printf("a1=%d\n",a); //200 当局部变量和全局变量名称相同的情况下优先使用局部变量 a=400; printf("a2=%d\n",a); //400 func(); return 0; } void func(void) { printf("a3=%d\n",a); //100 } ``` ## 8. 静态变量 静态变量声明关键字: static ```cpp #include #include int func(int a); int main() { int i; for(i=0;i5;i++) { printf("%d\n",func(i));//01234 } return 0; } int func(int a) { //int b=0; 局部变量 static int b=0; //静态变量(局部全局变量)--生命周期 b+=a; return b; } //函数调用完毕之后,函数占用的空间都会释放 ```
  • [其他] 华为云Python编程学习路径
    Python是一种易于学习又功能强大的编程语言。它提供了高效的高级数据结构,还能简单有效地面向对象编程。Python优雅的语法和动态类型,以及解释型语言的本质,使它成为多数平台上编写脚本和快速开发应用的理想语言,受到很多程序员的青睐。本课程将从Python环境搭建开始带您走进Python的世界,了解Python独特的语法和应用于web、爬虫、AI等领域的框架工具;同时结合实践操作,增强您的编程能力。https://education.huaweicloud.com/programs/2708d678-5dbb-4be2-afc4-88ae69f0dca3/aboutPython 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。Python 的设计具有很强的可读性,相比其他语言经常使用英文关键字,其他语言的一些标点符号,它具有比其他语言更有特色语法结构。Python 是一种解释型语言: 这意味着开发过程中没有了编译这个环节。类似于PHP和Perl语言。Python 是交互式语言: 这意味着,您可以在一个 Python 提示符 >>> 后直接执行代码。Python 是面向对象语言: 这意味着Python支持面向对象的风格或代码封装在对象的编程技术。Python 是初学者的语言:Python 对初级程序员而言,是一种伟大的语言,它支持广泛的应用程序开发,从简单的文字处理到 WWW 浏览器再到游戏。特点:    易于学习:Python有相对较少的关键字,结构简单,和一个明确定义的语法,学习起来更加简单。    易于阅读:Python代码定义的更清晰。    易于维护:Python的成功在于它的源代码是相当容易维护的。    一个广泛的标准库:Python的最大的优势之一是丰富的库,跨平台的,在UNIX,Windows和Macintosh兼容很好。    互动模式:互动模式的支持,您可以从终端输入执行代码并获得结果的语言,互动的测试和调试代码片断。    可移植:基于其开放源代码的特性,Python已经被移植(也就是使其工作)到许多平台。    可扩展:如果你需要一段运行很快的关键代码,或者是想要编写一些不愿开放的算法,你可以使用C或C++完成那部分程序,然后从你的Python程序中调用。    数据库:Python提供所有主要的商业数据库的接口。    GUI编程:Python支持GUI可以创建和移植到许多系统调用。    可嵌入: 你可以将Python嵌入到C/C++程序,让你的程序的用户获得"脚本化"的能力。
  • [新手课堂] Python函数笔记
    一:函数的创建和调用函数的创建:def calc(a,b):    c=a+b    return cresult=calc(10,20)print(result)二:函数的参数传递位置实参:·根据形参对应的位置进行实参传递关键字实参:·根据形参名称进行实参传递三:函数的返回值例题:输出奇数偶数分好类的def fun(num):    odd=[]    even=[]    for i in num:        if i%2:            odd.append(i)        else:            even.append(i)    return odd,evenlst=[10,29,34,44,54]print(fun(lst))函数的返回值::如果函数没有返回值[函数执行完毕后,不需要给调用处提供数据]return可以省略不写:函数的返回值,如果是1个,直接返回类型。:函数的返回值,如果是多个,返回的结果为元组。四:函数的参数定义默认值参数:def fun(a,b=10):#b称为默认值参数    print(a,b)#函数的调用fun(100)# 100 10fun(20,30)#20 30函数定义时:给形参设置默认值,只有与形参不符的时候才需要传递实参。个数可变的位置参数:定义函数时,可能无法事先确定传递的位置实参的个数,使用可变的位置参数。使用*定义个数可变的位置形参结果为一个元组def fun(*c):    print(*c)fun(10)fun(10,20)fun(100,20,30)输出结果就是:10;10,20;100,20,30;个数可变的关键字形参:定义函数时,无法事先确定传递的关键字实参的个数时,使用可变的关键字形参,使用**定义个数可变的关键字形参结果为一个字典def fun(**c):    print(c)fun(a=10)fun(a=10,b=20)fun(a=100,b=20,c=30)print("hello",'world','chang')函数调用时的参数传递:def fun(a,b,c):    print('a=',a)    print('b=',b)    print('c=',c)fun(10,20,30)结果:a= 10b= 20c= 30如果我们要传一个字典进去的话:def fun(a,b,c):    print('a=',a)    print('b=',b)    print('c=',c)lst=[11,22,33]fun(*lst)结果才会一一对应上。五:递归函数:def fac(n):    if n==1:        return 1    else:        return n*fac(n-1)print(fac(6))递归函数大家应该都很熟悉了,我不介绍了,我只把实现的代码放过来了。斐波那契额数列:def fib(n):    if n==1:        return 1    elif n==2:        return 1    else:        return fib(n-1)+fib(n-2)print(fib(6))
  • [新手课堂] 比较运算符的链接
    比较运算符的聚合是另一个有时可以派上用场的技巧。n = 10 result = 1 < n < 20 print(result) # True result = 1 > n <= 9 print(result) # False
  • [交流吐槽] 函数
    1、函数的优点:(1)复用代码(2)隐藏实现细节(3)提高可维护性(4)提高可读性便于调试2、函数的创建:def 函数名([输入参数])函数体[return xxx]3、函数的参数传递:(1)函数调用时的参数传递:位置实参:根据形参对应的位置进行实参传递,位置对应例如def fuc1(a,b),调用时fuc1(10,20)关键字实参:根据形参名称进行实参传递,例如def fuc1(a,b),调用时fuc1(b=10,a=20)(2)如果是不可变对象,在函数体内的修改不会影响实参的值如果是可变对象,在函数体内的修改会影响实参的值4、函数的返回值:(1)函数返回多个值时,结果为元组(2)函数返回一个值时,结果为原值(3)函数没有返回值时,省略return5、函数的参数定义:(1)函数定义默认值参数:函数定义时,给形参设置默认值,只有与默认值不符的时候才需要传递实参。只传一个参数,未被定义的参数未默认值。默认值参数注意一定要放在其他需要传递实参的形参最后。(2)个数可变的位置参数:使用*定义,结果为一个元组,例如def fun1(*args)个数可变的关键字形参:使用**定义,结果为一个字典,例如def fun1(**args)如果要让函数接受不同类型的实参,必须在函数定义中将接纳任意数量实参的形参放在最后。 Python先匹配位置实参和关键字实参,再将余下的实参都收集到最后一个形参中。
  • [新手课堂] 算数运算符
    基本四则与算符+   -   *   /   %注意事项:1、0不能作为除数;2、%表示取余,不仅可以对int求模,也可对double求模;增量赋值运算符又叫复合运算符,会自动进行类型转换;+=    -=    /=    *=    %=自增自减运算符自增或自减符号在前先自增或自减再参他运算;自增或自减符号在后先参与运算再自增或自减;如果自增自减符号在前则取的返回值是自增或自减之后的返回值,反之则取原返回值;++   --