Python调用C++

news2024/11/15 17:40:50

1 背景

python被称为胶水语言,其优势是能够粘结各种不同的语言。同时,python有着更大的“亲民性”,很容易进行开发。但是,python最大的问题就是计算速度不够。通常可以用CUDA或者C++对一个python程序进行加速,加速策略如下:

  • 大规模算术运算、矩阵运算等过程用底层语言编写,python只负责传参和处理结果数据;

  • 十分常用的函数,我们可以用C++写成“算子”,然后python调用算子即可,如边缘检测的Sobel算子;

2 原理说明与注意事项

2.1 原理说明

为什么要用extern "C"

使用C++来编译so库,需要注意一点,C++中的函数需要extern "C"来转成C语法编译,因为C++函数是可以重载的,使用g++编译函数会附上额外信息而不是函数名本身,比方void print(int a);使用g++编译会生成print_int之类的,这样cdll.LoadLibrary的时候会找不到。所以,我们需要让编译器使用C方法编译,这样才能达到目的。这也是值得我们请注意的一点。

调用ctypes的原理

调用Python的自有模块ctypes,其中cdll = <ctypes.LibraryLoader object>是一个库加载器对象,调用cdll.LoadLibrary便可调用C++的so库。

2.2 注意事项

  • 如果python在调用C函数内部出现了问题,系统不会提示具体出现什么问题,只会提示"segmentation fault"。所以最好是先用C语言调用该动态库验证没有问题了再提供给python调用。

  • python传参给C函数时,可能会因为python传入实参与C函数形参类型不一致会出现问题( 一般int, string不会有问题,float要注意)。这时需要在python调用时传入的实参做一个类型转换(见第三部分)

3 简单的python调用C++实例

3.1 无输入输出参数情况

原始CPP代码hello_world.cpp

#include <iostream>
using namespace std;

int main(){
    cout<<"hello world\n";
}

C++的函数需要用extern描述才能被Python调用。将代码修改为如下形式的CPP文件,如下:

#include <iostream>
using namespace std;

extern "C"{
    int main(){
        cout<<"hello world\n";
    }
}

在Linux环境下编译:

g++ -o hello_world.so -shared -fPIC hello_world.cpp

image-20221212084555893

根据上面的编译命令,就可以在同目录下得到名为hello_world.so的文件了,这就是可以被python直接调用的。再来看看python调用的代码:

import ctypes
ll = ctypes.cdll.LoadLibrary
lib = ll('./hello_world.so')
lib.main()

这样就成功实现在无传参情况下python调用C++的函数。输出如下

image-20221212084720256

3.2 有输入参数的情况

C++函数如果带输入参数

#include <iostream>
#include <string>
using namespace std;
extern "C"{
    void test(int n){
            cout<<"The input is "<<n<<"\n";
        }
}

编译完成后,python调用代码

import ctypes
ll = ctypes.cdll.LoadLibrary
lib = ll('./hello_world.so')
lib.test(100)

image-20221212085618832

3.3 有输出参数的情况

C++函数如果带输入参数

#include <iostream>
#include <string>
using namespace std;
extern "C"{
    int test(int n){
            cout<<"The C++ input is "<<n<<"\n";
            cout<<"The C++ output is "<<n+100<<"\n";
            return n+100;
        }
}

编译完成后,python调用代码

import ctypes
ll = ctypes.cdll.LoadLibrary
lib = ll('./hello_world.so')
cpp_out = lib.test(100)
print(cpp_out)

image-20221212085808293

3.4 多输入参数的情况

C++代码

#include <iostream>
#include <string>
using namespace std;
extern "C"{
    void test(int n1, int n2, int n3){
            cout<<"The C++ input 1 is "<<n1<<"\n";
            cout<<"The C++ input 2 is "<<n2<<"\n";
            cout<<"The C++ input 3 is "<<n3<<"\n";
        }
}

python调用代码

import ctypes
ll = ctypes.cdll.LoadLibrary
lib = ll('./hello_world.so')
lib.test(100,200,300)

image-20221212093432867

4 python与C++调用的类型转换

4.0 类型转换表

CType(Cpp经过extern转换成C后的类型)Python Type(python中的类型)ctypes Type(python中调用ctypes后实例化的类型)
charl-character stringc_char
wchar_tl-character Unicode stringc_wchar
charint/longc_byte
charint/longc_ubyte
shortint/longc_short
unsigned shortint/longc_ushort
intint/longc_int
unsigned intint/longc_uint
longint/longc_long
unsigned longint/longc_ulong
long longint/longc_longlong
unsigned long longint/longc_ulonglong
floatfloatc_float
doublefloatc_double
char * (NULL terminated)string or nonec_char_p
wchar_t * (NULL terminated)unicode or nonec_wchar_p
void*int/long or nonec_void_p

4.1 float的传入传出

如果还是使用之前的代码进行类似的直接传递就会出现如下问题

C++代码如下

#include <iostream>
#include <string>
using namespace std;
extern "C"{
    float test(float n){
            cout<<"The C++ float input is "<<n<<"\n";
            cout<<"The C++ float output is "<<n+100<<"\n";
            return n+100;
        }
}

python调用代码如下

import ctypes
ll = ctypes.cdll.LoadLibrary
lib = ll('./hello_world.so')
cpp_out = lib.test(100)
print(cpp_out)

image-20221212092843164

即使Python转换成python中的float也无济于事

image-20221212092920746

所以就需要在代码中进行类型转换

import ctypes
ll = ctypes.cdll.LoadLibrary
lib = ll('./hello_world.so')
lib.test.argtypes = [ctypes.c_float] # 对C++库在python中的实例进行进一步的输入参数类型的定义
lib.test.restype = ctypes.c_float # 对C++库在python中的实例进行进一步的输出类型的定义

cpp_out = lib.test(100)
print(cpp_out)

image-20221212173433627

同时还有一种方法:原理是使用ctype对python中的变量进行转换成一个新的变量,然后直接送到接口里面

import ctypes
ll = ctypes.cdll.LoadLibrary
lib = ll('./hello_world.so')
input_num = ctypes.c_float(100)
lib.test.restype = ctypes.c_float # 对C++库在python中的实例进行进一步的输出类型的定义
cpp_out = lib.test(input_num)
print(cpp_out)

输出结果同上

4.2 数据数组的传入传出

对于返回值为数组的情况,可以直接使用索引去访问,但是下标操作[]不是从迭代器中取对象,而是地址偏移

4.2.1 第一种方法(指定参数类型完成转换)

C++代码

#include <iostream>
#include <string>
using namespace std;
extern "C"{
    float* test(float* n){
            cout<<"The C++ input list is [0]:"<<n[0]<< "[1]:" << n[1] << "[2]:" << n[2] <<"\n";
            for(int i=0;i<3;i++){
                n[i] = n[i]+1;
            }
            return n;
        }
}

python调用代码

import ctypes
import numpy as np
ll = ctypes.cdll.LoadLibrary
lib = ll('./hello_world.so')
pyarray_in = [0.5,1.5,2.5]
carrary_in = (ctypes.c_float * len(pyarray_in))(*pyarray_in)
lib.test.argtypes = [ctypes.POINTER(ctypes.c_float*3)]
lib.test.restype = ctypes.POINTER(ctypes.c_float*3)
carray_out = lib.test(carrary_in) 
# 对指针类型数据的获取方法1
print(carray_out.contents[0])
print(carray_out.contents[1])
print(carray_out.contents[2])
# 对指针类型数据的获取方法2
for i in range(len(carrary_in)):
    print(carrary_in[i])

image-20221212145924189

4.2.2 第二种方法(使用numpy的封装进行类型转换)

C++代码不变

python调用代码,有如下特点

  • 可以使用内嵌的ndpointer类进行接口的定义
  • 可以对输出进行直接的转换,不需要根据索引去查找内存
  • 但是在定义接口的时候尤其是输出,是一定需要定义维度的,否则就会报错
import ctypes
import numpy as np
from numpy.ctypeslib import ndpointer,as_array
ll = ctypes.cdll.LoadLibrary
lib = ll('./hello_world.so')
pyarray = np.array([1,2,3], dtype="float32")

lib.test.argtypes = [ndpointer(ctypes.c_float)]
lib.test.restype = ndpointer(ctypes.c_float, shape=(3,))
array_out = lib.test(pyarray)
print(as_array(array_out))

image-20221212145941109

4.3 字符型变量的输入输出

C++代码

#include <iostream>
#include <string>
using namespace std;
extern "C"{
    char test(char n){
            cout<<"The C++ input char is "<< n <<"\n";
            cout<<"The C++ output char is "<< char(n+1) <<"\n";
            return n+1;
        }
}

python调用代码

注意事项需要在类型转换的过程中加入对应的编码等信息

import ctypes
import numpy as np
ll = ctypes.cdll.LoadLibrary
lib = ll('./hello_world.so')
lib.test.argtypes = [ctypes.c_char]
lib.test.restype = ctypes.c_char
cpp_out = lib.test('a'.encode('utf-8')) 
print(cpp_out)
print(cpp_out.decode())

image-20221212150850628

4.4 字符串变量的输入输出

C++代码

#include <iostream>
#include <string>
using namespace std;
extern "C"{
    char* test(char* n){
            cout<<"The C++ input char is "<< n ;
            char * n_out;
            for (int i=0; i<4; i++)
            {
                n_out[i] = char(n[i]-32);
            }
            return n_out;
        }
}

python调用代码(使用字符串形式)

import ctypes
ll = ctypes.cdll.LoadLibrary
lib = ll('./hello_world.so')
lib.test.argtypes = [ctypes.c_char_p]
lib.test.restype = ctypes.c_char_p
cpp_out = lib.test('abcd'.encode('utf-8')) 
print(cpp_out.decode())

image-20221212172129535

python调用代码(使用字符型指针类型,同时实例变量方式)

import ctypes
ll = ctypes.cdll.LoadLibrary
lib = ll('./hello_world.so')
lib.test.argtypes = [ctypes.c_char_p]
lib.test.restype = ctypes.c_char_p
cpp_in=(ctypes.c_char * 4)(*bytes("abcd",'utf-8'))
cpp_out = lib.test(cpp_in) 
print(cpp_out.decode())

4.5 图片的传入传出

其实原理和4.2.2一样 使用numpy的方式不一样

可以概括为如下伪代码

lib.C++函数名称.argtypes = [ndpointer(dtype=ctypes.c_int)]
lib.C++函数名称.restype = ctypes.POINTER(ctypes.c_int)
如果输出是要使用ndpointer的话需要定义维度
lib.C++函数名称.restype = ndpointer(ctypes.c_int, shape=(3,3))

python调用.so - 走看看

【python的numpy数组(c++接口PyArrayObject*) 和c++的Mat的相互转换】_无情的AI鸽子的博客-CSDN博客_python 调用c++ mat转换

Python中Numpy数组转换成C++中OpenCV的Mat类型(超少代码,超快速度)_Colin_Jing的博客-CSDN博客_numpy转mat

python 调用c++处理数组和图片_koibiki的博客-CSDN博客

4.6 二维数组

C++代码

#include <iostream>
#include <string>
using namespace std;
extern "C"{
    void show_matrix(int *matrix, int rows, int columns)
    {
        int i, j;
        for (i=0; i<rows; i++) {
            for (j=0; j<columns; j++) {
                printf("matrix[%d][%d] = %d\n", i, j, matrix[i*rows + j]);
            }
        }
    }
}

python调用代码

import ctypes
import numpy as np
 
lib = ctypes.cdll.LoadLibrary("./hello_world.so")
arr = np.random.randint(0, 10, size = (3,5))
print(arr)
#arr = np.array([[1,2],[3,4]])
tmp = np.asarray(arr)
rows, cols = tmp.shape
dataptr = tmp.ctypes.data_as(ctypes.c_char_p)
lib.show_matrix(dataptr, rows, cols)

image-20221212181255044

ctypes的运用(把一个numpy数组传入c中)_科研路上的小C的博客-CSDN博客_ctypes numpy

4.7 批量自适应python类型装换代码

写了一个总的接口,之后可以针对不同类型进行不不同的转换,然后直接送进去就好了

#将python类型转换成c类型,支持int, float,string的变量和数组的转换
def convert_type(input):
    ctypes_map = {int:ctypes.c_int,
              float:ctypes.c_double,
              str:ctypes.c_char_p
              }
    input_type = type(input)
    if input_type is list:
        length = len(input)
        if length==0:
            print("convert type failed...input is "+input)
            return null
        else:
            arr = (ctypes_map[type(input[0])] * length)()
            for i in range(length):
                arr[i] = bytes(input[i],encoding="utf-8") if (type(input[0]) is str) else input[i]
            return arr
    else:
        if input_type in ctypes_map:
            return ctypes_map[input_type](bytes(input,encoding="utf-8") if type(input) is str else input)
        else:
            print("convert type failed...input is "+input)
            return null
# 使用
直接将convert_type(python变量)送到so的库里面的函数中即可
eg
lib.test(convert_type(python变量))

python3调用cpp的方法——python调用so_springlustre的博客-CSDN博客_python cpp

4.8 结构体的传入传出

python 调用c++处理数组和图片_koibiki的博客-CSDN博客

python调用C++问题解决1(PEP 3118 buffer format string)

ValueError: ‘<P’ is not a valid PEP 3118 buffer format string

image-20221212142801554

  • 可能原因1:一般是因为python和numpy的版本不对,更新一下即可
  • 可能原因2:输出的接口处没有定义好维度信息(详见4.2.2)
  • 如何在python3 ctype中返回ndarray? - 问答 - 腾讯云开发者社区-腾讯云

python调用C++问题解决2(cannot dynamically load executable)

  • 可能原因1:动态库编译方式有问题,加入-shared

  • 可能原因2:也有可能是有可执行文件,可能需要把之前的可执行文件删掉了之后进行重新生成

cannot dynamically load executable的尴尬经历_Aero Auto的博客-CSDN博客_cannot dynamically load

python调用C++问题解决3(windows生成DLL后的使用)

python调用C++ DLL 传参技巧_冰雪满天的博客-CSDN博客

5 Python调用C++的另一种方式pybind11

pybind11 直接支持: 在python端传入list或numpy数据,c++中计算得到的vector或string结果也可以便捷传出

python调用c++模块.so库, 互相回传数据(ctypes、pybind11) - 知乎

6 使用cpython 调用 C/C++ 函数或者类

原理其实和Ctypes基本一致也是需要重定义接口的类型转换,但是这里可能定义文件都是在另一个文件中了,好像更加自由便捷一些,编译方式和之后的调用方式也有一些区别

Python 调用 C++ | iqhy’s Blog

速度测试

Cpp代码

#include <iostream>
#include <string>
using namespace std;
extern "C"{
    int test(int n){
            cout<<"The C++ input is "<<n<<"\n";
            int result = 0;
            for (int i=0;i<n;i++){
                result = result + 0;
            }
            cout<<"The C++ output is "<<result<<"\n";
            return result;
        }
}

python调用以及时间测试

from time import time
n = 1000000
result = 0
s1 = time()
for i in range(n):
    result = result + 0
print(result)
s2 = time()
print(s2-s1)

import ctypes
ll = ctypes.cdll.LoadLibrary
lib = ll('./hello_world.so')
input_num = ctypes.c_int(1000000)
lib.test.restype = ctypes.c_int # 对C++库在python中的实例进行进一步的输出类型的定义
s1 = time()
cpp_out = lib.test(input_num)
print(cpp_out)
s2 = time()
print(s2-s1)

image-20221212175555761

其实可以发现速度差距还是很大的,这只是简单循环所带来的差距

结论:

Python为C/C++语言提供了良好的扩展机制,这对于Python本身来说是至关重要的,因为这对于使用Python语言开发的项目来说,在特定条件下嵌入C/C++代码很有帮助,对于整个项目的开发和运用都是大有裨益的。

参考文献

python调用C++中的函数【最简明教程】_木盏的博客-CSDN博客_python调用c++函数

Python调用C/C++的两种方法 - 知乎

Python调用C++动态链接库返回数组 - 空‘ - 博客园

C++ 从函数返回数组 | 菜鸟教程

How do I convert a Python list into a C array by using ctypes? - Stack Overflow

如何在python3 ctype中返回ndarray? - 问答 - 腾讯云开发者社区-腾讯云

Value Error: ‘<P’ is not a valid PEP 3118 buffer format string · Issue #2 · rpoleski/MulensModel

python - PEP 3118 warning when using ctypes array as numpy array - Stack Overflow

Python中Numpy数组转换成C++中OpenCV的Mat类型(超少代码,超快速度)_Colin_Jing的博客-CSDN博客_numpy转mat

ctypes的运用(把一个numpy数组传入c中)_科研路上的小C的博客-CSDN博客_ctypes numpy

cannot dynamically load executable的尴尬经历_Aero Auto的博客-CSDN博客_cannot dynamically load

python调用c++模块.so库, 互相回传数据(ctypes、pybind11) - 知乎

python3调用cpp的方法——python调用so_springlustre的博客-CSDN博客_python cpp

Python 调用 C++ | iqhy’s Blog

python 调用c++处理数组和图片_koibiki的博客-CSDN博客

How do I convert a Python list into a C array by using ctypes? - Stack Overflow

Python如何调用DLL函数:C数组与numpy数组传递 - 腾讯云开发者社区-腾讯云

python调用C函数时的数组传递_左左张的博客-CSDN博客_python 传递数组给c

python调用C++ DLL 传参技巧_冰雪满天的博客-CSDN博客

之后可以参考的官方文档

C型外部功能接口 (numpy.ctypeslib ) — NumPy v1.21.dev0 Manual

NumPy API(二十八)——C-Types 外部功能接口 - 简书

C-Types外部函数接口(numpy.ctypeslib) - NumPy 中文文档

1. 使用 C 或 C++ 扩展 Python — Python 3.7.13 文档

使用Python作为粘合剂 - NumPy 中文文档

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

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

相关文章

【LeetCode】单词搜索 II [H](前缀树)

212. 单词搜索 II - 力扣&#xff08;LeetCode&#xff09; 一、题目 给定一个 m x n 二维字符网格 board 和一个单词&#xff08;字符串&#xff09;列表 words&#xff0c; 返回所有二维网格上的单词 。 单词必须按照字母顺序&#xff0c;通过 相邻的单元格 内的字母构成&am…

QT系列第2节 QT中元对象系统

QT是在标准C上进行了扩展&#xff0c;所以就有自己的特性&#xff0c;其中元对象系统就是其一。元对象系统有点类似于java和go语言中的反射&#xff0c;让我们在编程时解决问题多了些方法和思路&#xff0c;关于元对象可以简单总结出以下内容项。 目录 一.元对象要点总结 二…

Linux转发性能评估与优化之——转发瓶颈分析与解决方案

线速问题 很多人对这个线速概念存在误解。认为所谓线速能力就是路由器/交换机就像一根网线一样。而这&#xff0c;是不可能的。应该考虑到的一个概念就是延迟。数据包进入路由器或者交换机&#xff0c;存在一个核心延迟操作&#xff0c;这就是选路&#xff0c;对于路由器而言&…

软件工程复习简略

软件工程复习简略1.什么是软件生存周期&#xff1f;通常可划分为哪些阶段&#xff1f;2.简述需求分析要经过哪些步骤&#xff0c;每个步骤的作用。3.详细设计有哪些常用工具&#xff1f;&#xff08;注意Pad图的画法&#xff09;4.软件测试的目的和原则是什么&#xff1f;5.测试…

pythonselenium自动化测试实战项目(完整、全面)

前言 之前的文章说过&#xff0c; 要写一篇自动化实战的文章&#xff0c; 这段时间比较忙再加回家过11一直没有更新博客&#xff0c;今天整理一下实战项目的代码共大家学习。&#xff08;注:项目是针对我们公司内部系统的测试&#xff0c;只能内部网络访问&#xff0c;外部网络…

【SpringCloud负载均衡】【源码+图解】【三】LoadBalancer的工作原理

【SpringCloud负载均衡】【源码图解】【二】LoadBalancer配置 目录3. LoadBalancer的工作原理3.1 创建LoadBalancerRequest3.2 创建上下文3.2.1 properties3.2.2 configurations3.2.3 contexts3.3 获取ReactiveLoadBalancer3.4 获取ServiceInstance3.5 向serviceInstance请求结…

Java要学到什么程度才可以找工作?

Java为不同的集合提供了一个集合框架。集合基于数据结构&#xff0c;比如常见的&#xff1a;列表、数组、集合、哈希图等等。因此&#xff0c;在研究集合时&#xff0c;最好了解一点数据结构的相关知识。 主要副题&#xff1a; List Set Map ArrayList LinkedList Queue…

web3:智能合约-虚拟机(EVM、HVM、WASM、MOVE)

在区块链上&#xff0c;用户通过运行部署在区块链上的合约&#xff0c;完成需要共识的操作。而为智能合约提供运行环境的便是对应的虚拟机。 目录EVM基础概念技术细节EVM的存储模型交易在EVM的执行普通转账交易智能合约的创建或者调用EVM机器语言与现有的虚拟机科技作比较EVM的…

Java中类的复用

类的复用&#xff08;组合与继承&#xff09; 第一种方法&#xff1a;只需在新类中产生现有类的对象&#xff0c;新类由现有类组成&#xff0c;也称为组合&#xff0c;该方法只是复用了现有程序代码的功能&#xff1b; 第二种方法&#xff1a;按现有类来创建新类&#xff0c;…

m基于LPF-VMD和KELM的鸟群优化算法的风速预测算法matlab仿真

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 1).使用 LPF-VMD 对风速时间序列进行分解&#xff0c; 得到一个低频的趋势分量以及 n 个由 VMD 分解得 到的 BIMF。 2).对 LPF-VMD 分解得到的各分量分别建立 KELM 预测模型&#xff0c;采用 B…

【进阶】C语言第二课:升级你的指针(1)

目录 &#x1f929;前言&#x1f929;&#xff1a; 一、字符指针&#x1f92f;&#xff1a; 1.字符指针的使用&#x1f99d;&#xff1a; 2.常量字符串&#x1f98a;&#xff1a; 3.相关面试题分析&#x1f423;&#xff1a; 二、指针数组&#x1f9d0;&#xff1a; 三、数…

vue+nodejs公益图书借阅捐赠管理系统

公益图书捐赠管理系统 用户信息&#xff1a;id、用户名、密码、捐书数量&#xff08;管理员端可以点击跳转查看详情&#xff09;、上传电子书数量&#xff08;管理员端可以点击跳转查看详情&#xff09;、借阅图书数量&#xff08;管理员端可以点击跳转查看详情&#xff09;&am…

利用全长转录组多重阵列测序检测同源异构体

哈佛大学和麻省理工学院近期发表了“High-throughput RNA isoform sequencing using programmable cDNA concatenation.”研究论文中&#xff0c;将 cDNA 串联成可用于长读长测序最佳的单分子的技术应用于肿瘤浸润 T 细胞的单细胞 RNA 测序,提高了寻找可变剪接基因的准确度&…

秒懂:JCTool 的 Mpsc 高性能无锁队列 (史上最全+10W字长文)

文章很长&#xff0c;而且持续更新&#xff0c;建议收藏起来&#xff0c;慢慢读&#xff01;疯狂创客圈总目录 博客园版 为您奉上珍贵的学习资源 &#xff1a; 免费赠送 :《尼恩Java面试宝典》 持续更新 史上最全 面试必备 2000页 面试必备 大厂必备 涨薪必备 免费赠送 经典…

C# 修饰符

一 访问控制符 二 static 1 static 的字段、方法、属性是属于整个类的 ① static方法中&#xff0c;不能访问实例变量&#xff1b; ② 调用static方法时&#xff0c;直接用类名访问 Console.Write();Math.Sqrt(); Convert.ToDateTime();DateTime.Parse String.Copy(a);Strin…

【JavaSE】javaSE练习项目——>《简易图书管理系统》

目录 前言&#xff1a; 1、项目实现要求 2、设计思路流程 设计思路&#xff1a; 登录后菜单的实现效果&#xff1a; 3、代码实现&#xff08;大体框架&#xff09; Main类 book包 Book类 BookList类 user包 User类 AdminUser(管理员)类 NormalUser&#xff08;普通…

Hibernate Validator 使用详解

目录 Hibernate Validator的依赖 Hibernate Validator 支持注解 空与非空检查 Boolean值检查 日期检查 数值检查 其他 Hibernate-validator扩展约束 Hibernate Validator 校验 简单对象校验 嵌套对象校验 Hibernate Validator 分组校验 静态分组 动态分组 动态分…

【软件测试】刚入职后,快速适应新的工作需要做啥?

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 入职一家新公司后&a…

基于AD8226的环境光传感器电路

人们越来越多地认为环境光是一种能源,可用于驱动心率监控器、浴室灯具、远程天气传感器和其他低功耗器件。对于能量采集系统,最关键的是精确测量环境光的能力。本设计思路将描述一种简单的低成本电路,可以根据环境光的强度按一定比例提供电压。 所用传感器是一款光敏电阻(L…

spring framework 容器

org.springframework.beans 和 org.springframework.context 包是 Spring Framework 的 IoC 容器的基础。 这里需掌握两个体系结构&#xff0c;BeanFactory 和 ApplicationContext。 BeanFactory 主要接口&#xff0c;可分为三级&#xff1a; BeanFactory 是顶层容器&#xf…