尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Python非数字型数据类型详解:字符串、列表、元组、字典与集合

发布时间:2026/9/29 17:51:39

资讯中心
01
ARTICLE

Python非数字型数据类型详解:字符串、列表、元组、字典与集合

Python非数字型数据类型详解:字符串、列表、元组、字典与集合
1. 先搞清楚为什么Python的数据类型要分成“数字”和“非数字”两拨我教过不少零基础的朋友学Python发现一个规律大部分人第一遍学数据类型都是死记硬背“字符串是str、列表是list、字典是dict”背完就忘根本不知道怎么串起来用。所以我写这份笔记的时候决定换一个切法——先按“能不能直接做算术”把所有数据类型分成两拨。数字型就是那三个老熟人int整数、float浮点数、complex复数它们天生就是拿来算数的可以直接加减乘除。剩下的全是非数字型字符串str、列表list、元组tuple、字典dict、集合set还有那个身份特殊的布尔型bool都归在这一拨。注意这个分法不是Python官方的分类官方文档更习惯按“可变与不可变”“序列与映射”来区分但对初学者来说“能不能直接算”这个判断标准特别直观——你拿到一个数据第一反应就是想知道能对它做什么而“能否参与数学运算”就是最基础的那个分水岭。不过这里有个小尴尬布尔型bool看起来是个开关可它其实是int的子类True和1在Python里几乎是同一个东西True 1会得到2。所以严谨地说布尔值也能“算”但我们还是习惯把它当成非数字类型来学习后面讲到字典和集合的哈希规则时这个“True等于1”的设定还会再坑你一次到时候我们再细说。为了让你对这几兄弟先有个整体印象我把它们的核心差异放在一张表里类型是否可变是否有序元素能否重复存储内容str 字符串不可变有序允许只能存字符list 列表可变有序允许任意类型tuple 元组不可变有序允许任意类型dict 字典可变有序Python 3.7键唯一、值可重复键值对set 集合可变无序元素唯一任意不可变类型后面每一节都会反复用到这张表里的概念。尤其是“可变”和“不可变”这两个词我劝你第一次看到就要刻在脑子里。Python的数据类型分类方式有好几套但“可变性”才是真正决定你代码行为的那把钥匙后面所有坑几乎都从这两个字里长出来。2. 字符串不可变的“字符墙”修改一次等于重建一次2.1 定义方式与基本操作字符串是大家最早接触的非数字类型任何用引号包起来的内容都是它。单引号hello、双引号hello完全等价三引号hello和hello一般用来写多行文本或文档注释。需要注意的一点是字符串里面如果要嵌套引号最好外双内单或者外单内双省得写一堆转义符。比如要表达s 他说今天学Python就不会因为引号冲突而报错。要是非要用同一种引号包同一种引号那只能借助\转义代码可读性会差很多。字符串的索引和切片是基本功中的基本功。索引从0开始负索引从-1开始从右往左数。切片遵循“包头不包尾”原则s python编程笔记 print(s[0]) # p print(s[-1]) # 记 print(s[0:6]) # python print(s[::2]) # pto编笔 —— 步长为2隔一个取一个 print(s[::-1]) # 记笔程编nohtyp —— 反向这是倒序字符串的经典写法这里多提一句字符串切片永远是生成新字符串原字符串一丝一毫都不动。明白了这个你就能理解为什么在循环里反复做result s[i]这种操作会那么慢——每次拼接都是造了一个全新的字符串对象循环一万次就造一万个临时的“半成品”内存和时间的开销全浪费在“重建”上了。2.2 常用方法里最该先练熟的是这五个字符串自带的方法非常多查文档能查到几十个但日常开发里来来去去就那几个。我的建议是先练熟这五个strip()去空白、split()分割、join()连接、replace()替换、find()查找。s hello, python world print(s.strip()) # hello, python world 去掉两端空白 print(s.split(,)) # [ hello, python world ] 按逗号切 print(s.replace(python, GO)) # hello, GO world print(s.find(python)) # 9 找不到则返回 -1split()返回的是列表join()正好相反是把列表合成字符串。注意join()的调用方式是“分隔符.join(列表)”不是“列表.join(分隔符)”这个语法顺序我见过无数新手写反写反了就直接AttributeError。比如words [Python, 笔记, 非数字型] print(-.join(words)) # Python-笔记-非数字型另外判断类方法isdigit()、isalpha()、isalnum()在处理用户输入时特别好用比如判断一个字符串是不是纯数字就能决定下一步是转成int还是提示用户重新输入。2.3 格式化输出与内存不可变Python的格式化方式经历了三代老派的%格式化、str.format()以及现在最推荐的f-string。f-string是Python 3.6引入的写法是在字符串前加f然后用花括号直接引用变量和表达式name Python version 3.11 print(f我正在学{name}版本是{version}学完能写{2 * 50}行代码)性能上f-string也是三者里最优的因为它是编译期就确定的格式运行时不额外解析。日常写代码认准这一种就够用了。最后说回不可变性。字符串在内存里是“字符墙”一样的存在你看着像改了某个字符其实Python是重新砌了一面墙再让变量指向新墙。所以下面这种写法是错的s hello s[0] H # TypeError: str object does not support item assignment正确做法是s H s[1:]或者干脆s.replace(h, H)。理解不可变性的真正价值是在学元组和字典时会省很多力气——不可变类型可以被哈希、可以做字典的键、可以放进集合可变类型统统不行。这个逻辑链条建议你在学这一节的时候就搭起来。3. 列表最灵活的“容器”但两头都有坑3.1 增删改查的“正确姿势”列表是Python里使用频率最高的容器类型几乎任何批量数据都优先考虑用列表装。它和C语言数组最大的区别是不要求元素类型一致可以同时装整数、字符串、甚至是另一个列表。比如[1, a, [2, 3], {k: 1}]是完全合法的。增删改查四类操作的常用方法我列个清单增append()末尾添加一个元素extend()末尾批量添加insert(位置, 元素)指定位置插入。删remove(值)删除第一个匹配项pop(索引)按位置取出并删除del 列表[索引]删除指定位置clear()清空。改直接列表[索引] 新值切片也能整体替换列表[1:3] [x, y, z]。查元素 in 列表判断存在列表.index(值)查索引.count(值)统计次数。一段示例代码把常用操作串起来nums [3, 1, 4, 1, 5, 9, 2] nums.append(6) # [3, 1, 4, 1, 5, 9, 2, 6] nums.sort() # [1, 1, 2, 3, 4, 5, 6, 9] 原地排序 nums.reverse() # [9, 6, 5, 4, 3, 2, 1, 1] 原地反转 print(sorted(nums, reverseTrue)) # sorted() 返回新列表且不影响原列表 print(2 in nums) # True初学者最容易混淆的是sort()和sorted()的差别。简单记sort()是“就地”修改原列表变了sorted()是“新造”一份排序后的列表原列表不动。类似的一对还有reverse()和reversed()不过reversed()返回的是迭代器想拿到列表还得再list()包一层。3.2 切片能赋值这是列表和字符串最大的行为差异字符串的切片只能取数据不能改数据但列表的切片是个“左膀右臂”既用来读取也能用来批量修改甚至能插入和删除。a [1, 2, 3, 4, 5] a[1:3] [20, 30] # a 变成 [1, 20, 30, 4, 5] a[1:4] [7] # 用3个位置换1个位置a 变成 [1, 7, 5] a[0:0] [0, 0] # 头部插入a 变成 [0, 0, 1, 7, 5] a[2:] [] # 相当于删除索引2及以后的所有元素很多人不知道切片还能用来快速复制列表b a[:]。这里要注意[:]是浅拷贝它确实创建了一个“新”列表但如果列表里的元素本身是可变对象比如子列表那新旧列表共享的其实是同一批子列表。这个话题马上就会讲。3.3 三个和“可变性”有关的经典翻车现场第一个经典坑函数默认参数。看这段代码def add_item(item, lst[]): lst.append(item) return lst print(add_item(1)) # [1] print(add_item(2)) # [1, 2] - 怎么回事问题就出在lst[]这个默认值上。Python的默认参数只在函数定义时创建一次之后每次调用如果不传lst用的永远是同一个列表对象。正确写法是def add_item(item, lstNone): lst [] if lst is None else lst。这个坑是面试常客背后考的就是“默认可变对象”这个知识点。第二个经典坑循环中删除元素。很多人想当然写nums [1, 2, 3, 4, 5] for n in nums: if n % 2 0: nums.remove(n) print(nums) # 想删偶数是 [1, 3, 5]实际得到 [1, 3, 4, 5]原因很简单遍历时用下标一个个往前挪删掉一个元素后后面的元素会补上来导致部分元素被“跳过”。最稳的办法是“倒着删”或者直接用列表推导式重建新列表nums [n for n in nums if n % 2 ! 0] # 这才是正经写法第三个经典坑浅浅的“拷贝”。b a不是拷贝只是给同一个列表起了别名改b等于改a。要真正创建新列表用a[:]、list(a)或a.copy()但这些都是浅拷贝如果列表里嵌了子列表子列表依然是共享的。遇到嵌套列表需要彻底独立的话得动用copy.deepcopy()import copy a [[1, 2], [3, 4]] b copy.deepcopy(a) b[0][0] 99 print(a) # [[1, 2], [3, 4]] a 完全不受影响这三个坑都指向同一个底层逻辑列表是可变对象对象的内容改没改、对象换没换必须分清楚。平时写代码多留个心眼就能少调试半天。4. 元组说好的“不可变”为什么还能出幺蛾子4.1 一个决定命运的逗号元组的定义方式最容易被忽略的一个细节是单个元素的元组必须有那个逗号。(1)就是整数1而(1,)才是元组。甚至不写小括号1, 2, 3也是元组。我见过有人在这里栽跟头排查半天才发现自己创建的根本不是元组。元组的两大特点是“有序”和“不可变”。不可变指的是你不能往元组里添加元素不能删除元素也不能替换已有的元素。它没有append()、没有remove()方法只有count()和index()两个清清爽爽。那不可变有什么用最大的用处是“保护数据”。比如一个函数的返回值设计成元组调用方就只能读取、不能篡改这在团队协作时能让接口契约非常明确。另一个用处是“可哈希”这句话翻译过来就是元组可以被当作字典的键、可以被放进集合。列表干不了的事元组能干。4.2 拆包Python里少有的零成本炫技元组拆包是我非常喜欢的特性。既然元组的长度是固定的那就可以直接把它拆开赋值给多个变量point (10, 20) x, y point print(x, y) # 10 20 # 交换两个变量一行搞定 a, b 1, 2 a, b b, a print(a, b) # 2 1第二种写法背后也是“打包成元组再拆包”的过程。这个技巧看起来简单但真能帮你少写三四行临时变量。还可以用*rest收集多余的元素first, *middle, last (1, 2, 3, 4, 5) print(first, middle, last) # 1 [2, 3, 4] 54.3 说好的不可变为什么总有人翻车先看这段代码t ([1, 2], 3) t[0].append(99) print(t) # ([1, 2, 99], 3) 这看起来太矛盾了——说好的元组不可变呢其实元组里存的不是“数据”本身而是“引用”。t[0]指向的是一个列表对象元组保证的是你不能把t[0]改指向别的对象但完全没有阻止那个列表对象修改自己。就好比你说“这本书的内容不能换”但书里夹的一张纸上你可以随便写字。所以更严谨的说法是元组只保证“引用的不可变”不保证“引用对象的不可变”。当元组里的元素是列表、字典这类可变对象时它们本身照样可以增删改。这个特性在你想把“一组可变化的数据”打包成一个整体、但又不能换掉整体时反而还挺好用。元组的进阶玩法是namedtuple它让元组像字典一样可以通过属性名访问字段from collections import namedtuple Point namedtuple(Point, [x, y]) p Point(10, 20) print(p.x, p.y) # 10 20这段代码在数据量小、想要“轻量级对象”的场景下很受用比定义一个完整的类省事得多。5. 字典和集合哈希表两兄弟为什么查询快到离谱5.1 字典的键值对世界字典是Python里用“键”查“值”的结构写法是花括号加冒号{name: Python, version: 3.11}。它在内存里的组织方式是哈希表所以查找一个键的时间复杂度接近O(1)。通俗地讲列表查值是从第一个元素一个个翻过去字典查值则是根据键直接算出存储位置类似于查字典时直接按拼音翻到那一页而不是从第一页开始逐页找。字典的基本操作围绕四个字增删改查。d {name: Python} d[age] 30 # 增键不存在就是添加 d[age] 31 # 改键已存在就是更新 print(d.get(name, 未知)) # 查用 get 比 d[name] 安全键不存在返回默认值而不是报错 d.setdefault(level, 初级) # 查改如果键不存在才设置默认值存在则不动 d.pop(age) # 删弹出并删除指定键遍历字典时通常用.items()同时取键和值for k, v in d.items(): print(k, v)这里有个迭代的小细节我每次都要提醒直接for k in d遍历出来的是键而不是值这是Python初学阶段最容易搞混的行为之一。另外Python 3.7之后字典保持插入顺序也就是说你遍历时看到的顺序就是元素加进去的顺序这在以前是不可靠的。5.2 集合去重只是入门交并差才是精髓集合set长得像没有值的字典{1, 2, 3}。它的底层也是哈希表所以自带两个硬性规则元素唯一、元素必须可哈希也就是必须为不可变类型。去重是最直观的用法nums [1, 2, 2, 3, 3, 3] unique_nums list(set(nums)) print(unique_nums) # [1, 2, 3]但集合真正强大的地方是集合运算。求两个列表的交集、并集、差集用集合一行搞定a {1, 2, 3, 4} b {3, 4, 5, 6} print(a b) # {3, 4} 交集 print(a | b) # {1, 2, 3, 4, 5, 6} 并集 print(a - b) # {1, 2} 差集在a但不在b print(a ^ b) # {1, 2, 5, 6} 对称差集只在一个集合里的实际开发里这个能力特别好用。比如你抓了两批数据想找出哪些是两批共有的不用写二重循环一个就完了而且速度飞快。换成列表做同样的事得写两层嵌套循环数据量一上来性能差距立马显现。5.3 哈希表体制下的两个“隐形天敌”第一个True和1在字典里居然是同一个键。因为1 True成立它们的哈希值也一样所以在字典里d[True]和d[1]操作的是同一个位置。请看d {} d[True] yes d[1] no print(d) # {True: no} 只有一个键这种反直觉行为本质上是Python把True当成整数1的子类造成的。写业务代码时如果键同时出现布尔值和数值很容易出这种“看似改了多个键其实只留一个”的诡异问题。第二个列表不能当字典的键但元组可以。元组能当键的前提是“元组里所有元素也都不可哈希”。所以{(1, 2): ok}没问题{([1, 2]): no}直接报unhashable type: list。说到底哈希值的计算依赖内容不变内容会变的容器去计算哈希算出位置后内容再一改就再也找不回来了。这套逻辑理解了你不仅懂了字典键的要求也顺便懂了为什么字符串、数字这些最朴素的类型反而是最可靠的键。6. 它们之间的转换一张表搞懂外加三个连环坑6.1 转换速查表与示例非数字类型之间互相转换是刷题和写脚本时的高频操作。我整理了一张速查表建议收藏目标类型写法结果说明list(字符串)list(abc)[a, b, c]按字符拆list(元组)list((1,2,3))[1, 2, 3]list(集合)list({1,2,3})[1, 2, 3]顺序不保证list(字典)list({a:1,b:2})[a, b]只取键tuple(列表)tuple([1,2])(1, 2)set(列表)set([1,1,2]){1, 2}顺带去重str(列表)str([1,2])[1, 2]注意这不是想要的结果列表转字符串.join(可迭代)元素必须全是字符串代码演示一些常见用法s python print(list(s)) # [p,y,t,h,o,n] print(s.split()) # [python] 和 list(s) 完全不同 pairs [(name, Python), (age, 30)] d dict(pairs) print(d) # {name: Python, age: 30} keys [a, b] values [1, 2] print(dict(zip(keys, values))) # {a: 1, b: 2}6.2 连环坑一list(s)和s.split()千万别混list(hello)得到的是[h,e,l,l,o]按字符拆hello world.split()得到的是[hello,world]按空白拆。一个是把字符串“拆成最小单元”一个是把字符串“切成若干段”。拿1,2,3举例list()会得到[1,,,2,,,3]这种鬼样子而.split(,)得到[1,2,3]这才是大多数情况下你真正想要的。6.3 连环坑二.join()对非字符串元素直接报错.join([Python, 笔记])没问题但.join([1, 2, 3])会抛TypeError。因为join()要求可迭代对象里的每个元素都必须是字符串。想把数字列表拼成字符串先得把元素全部转成str最优雅的写法是nums [1, 2, 3] print(, .join(map(str, nums))) # 1, 2, 36.4 连环坑三字典转列表得到的不是键值对list({a: 1, b: 2})只会得到[a, b]键值对悄无声息地丢了。如果你想把“键值对”转出来要用.items()d {a: 1, b: 2} print(list(d.items())) # [(a, 1), (b, 2)]如果想把键值对反过来、以值作为索引可以用推导式reversed_d {v: k for k, v in d.items()} print(reversed_d) # {1: a, 2: b}6.5 综合案例统计一段文本中每个字符的出现次数把这一章的知识串起来最好的方式是做一个“字符频次统计”的小脚本。需求很简单给定一个字符串统计每个字符出现次数并用字典输出。def count_chars(text): result {} for ch in text: result[ch] result.get(ch, 0) 1 return result print(count_chars(hello python)) # {h: 1, e: 1, l: 2, o: 2, : 1, p: 1, y: 1, t: 1, n: 1}里面用到了字符串的可迭代特性直接遍历字符、字典的get()查值技巧、以及“键不存在就给默认值再加1”的累加模式。如果你想输出“出现次数最高的前三位”可以先把字典的.items()转成列表再按值排序top3 sorted(count_chars(hello python).items(), keylambda x: x[1], reverseTrue)[:3] print(top3) # [(l, 2), (o, 2), (h, 1)] 这类的结果这样一来字符串、列表、字典、元组.items()返回的就是视图转成列表后就是元组元素全在这一段小代码里碰了个面。你学到的不是一个个孤立的知识点而是一套可以自由组合的工具箱。最后再分享一个我平时带新人时的习惯学完数据类型别急着往下赶进度找一篇英文短文用今天这套技巧写个词频统计。当你亲手把“非数字型”这几个类型在一个小工具里来回倒腾、互相转换之后这些知识才算真正长在你身上了。这个阶段踩过的每一处混乱都会成为你后面写复杂逻辑时的免疫力。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。