_数据类型和数据结构)
前言这个系列的文章以python为主会从编程语言的四类知识范畴去总结对比python和C。这部分文章共四篇分别是数据类型和数据结构、语法规则和执行流程、内存模型和运行机制、编程范式和语言特性这篇文章是从数据类型和数据结构的角度对比两者的不同。这部分总结是通过总分的架构实现的目的是展现两种编程语言的区别对比着学习理解他们之间的本质差异加深记忆。这个系列的每一篇文章后面会继续修改完善。python和C本质不同Python中万物皆对象所有数据、变量本质都是对象引用统一面向对象设计C兼顾原生值类型 对象类型分为两套独立体系并非一切都是对象。数据类型和数据结构将编程语言比喻成一个产品加工厂的话数据类型和数据结构就是这个工厂生成时需要的原材料。数据类型编程语言中对数据的分类定义规定了一类数据的取值范围、存储形式以及可进行的合法操作是构成程序数据的基础单元。数据结构数据的组织、存储与排列方式基于基础数据类型构建而成用于高效地管理、访问和操作批量数据核心是数据的布局逻辑与操作效率。摘要序号对比概念pythonC补充1自带数据类型√√×2衍生数据类型√√√3数据类型特性√√×概念对比一、自带数据类型语言内核 / 编译器底层硬编码实现、无需引入任何库、无需自定义。声明后可直接使用的基础数据类型是语言最底层的基础存储单元。1.1、在python中的定义python自带数据类型一共五类int、float、bool、str、Noneint内置基础类型无限精度整数不分长短整型自动适配数值大小二进制/八进制/十六进制均可表示。float内置基础类型64位双精度浮点数存在浮点精度误差支持科学计数法。bool内置基础类型int子类仅True、False两个取值True等价1False等价0。str内置序列类型不可变字符序列单/双/三引号定义支持切片。不可变不能增删改仅可查询。None内置基础类型唯一值None表示空对象区别0、空字符串。1.2、具体案例# -*- coding: utf-8 -*-# Python五大自带基础数据类型演示num_int9999999999999999999999999999# int 无限大整数num_float3.14e-2# float 科学计数浮点数flag_boolTrue# bool布尔值text_strhello python# str字符串empty_noneNone# None空对象# 打印值与对应类型print(num_int,type(num_int))# 9999999999999999999999999999 class intprint(num_float,type(num_float))# 0.0314 class floatprint(flag_bool,type(flag_bool))# True class boolprint(text_str,type(text_str))# hello python class strprint(empty_none,type(empty_none))# None class NoneType# 补充特性演示print(True5)# bool是int子类True等价1 6print(text_str[0:3])# str切片读取不可修改 helprint(None0)# None不等于数字0 Falseprint(None)# None不等于空字符串 False1.3、与C对比C 标准原生基础标量只有四类整型、浮点型、布尔型、空类型voidPython 的 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、具体案例# 运行时确定类型a10print(type(a))# class int此时是整型ahelloprint(type(a))# class str运行中直接变成字符串a[1,2,3]print(type(a))# class list又变成列表# 自动隐式类型转换# int float → 自动转floatres52.5print(res,type(res))# 7.5 class float# bool本质是int子类True1、False0可直接和数字运算print(True3)# 4print(False*10)# 0# python中只有引用语义a10ba a20# 不是修改原对象是让 a 指向了新的 int 对象 20print(b)# b 还是指向原来的 10所以不变3.3、与C对比C静态强类型编译期固定类型强制显式转换。C语义丰富多套规则并存C 之所以说语义丰富是因为它同时支持多套不同的语义规则开发者可以按需选择不同语义对应不同的内存行为和性能表现。核心包含四类语义值语义普通栈变量、结构体、类对象的默认行为赋值 / 传参全量拷贝数据独立。引用语义 引用给已有变量起别名不拷贝数据绑定后不能改指向常用于函数传参避免拷贝。指针语义变量存内存地址可空、可随时修改指向支持指针运算是 C 底层内存操作的核心。移动语义C11 新增通过 std::move 转移资源所有权不拷贝数据专门用于大对象高效传递。除此之外还有左值、右值、右值引用等细分语义对应不同的编译期规则和优化场景。C 中静态强类型 值语义连续存储路线编译期必须确定元素类型与大小因此不天然支持混合类型。示例代码#includeiostreamusingnamespacestd;intmain(){intnum10;numhello;// 编译直接报错int不能存字符串string s123;intx4;interrsx;// 编译报错string和int不能直接相加// 必须手动显式转换才能处理intnum1stoi(s);intansnum1x;coutansendl;return0;}