python和C++对比(1)_数据类型和数据结构
📅 2026/7/6 8:29:33
👁️ 阅读次数
📝 编程学习
前言
- 这个系列的文章,以python为主,会从编程语言的四类知识范畴去总结对比python和C++。这部分文章共四篇,分别是:数据类型和数据结构、语法规则和执行流程、内存模型和运行机制、编程范式和语言特性,这篇文章是从数据类型和数据结构的角度对比两者的不同。
- 这部分总结,是通过总分的架构实现的,目的是展现两种编程语言的区别,对比着学习,理解他们之间的本质差异,加深记忆。
- 这个系列的每一篇文章,后面会继续修改,完善。
- python和C++本质不同:Python中万物皆对象,所有数据、变量本质都是对象引用,统一面向对象设计;C++兼顾原生值类型 + 对象类型,分为两套独立体系,并非一切都是对象。
- 数据类型和数据结构:将编程语言比喻成一个产品加工厂的话,数据类型和数据结构就是这个工厂生成时需要的原材料。
- 数据类型:编程语言中对数据的分类定义,规定了一类数据的取值范围、存储形式以及可进行的合法操作,是构成程序数据的基础单元。
- 数据结构:数据的组织、存储与排列方式,基于基础数据类型构建而成,用于高效地管理、访问和操作批量数据,核心是数据的布局逻辑与操作效率。
摘要
| 序号 | 对比概念 | python | C++ | 补充 |
|---|---|---|---|---|
| 1 | 自带数据类型 | √ | √ | × |
| 2 | 衍生数据类型 | √ | √ | √ |
| 3 | 数据类型特性 | √ | √ | × |
概念对比
一、自带数据类型:语言内核 / 编译器底层硬编码实现、无需引入任何库、无需自定义。声明后可直接使用的基础数据类型,是语言最底层的基础存储单元。
1.1、在python中的定义:
- python自带数据类型一共五类:int、float、bool、str、None
- int:内置基础类型;无限精度整数,不分长短整型,自动适配数值大小,二进制/八进制/十六进制均可表示。
- float:内置基础类型;64位双精度浮点数,存在浮点精度误差,支持科学计数法。
- bool:内置基础类型,int子类;仅True、False两个取值,True等价1,False等价0。
- str:内置序列类型;不可变字符序列,单/双/三引号定义,支持切片。不可变,不能增删改,仅可查询。
- None:内置基础类型;唯一值None,表示空对象,区别0、空字符串。
1.2、具体案例:
# -*- coding: utf-8 -*-# Python五大自带基础数据类型演示num_int=9999999999999999999999999999# int 无限大整数num_float=3.14e-2# float 科学计数浮点数flag_bool=True# bool布尔值text_str="hello python"# str字符串empty_none=None# None空对象# 打印值与对应类型print(num_int,type(num_int))# 9999999999999999999999999999 <class 'int'>print(num_float,type(num_float))# 0.0314 <class 'float'>print(flag_bool,type(flag_bool))# True <class 'bool'>print(text_str,type(text_str))# hello python <class 'str'>print(empty_none,type(empty_none))# None <class 'NoneType'># 补充特性演示print(True+5)# bool是int子类,True等价1 6print(text_str[0:3])# str切片读取,不可修改 helprint(None==0)# None不等于数字0 Falseprint(None=="")# None不等于空字符串 False1.3、与C++对比:
- C++ 标准原生基础标量只有四类:整型、浮点型、布尔型、空类型void;
- Python 的 str 是原生基础类型;C++ 无原生字符串基础类型,对应能力由标准库 std::string 提供(属于衍生类型)
- C++的整型包含 char、short、int、long、long long 及对应无符号版本,固定位宽、存在数值溢出;Python int 为无限精度对象,无溢出限制,二者语义相似但底层实现完全不同。
- C++ 提供 float、double、long double 三种精度浮点;Python 仅一种浮点,底层等价 C++ double,缺少单精度与扩展长浮点。
- C++布尔型和python类似,仅有真 / 假两个取值,但底层模型不同。Python bool 是 int 子类;C++ bool 为独立原生类型,标准未强制规定字节大小,主流编译器实现为 1 字节。
- C++的空类型 void和Python的空类型None 完全不互通、含义不同。void 无法创建变量,仅作函数返回、万能指针修饰;Python None 是可赋值的空对象。
二、衍生数据类型:以自带数据类型为底层基础,通过不同衍生方法(语法原生衍生、标准库衍生、自定义衍生等),生成的复合、拓展型数据结构,无法脱离基础原生类型独立存在。
2.1、在python中的定义:
2.1.1、语法原生衍生(内置容器,无需导入):
- 一共有四类分别是:list、tuple、dict、set
- 特点如下:
| 类型 | 定义 | 是否允许重复元素 | 是否有序 | 是否可变 | 是否支持混合类型元素 |
|---|---|---|---|---|---|
| list | 有序可变的序列容器,通过[]字面量或list()创建,支持索引、切片访问 | 允许,可存放完全相同的元素 | 是,严格按插入顺序保存,支持下标索引访问 | 是,创建后可随时增、删、改元素 | 支持,可同时存放任意不同类型的数据 |
| tuple | 有序不可变的序列容器,通过()字面量或tuple()创建,支持索引、切片访问 | 允许,可存放完全相同的元素 | 是,严格按插入顺序保存,支持下标索引访问 | 否,创建后无法增、删、改元素 | 支持,可同时存放任意不同类型的数据 |
| dict | 键值对映射型容器,通过{key:value}或dict()创建,通过键访问对应的值 | 键不允许重复,重复键会覆盖原值;值允许重复 | Python 3.7及以上版本按插入顺序有序,低版本无序 | 是,可随时增删改键值对 | 值支持任意类型;键必须是可哈希的不可变类型 |
| set | 无序不重复的集合容器,通过{}或set()创建,用于去重与集合运算 | 不允许,自动对元素去重,重复元素仅保留一份 | 否,内部无序存储,不支持下标索引访问 | 普通set可变,可增删元素;frozenset不可变 | 支持混合可哈希类型,元素必须为不可变的可哈希对象 |
2.1.2、标准库衍生(内置模块拓展,需 import 引入)
- Python 官方标准库针对特定场景封装的专用数据结构,在功能、性能上做了定向优化,底层仍完全基于基础类型实现。
- 代表类型:collections 系列(deque、OrderedDict、defaultdict、namedtuple)、array.array(同类型数值数组)、队列 queue、字节序列 bytes/bytearray 等
2.1.3、用户自定义衍生
- 开发者可自由组合基础类型与已有衍生类型,封装属性与方法,实现业务定制化的数据结构与行为逻辑,本质是对原生类型体系的进一步抽象封装。
- 例如:通过 class 关键字定义的自定义类与实例对象
2.2、具体案例:
# -*- coding: ANSI -*-# ========== 1. 列表 list ==========# 特性:支持混合类型、允许重复元素、有序、可变my_list=[1,"hello",3.14,1,"hello"]# 混合类型 + 重复元素my_list[0]=999# 可变:可修改元素print("列表:",my_list)# 列表: [999, 'hello', 3.14, 1, 'hello']print("列表有序,支持索引访问第2个元素:",my_list[1])# 列表有序,支持索引访问第2个元素: helloprint("-"*30)# ========== 2. 元组 tuple ==========# 特性:支持混合类型、允许重复元素、有序、不可变my_tuple=(1,"world",2.718,1,"world")# 混合类型 + 重复元素# my_tuple[0] = 999 # 不可变:取消注释运行会报错 TypeErrorprint("元组:",my_tuple)# 元组: (1, 'world', 2.718, 1, 'world')print("元组有序,支持索引访问第2个元素:",my_tuple[1])# 元组有序,支持索引访问第2个元素: worldprint("-"*30)# ========== 3. 集合 set ==========# 特性:元素需可哈希、自动去重、无序、可变my_set={1,"python",3.14,1,"python"}# 重复元素会被自动去重# print(my_set[0]) # 无序:不支持下标索引,取消注释运行会报错print("集合(自动去重):",my_set)# 集合(自动去重): {1, 3.14, 'python'}print("-"*30)# ========== 4. 字典 dict ==========# 特性:键唯一不可重复、值可混合类型、3.7+按插入顺序有序、可变my_dict={"name":"张三","age":25,"age":30}# 重复键会覆盖旧值print("字典:",my_dict)# 字典: {'name': '张三', 'age': 30}print("字典通过键访问值:",my_dict["name"])# 字典通过键访问值: 张三2.3、与C++对比:
2.3.1、C++语法原生衍生(纯语法构造,无需引入标准库)
- 一共有六类分别是:原生数组、指针、引用、结构体 struct、枚举 enum、联合体 union
- 和python的不同点在于:底层构造逻辑完全不同;
- python中原生衍生类,本身就是完整的功能对象,自带大量成员方法(如append、keys),容器内可混合存放任意类型的数据,元素类型无强制约束,长度动态可变,内存由解释器自动管理,本质是引用语义;
- C++ 原生语法的 struct 常用于数据聚合,默认成员公开(C++中Class默认成员私有),其他方面与 class 语义能力一致。
2.3.2、标准库衍生(STL 标准库提供,需包含对应头文件)
- C++ 标准模板库(STL)通过模板泛型机制封装的通用容器与工具类型;
- 代表类型:std::string、std::vector、std::map、std::unordered_map、std::set、std::deque、std::list、智能指针等
- 和python的不同点在于:两者都是通过内置模块或者内置标准库引入,python中是动态对象,C++实例化必须显示指定元素类型,还有就是内存管理模式不同。
2.3.3、用户自定义衍生
- 开发者可基于原生基础类型、语法衍生类型、标准库类型进行封装,自定义成员变量、成员函数与访问控制,实现面向对象的自定义数据结构与业务逻辑。
- 代表形式:自定义 class 类、模板类、继承派生类
- 和python的不同点在于:两者都是面向对象的实现模式,但具体实现方式不同。python是动态类型,C++是静态类型。C++中语义丰富,python中都是引用语义。
2.4、补充
2.4.1、语法和语义:语法就是编程语言规定的合法书写规则,语义是代码所表达的含义、执行时的行为规则,以及最终产生的效果。
- 最典型的例子就是赋值语句 a = b:
在 C++ 里,默认是「把 b 的值拷贝一份给 a」;
在 Python 里,是「让 a 和 b 指向同一个对象」;
写法语法几乎一致,但底层行为完全不同,这就是语义不同。 - 值语义: 变量直接存储数据本身,赋值、传参时会拷贝一份完整的新数据;两个变量相互独立,修改其中一个不会影响另一个。
- 引用语义:变量存储的是数据的地址 / 引用,赋值、传参时只拷贝地址,两个变量指向同一份真实数据;通过其中一个修改数据,另一个也会同步变化。
2.4.2、深拷贝和浅拷贝:两者都是针对包含嵌套子对象的复合对象(比如列表套列表、字典套列表)的复制行为,核心区别只在于:嵌套的内层对象有没有被一起独立复制。
- 浅拷贝(Shallow Copy)只复制对象的最外层结构,内层嵌套的子对象仍然共享同一份内存引用。修改内层数据,原对象和拷贝对象会同步变化。
- 深拷贝(Deep Copy):递归复制对象的所有层级,从外到内每一层子对象都会创建全新的独立副本。两边完全独立,修改任何一层都互不影响。
- Python 所有变量存的都是对象的引用(内存地址),复制一个容器(比如 list)时:默认的浅拷贝,只是把容器里的地址列表复制了一遍;所以修改内层子对象时,两边都会同步变化。Python 官方标准库 copy 模块提供了 deepcopy() 函数,专门做递归深拷贝。它会自动遍历对象的所有嵌套层级,遇到可变对象就创建新副本,最终得到一个完全独立的新对象。Python 深浅拷贝是运行时的通用行为,由标准库统一处理,不需要开发者自己手写拷贝逻辑。
- C++ 默认值语义下,普通对象拷贝会调用默认拷贝构造函数,本质是逐成员拷贝(类似浅拷贝);如果类内有指针成员指向堆内存,默认拷贝会出现双重释放问题,C++需要手动重写拷贝构造函数实现深拷贝。
三、数据类型特性:两种语言中造成数据类型和数据结构差异最本质的原因
3.1、在python中的定义:
- Python:动态强类型,Python 仅在数值体系内部(int/float/bool)做隐式提升,字符串与数字、列表与数字等跨类型运算会直接报错,拒绝隐式转换,因此属于强类型;
- Python 遵循万物皆对象,所有变量本质都是对象的引用,全程只有引用语义,没有原生的值语义。像 int、str 这些不可变类型,看起来 “改一个不影响另一个”,很像值语义,但本质还是引用语义,不是拷贝了值,而是对象本身不可修改,一旦 “修改” 就会生成一个全新的对象,变量重新指向新对象,原对象不受影响。
- Python 中动态类型 + 统一引用存储路线,天然兼容异构元素;
3.2、具体案例:
# 运行时确定类型:a=10print(type(a))# <class 'int'>,此时是整型a="hello"print(type(a))# <class 'str'>,运行中直接变成字符串a=[1,2,3]print(type(a))# <class 'list'>,又变成列表# 自动隐式类型转换:# int + float → 自动转floatres=5+2.5print(res,type(res))# 7.5 <class 'float'># bool本质是int子类,True=1、False=0,可直接和数字运算print(True+3)# 4print(False*10)# 0# python中只有引用语义:a=10b=a a=20# 不是修改原对象,是让 a 指向了新的 int 对象 20print(b)# b 还是指向原来的 10,所以不变3.3、与C++对比:
- C++:静态强类型,编译期固定类型,强制显式转换。
- C++:语义丰富,多套规则并存,C++ 之所以说语义丰富,是因为它同时支持多套不同的语义规则,开发者可以按需选择,不同语义对应不同的内存行为和性能表现。核心包含四类语义:
- 值语义:普通栈变量、结构体、类对象的默认行为,赋值 / 传参全量拷贝,数据独立。
- 引用语义(& 引用):给已有变量起别名,不拷贝数据,绑定后不能改指向,常用于函数传参避免拷贝。
- 指针语义:变量存内存地址,可空、可随时修改指向,支持指针运算,是 C++ 底层内存操作的核心。
- 移动语义(C++11 新增):通过 std::move 转移资源所有权,不拷贝数据,专门用于大对象高效传递。
- 除此之外还有左值、右值、右值引用等细分语义,对应不同的编译期规则和优化场景。
- C++ 中静态强类型 + 值语义连续存储路线,编译期必须确定元素类型与大小,因此不天然支持混合类型。
- 示例代码
#include<iostream>usingnamespacestd;intmain(){intnum=10;num="hello";// 编译直接报错,int不能存字符串string s="123";intx=4;interr=s+x;// 编译报错,string和int不能直接相加// 必须手动显式转换才能处理intnum1=stoi(s);intans=num1+x;cout<<ans<<endl;return0;}
编程学习
技术分享
实战经验