Python容器详解:列表、元组、字典与集合从入门到实战

发布时间:2026/9/15 6:11:36

Python容器详解:列表、元组、字典与集合从入门到实战 我先说个场景零基础学Python最容易卡住的地方不是if不是for而是突然听到“容器”这个词。其实你完全不用把它想得多高深。生活里你用收纳盒装衣服、用抽屉装杂物Python里的list、tuple、dict、set就是编程世界里那几种不同结构的收纳盒。第四章把这几样东西吃透后面写循环、写函数、写爬虫脚本手感和之前完全是两个层次。如果你还没把Python环境装好也别急着往后看。先去官网下一个安装包装的时候勾选“Add Python to PATH”然后在VS Code里装好Python插件新建一个.py文件跑通print(hello)全程大概十分钟。下面所有代码你都照着敲一遍最好再自己改动几个参数看结果这比光读文章有用得多。1. 容器是什么为什么非学不可1.1 从变量到容器的思维转变变量只能存一个值比如name 小明、age 18。但真实场景哪有这么简单你手里有三门课的成绩你得存三个变量你有全班五十个人的名字难道写五十个变量这显然不现实。容器的价值就在于用单个变量名就能把一堆数据装进去然后通过索引、循环、方法去批量处理。很多教材把容器叫“数据结构”把零基础的读者直接吓跑。我讲课的时候更喜欢叫它“数据盒子”。你只要先记住一个结论凡是碰到“一个东西的多个数据”第一反应就应该是容器而不是拼命声明变量。比如要统计一篇文章里哪些字出现次数最多你得先把所有字符装进一个结构里再逐一遍历统计。没有容器这一步根本没法做。刚入门不需要背概念需要建立的是“能用容器装数据”的直觉。你每写一段代码前先问自己一句话我手上是单个数据还是多个数据多个数据核心思路就是用容器把它们组织起来。这个思维一转变你就从“只能处理一个数”进入了“可以处理一批数”的阶段。1.2 Python内置的四大容器类型Python自带四种最核心的容器我习惯用一张表先让学员建立整体印象类型名称是否有序是否可修改是否允许重复典型场景list列表有序可修改允许序列数据、待处理任务tuple元组有序不可修改允许固定配置、坐标、返回值dict字典有序3.7可修改键不允许重复键值映射、配置项set集合无序可修改不允许重复去重、集合运算这四种就是Python容器的主力军。列表像一条排队的长龙每个位置都有编号元组像一条被焊死的铁轨不能随便改动字典像一本通讯录靠“姓名”直接翻到“电话”集合像一个大麻袋往里丢东西时自动把重复的抖掉。还有一个容易忽略的重点从Python 3.7开始字典会保持键的插入顺序。3.6之前的字典是无序的很多老教程还在强调“字典无序”如果你的Python版本是3.8以上完全可以依赖插入顺序来遍历。集合则始终无序哪怕你打印时看到好像有顺序那也只是哈希分布的结果千万别依赖它。2. 列表最常用的有序容器2.1 列表的增删改查列表用方括号定义元素之间用逗号隔开scores [89, 92, 77, 85] names [张三, 李四, 王五] mixed [1, hello, 3.14, True]列表可以装任意类型甚至可以嵌套比如[[1, 2], [3, 4]]。但我建议新手尽量让一个列表里的元素保持同类型否则后续处理容易出幺蛾子。查某个元素直接用下标下标从0开始scores[0]是89scores[-1]是85负号表示从尾部往前数这是Python非常舒服的一个设计。增删改查是列表的基础操作我直接给你一套最快上手的动作scores [89, 92, 77, 85] # 增 scores.append(60) # 尾部追加最常用 scores.insert(1, 100) # 在索引1处插入 scores.extend([70, 80]) # 把另一个列表的元素逐个追加 # 删 scores.remove(77) # 按值删除删第一个匹配项 popped scores.pop() # 弹出尾部元素也可以pop(索引) del scores[0] # 按下标删除 # 改 scores[1] 99 # 直接覆盖 # 查 index scores.index(85) # 找值对应的下标 count scores.count(85) # 统计值出现次数这里有个新手特别爱犯的错用append往里加一个列表结果变成嵌套列表而不是拼接。比如result.append([1, 2])得到的是[[1, 2]]而不是[1, 2]。想合并两个列表用extend或者运算符。另外remove删除的是第一个匹配值如果列表里有多个相同值只删一个值不存在会直接抛ValueError所以删除前最好先判断一下。2.2 切片和遍历切片是列表的精髓语法是list[start:stop:step]左闭右开意思是包含start位置不包含stop位置。这个规则刚接触会觉得反直觉但你只要记住“取头不取尾”配合几个例子几分钟就适应nums [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] nums[:3] # [0, 1, 2]从头取到索引2 nums[3:] # [3, 4, 5, 6, 7, 8, 9]从索引3取到末尾 nums[::2] # [0, 2, 4, 6, 8]每隔一个取一个 nums[::-1] # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]反转列表第三行和第四行是高频操作尤其是[::-1]反转实测下来比单独写循环方便太多。切片还有个隐藏技能它返回的是一个新列表所以你可以用切片快速复制一层列表比如copy_nums nums[:]这比直接用b a安全得多因为b a只是让两个变量指向同一个列表改一个另一个也跟着变。遍历列表时如果只关心元素值直接for item in my_list即可如果既想要下标又想要值用enumeratefor idx, value in enumerate(scores): print(idx, value)enumerate还能指定起始值比如scores是学号索引你想让编号从1开始显示就写enumerate(scores, start1)。2.3 列表推导式入门最香的语法糖列表推导式是Python非常受欢迎的一个特性它能把“创建一个新列表”的循环压缩成一行。先看传统写法squares [] for n in range(10): squares.append(n * n)用推导式三行变一行squares [n * n for n in range(10)]再叠加一个if条件even_squares [n * n for n in range(10) if n % 2 0]完整拆解一下这个语法最外层是方括号里面先写“要生成什么”再写“从哪循环”最后写“过滤条件”。顺序是[表达式 for 变量 in 可迭代对象 if 条件]这个顺序千万别搞反新手最容易把for和if的位置写颠倒。列表推导式用好了效率极高它不仅短运行速度通常也比手动append快。我拍板建议凡是“遍历一个列表生成另一个新列表”的场景优先考虑推导式。但有一个度别套太多层比如[[x * y for x in range(3)] for y in range(3)]还可以接受三层以上嵌套推导式可读性断崖式下降别人维护代码时会想骂人。3. 元组那个“不能改”的兄弟3.1 怎么创建元组注意这几个坑元组用圆括号定义但真正标识元组的其实不是括号而是逗号point (3, 5) point2 3, 5 # 这样也是元组 single (1) # 这是整数1不是元组 single_tuple (1,) # 这才是单元素元组那个单元素元组的逗号是新手极其容易踩的坑。你写data (10)以为拿到元组实际上Python直接把它当成整数10后续一调用元组方法立刻AttributeError。记住口诀括号不是重点逗号才是。元组不可修改指的是它不能添加、删除、替换元素。这一点我觉得特别适合用来放那些“不应该变”的数据。比如一个点的x、y坐标一旦确定了就不希望被后面代码误改再比如函数返回多个结果时本质返回的就是一个元组def get_user(): name 张三 age 18 return name, age # 返回的是元组 ret get_user() print(ret[0]) # 张三另一个容易被忽略的地方元组如果内部放了可变对象那份可变对象本身还是能被修改的。比如t (1, [2, 3])你没法把t[1]换成别的东西但可以t[1].append(4)元组内容就变成了(1, [2, 3, 4])。很多教程管这叫“元组里的可变元素陷阱”面试题常考理解一句话就行元组保证的是“引用不变”不是“引用指向的对象不变”。3.2 解包与星号表达式元组最顺手的功能是解包。一对一的场景point (3, 5) x, y point print(x, y) # 3 5这个特性在交换变量时极其好用。其他语言换个变量值得开一个临时变量Python直接这样a, b 10, 20 a, b b, a print(a, b) # 20 10星号表达式可以处理数量不定的解包这种场景处理数据列表时非常实用first, *rest [100, 200, 300, 400] print(first) # 100 print(rest) # [200, 300, 400]再比如只要头尾不要中间head, *mid, tail [1, 2, 3, 4, 5]变量mid会自动变成一个列表收集中间剩余的所有元素。解包不仅限于元组列表、字符串也都支持因为只要它是可迭代对象就可以。配合函数参数就变成了*args可变参数这是函数章节的内容但你提前理解了星号收集剩余元素后面学函数会顺很多。4. 字典键值对查找是性价比之王4.1 字典的创建与常用方法字典用的是键值对(key-value)结构和列表最大的区别是列表靠下标找值字典靠键找值。创建字典有几种方式person {name: 张三, age: 18} # 用 dict() 传关键字参数 person2 dict(name李四, age20) # 用 zip 把两个列表组合成字典 keys [name, age] values [王五, 25] person3 dict(zip(keys, values))第三种方式在数据处理里特别常用两个列表天然就有关联关系zip一拼就是一个字典。查字典里某个值最直观的是person[name]但键不存在时会直接抛KeyError。想安全一点用get方法age person.get(age, 0) # 键不存在时返回默认值0 phone person.get(phone, 未填写)get是字典里我使用频率最高的方法写脚本处理外部数据时你永远不能假设数据里每个键都存在。举个例子解析接口返回的JSON时某个字段可能缺失用get(key, default)能避免一长串try/except。新增和修改的语法是一样的person[address] 北京 # 键不存在就是新增 person[age] 19 # 键已存在就是修改删除用的是pop(key)它会返回被删除的值。还有popitem()会删除并返回最后一个键值对适合需要按插入顺序倒序处理的场景。4.2 三种遍历方式很多新手刚接触字典时会困惑我知道怎么取单个值但怎么把整个字典过一遍其实字典遍历有三种常见姿势对应三个方法person {name: 张三, age: 18, city: 北京} # 1. 只遍历键 for key in person: print(key) # 2. 遍历键值对 for key, value in person.items(): print(key, value) # 3. 只遍历值 for value in person.values(): print(value)for key in person和for key in person.keys()等价直接遍历字典时拿到的就是键。需要同时用键和值时一定要用items()它返回一个键值对的视图每次迭代时解包成两个变量代码是最清晰、效率也最高的方式。这里提醒一个坑在遍历字典时如果同时修改字典的键增加或删除会直接报错RuntimeError: dictionary changed size during iteration。解决办法通常是把要删除的键先收集成一个列表遍历完列表再逐个删除或者直接创建一个新字典来过滤。4.3 默认值处理与字典合并“统计频率”是字典最经典的用法。统计一串字符里每个字母出现多少次新手通常这样写word_count {} for char in helloworld: if char in word_count: word_count[char] 1 else: word_count[char] 1逻辑没问题但每次都要判断键是否存在太啰嗦用setdefault一行搞定for char in helloworld: word_count[char] word_count.setdefault(char, 0) 1setdefault(key, default)的逻辑是键存在就返回原值键不存在就先把默认值写入再返回默认值。配合加1赋值就把“有则加一无则创建为1”压缩成一行了。还有更优雅的方案是collections.defaultdict它能在键不存在时自动创建默认值from collections import defaultdict word_count defaultdict(int) for char in helloworld: word_count[char] 1defaultdict(int)会为每个新键自动调用int()生成0于是你只管加1就行。这个方式我强烈推荐可读性比setdefault还顺。字典合并也有讲究。Python 3.9以上可以直接用|运算符d1 {a: 1, b: 2} d2 {b: 3, c: 4} merged d1 | d2 # {a: 1, b: 3, c: 4}3.8及以下版本用update方法或{**d1, **d2}。注意合并时如果键冲突右侧字典的值会覆盖左侧的值。key冲突时“后到的胜出”这个规则在任何合并方式里都一样。5. 集合去重与关系运算两把抓5.1 去重与增删集合定义用花括号但和字典的区别是集合没有冒号元素直接展开。空集合不能写{}因为那是空字典得用set()s {1, 2, 3} empty set()集合最大的特性是元素不重复。去重是它实践价值最高的场景一行代码解决nums [1, 2, 2, 3, 3, 3, 4] unique_nums list(set(nums)) print(unique_nums) # [1, 2, 3, 4]这个操作在数据处理里太常用了。比如你从两份名单里收集到一批用户ID里面可能有重复直接set一下重复的自动就没了。但去重时要注意集合是无序的去重后的结果不保证保持原顺序。如果你既要去重又要保持原来的相对顺序就得换一种写法seen set() result [] for num in nums: if num not in seen: seen.add(num) result.append(num)这段代码的原理是集合的in判断速度远快于列表的in判断因为集合底层是哈希表查找时间是O(1)列表需要逐个比较是O(n)。数据量小还不明显列表里有几万条数据时性能差距就出来了。集合的增删方法注意和列表、字典的区别s {1, 2, 3} s.add(4) # 添加元素已存在则不生效 s.remove(4) # 删除元素不存在则抛KeyError s.discard(5) # 删除元素不存在也不报错推荐 popped s.pop() # 弹出任意元素因为无序别指望“最后一个” s.clear() # 清空集合5.2 集合运算交集并集差集集合操作往往比手工循环高效得多。很多时候你会发现原本要写好几层循环的判断用集合运算一行就结束了。比如你有A班学生和B班学生想知道两个班都报过哪些课这是典型的交集场景java_course {张三, 李四, 王五} python_course {李四, 王五, 赵六} # 交集两门课都报的人 both java_course python_course # {李四, 王五} # 并集报名了任意一门课的人 all_students java_course | python_course # 差集只报了Java没报Python的人 only_java java_course - python_course # 对称差集只报了一门的人 one_course java_course ^ python_course运算符版本写起来很短但可读性略低也可以用方法版本intersection()、union()、difference()、symmetric_difference()。两种写法我建议都记住看别人代码时两种风格都很常见。集合还能做包含关系判断a {1, 2} b {1, 2, 3, 4} a b # Truea是b的子集 b a # Trueb是a的超集 {1, 5}.isdisjoint({2, 3}) # True两个集合没有交集这些运算在权限系统、标签筛选、历史记录对比这些场景里都是主力。5.3 frozenset 与可哈希问题集合里的元素必须是可哈希的说白了就是“不可变类型”才能进集合。数字、字符串、元组可以进集合列表、字典、集合本身都不行因为集合内部靠哈希值定位元素元素一变哈希位置就乱了。想验证一下执行{[1, 2]}立刻报TypeError: unhashable type: list。这就引出一个工具frozenset它是不可变集合。普通集合没法放进另一个集合作元素但frozenset可以s1 frozenset([1, 2, 3]) s2 frozenset([4, 5]) s {s1, s2} # 正常frozenset还能当字典的键使用。比如你要对多个集合分组统计每个集合作为字典的键这时候就得用frozenset因为普通set不可哈希。这个知识点平时用得少但在算法题、复杂数据处理里是个利器面试时能答上来也是加分项。6. 容器互转与类型转换6.1 常用互转对照表容器的真正威力在于它们之间可以灵活转换这也是Python类型转换里非常核心的一块。最常见的几个互转函数我整理成一张速查表目标类型转换函数作用列表list(可迭代对象)字符串、元组、集合、字典键转列表元组tuple(可迭代对象)列表、集合、字符串转元组集合set(可迭代对象)序列去重、字典键转集合字典dict(zip(keys, values))两个序列合成字典字符串也能转列表最常用的是splittext hello world python words text.split() # [hello, world, python] chars list(text) # [h, e, l, l, o, ...]反过来把列表转回字符串要用join注意语法是“字符串去join列表”不是“列表.join字符串”words [hello, world, python] result .join(words) # hello world python result2 ,.join(words) # hello,world,python这里有个常见的坑join要求列表里的元素全是字符串如果列表里有数字比如[1, 2, 3]直接用 .join([1, 2, 3])会报TypeError。解决办法是先转成字符串再joinnums [1, 2, 3] result .join(map(str, nums)) # 1 2 3还有一个反向操作字典转列表时list(some_dict)拿到的是所有键的列表而不是键值对。如果想拿到键值对列表用list(some_dict.items())如果想拿值列表用list(some_dict.values())。这几个区别在新手期也经常混淆建议自己敲一遍对比一下输出。6.2 实战一行代码统计字符频率容器之间的转换不只是“为了转而转”很多时候是为了借用目标容器的能力。我举一个综合性很强的例子统计一段文本中每个字符出现的次数并按频率排序输出text hello python, python is everywhere! # 第1步建一个空字典用于存频率 freq {} # 第2步遍历字符串统计每个字符出现次数 for char in text: freq[char] freq.get(char, 0) 1 # 第3步把字典转成列表方便排序 items list(freq.items()) # 第4步按频率倒序排列 items.sort(keylambda x: x[1], reverseTrue) # 第5步打印前5个最常见的字符 for char, count in items[:5]: print(f{char!r}: {count})这个例子把字典、列表、元组解包、get默认值、sort排序、字符串格式化全串起来了是容器章节最值得吃透的入门综合题。freq.items()返回的是一系列键值对元组所以遍历时能直接解包成char, count两个变量。sort的key参数指定按照元组的第二个元素排序reverseTrue表示从大到小。如果你只想统计“单词”的频率而不是单个字符先做一步text.split()把字符串变成单词列表然后再套用同样的统计逻辑。你会发现代码主体完全不用变只需要改变“输入容器里装的是什么”这正好体现了容器类型的抽象价值统计逻辑和数据类型解耦了。7. 我踩过的容器坑排查记录7.1 可变默认参数写函数时的大坑这个坑是所有Python函数讲解里都会划重点的因为它是真实项目里的高频翻车点。先看错误示范def add_item(item, items[]): items.append(item) return items第一次调用add_item(1)返回[1]第二次调用add_item(2)返回[1, 2]看起来似乎没问题但如果你在不同场景下多次调用这个函数会发现默认列表在函数调用之间被共享了。函数定义时默认参数items[]只创建一次之后所有调用都复用同一个列表。这个问题最隐蔽的地方在于当你不传第二参数时数据会在所有调用之间累积。正确做法是用None占位def add_item(item, itemsNone): if items is None: items [] items.append(item) return items这样每次不传items时都会创建全新列表。这个规则同样适用于默认参数为字典、集合的情况凡是可变对象都不能直接当默认参数。7.2 遍历时修改容器跳着删的诡异现象循环里删除列表元素看起来天经地义但结果往往让人看不懂。你写my_list [1, 2, 3, 4, 5, 6] for num in my_list: if num % 2 0: my_list.remove(num) print(my_list)你以为删掉偶数剩下[1, 3, 5]结果实际输出[1, 3, 5]这道题我见过太多次答案是在特定数据组合下结果是对的但换一组数据就错了。比如my_list [1, 2, 3, 4, 5, 6, 8]结果会残留8。原因是在遍历过程中删除元素列表的索引发声了前移循环又按原索引继续走于是跳过了紧挨着被删除元素的下一个元素。解决方案有三个一是遍历副本for num in my_list[:]:这样原列表怎么改都不影响遍历逻辑二是用列表推导式创建新列表[num for num in my_list if num % 2 ! 0]三是从后往前遍历。我个人推荐列表推导式因为它的意图最明确代码也最干净。记住一个原则遍历容器时不要修改容器本身要么遍历副本要么生成新的容器。7.3 浅拷贝与深拷贝b a只是多了个名字另一个让人非常容易困惑的问题列表复制。很多新手写a [1, 2, [3, 4]] b a b.append(5) print(a) # [1, 2, [3, 4], 5]明明改的是b为什么a也变了因为b a根本没有复制数据它只是给同一个列表多加了一个名字。两个变量指向内存里同一个对象任何修改都会互相影响。如果你想要一个独立的副本用切片或copy方法b a[:] b a.copy()但这两个都是浅拷贝。什么叫浅拷贝出来的新列表内部嵌套的可变对象仍然和原列表共享。比如b a.copy() b[2].append(99) print(a) # [1, 2, [3, 4, 99]]a也被改了如果你希望完全独立包括嵌套的内部列表需要用copy.deepcopyfrom copy import deepcopy b deepcopy(a) b[2].append(99) print(a) # [1, 2, [3, 4]]a没变这个知识点在刚开始用列表嵌套时会踩得比较痛建议专门写一小段代码验证一下浅拷贝和深拷贝的区别。字典和集合的复制也是同样的道理dict1.copy()是浅拷贝遇到嵌套的列表或字典仍然共享内部对象。判断“是否需要完全独立”的思路很简单数据里有没有嵌套的可变对象没有的话浅拷贝就够了有的话用deepcopy。8. 综合实战用容器类型写通讯录8.1 需求设计学到这里四种容器你已经都见过了。怎么把它们组合起来用我建议做一个迷你通讯录需求很接地气支持添加联系人、按姓名查找电话、显示所有联系人、检查电话号码是否重复。这个项目用字典做主存储结构键是姓名值是电话天然满足“按名字查电话”的需求contacts {} def add_contact(name, phone): contacts[name] phone def find_contact(name): return contacts.get(name, 联系人不存在) def show_all(): for name, phone in contacts.items(): print(f{name}: {phone}) def check_duplicate_phone(): phones list(contacts.values()) return len(phones) ! len(set(phones))contacts就是字典容器contacts.values()取出所有电话组成列表set(phones)去重后长度变短了说明存在重复电话。这行判断正是集合适用于去重的体现。如果你想按姓名排序显示可以用sorted(contacts)它返回排好序的键列表再遍历输出。8.2 核心代码与运行效果我们把上面的功能串起来写一个最简单的交互循环不用界面纯命令行就能跑def main(): contacts {} while True: print(\n1. 添加联系人 2. 查找联系人 3. 显示全部 4. 检查重复 5. 退出) choice input(请选择操作) if choice 1: name input(姓名) phone input(电话) contacts[name] phone elif choice 2: name input(姓名) print(contacts.get(name, 联系人不存在)) elif choice 3: for name, phone in contacts.items(): print(f{name}: {phone}) elif choice 4: phones list(contacts.values()) if len(phones) ! len(set(phones)): print(存在重复号码) else: print(没有重复号码) elif choice 5: break if __name__ __main__: main()这段代码里变相用到了四种容器的配合contacts是字典contacts.items()返回键值对元组list(contacts.values())转成列表set(phones)用于去重判断。虽然代码简单但容器协作的思路全在里面。运行效果大概是1. 添加联系人 2. 查找联系人 3. 显示全部 4. 检查重复 5. 退出 请选择操作1 姓名张三 电话13800138000 请选择操作3 张三: 13800138000如果你想更贴近真实需求可以把contacts初始化为一个已有的字典避免每次启动都从空开始。比如contacts {张三: 13800138000, 李四: 13900139000}添加新联系人时如果姓名已存在contacts[name] phone就会覆盖旧号码。想改成“已存在则提示”加一个判断即可。这个判断同样用到了in运算符对字典键的快速查找if name in contacts: print(联系人已存在覆盖电话)8.3 还能怎么扩展通讯录做到这一步已经足够你理解容器。但它只存在于内存里程序一关闭数据就没了。想持久化最简单的思路是用文件存储把字典写成文本文件下次启动时再解析回来。这一过程本身又会用到类型转换和容器操作def save(contacts, filenamecontacts.txt): with open(filename, w, encodingutf-8) as f: for name, phone in contacts.items(): f.write(f{name},{phone}\n) def load(filenamecontacts.txt): contacts {} try: with open(filename, r, encodingutf-8) as f: for line in f: name, phone line.strip().split(,) contacts[name] phone except FileNotFoundError: pass return contacts保存时把键值对一行一行写进文件加载时用split(,)把一行文本切成姓名和电话再重新组装成字典。你看split返回列表列表的元素又能解包成两个变量最后变成字典的键和值——类型转换在那张速查表里都有。如果你还要检查重复姓名而不是重复电话用字典就已经天然保证了键不重复所以不需要额外判断。如果需求变成“一个姓名可以对应多个电话”那存储结构就不能用简单的字典得用字典的键对应一个列表这就是嵌套容器了contacts {张三: [13800138000]} def add_phone(name, phone): if name not in contacts: contacts[name] [] contacts[name].append(phone)这个扩展思路值得你仔细琢磨一下它解释了一个核心问题为什么说容器可以组合使用因为现实数据不是单层结构一个“联系人”本身就可以是一个字典多个联系人组成一个列表列表又能变成集合去重。把基础容器组合起来能表达的数据模型几乎是无限的。我带过不少零基础的学员大家最容易卡住的不是语法而是想不到用什么容器。我的一个习惯是写代码前先用中文把数据的形状描述出来。比如这句话“我有一个电话本里面每个人对应一个号码”它天然就是字典。“我有一批成绩按顺序排列”天然就是列表。先用自然语言描述完数据再决定用哪种容器整个过程会顺很多。这一章学完建议你把每个容器的增删改查都手敲一遍再照着综合实战改造一个属于自己的小工具比如记账本、成绩单统计、购物车。容器不是背出来的是用出来的。
延伸阅读

更多相关文章

2026/9/15 6:11:36

SpringBoot高校智慧食堂预约平台:从需求到答辩的完整实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/15 6:11:36

Key Manager API:密钥生命周期管理与安全实践

1. 项目概述:Key Manager API在信息安全领域的核心价值密钥管理一直是信息安全体系中最关键的底层支撑。从业十年间,我见证过太多因密钥管理不当导致的数据泄露事件——从简单的配置文件硬编码到复杂的密钥轮换失效。Key Manager API正是为解决这一痛点而…

2026/9/15 6:06:36

affinitic-caching实战:用装饰器优雅管理Python缓存

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/15 6:21:36

MIT纳米级内爆制造技术突破:三维光子准晶体可编程制造

1. 项目背景与核心突破MIT研究团队在《Light: Science & Applications》发表的最新成果,将"内爆制造"技术(Implosion Fabrication)的精度从毫米级推进到纳米尺度。这项突破性技术通过精确控制材料的折射率分布,首次…

2026/9/15 6:21:36

仓颉IDE如何实现API文档与代码零切换开发

1. 为什么“切浏览器查 API”成了仓颉开发者的日常噩梦写仓颉代码时,我见过太多人把工作流卡在同一个地方:刚写完一行callService("user", "getProfile"),光标一停,立刻 AltTab 切出 IDE,点开浏览…

2026/9/15 6:21:36

RS485与Modbus RTU实战解析:物理层与协议层协同避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/15 6:21:36

iOS内存管理详解:从引用计数到循环引用,面试与实战全攻略

1. 为什么“iOS内存管理”是面试必考题,也是实战分水岭做iOS开发这几年,我面试过不少人,也被面试过不少次。只要岗位要求里写着“扎实的计算机基础”,内存管理几乎是逃不掉的一关。它不像UIKit那样背几个API就能糊弄过去&#xff…

2026/9/15 6:21:36

go2rtc + Docker 统一接入摄像头:RTSP/WebRTC 低延迟流媒体网关实践

1. go2rtc 到底是什么,为什么我需要它先说结论:go2rtc 是一个轻量级流媒体网关,用 Go 语言写的,核心功能是把各种不同协议的摄像头流统一接进来,再以你想要的协议转发出去。它支持 RTSP、RTMP、HLS、MSE、WebRTC、ONVI…

2026/9/15 6:16:36

基于以太坊的去中心化微博设计与实现:DApp全栈开发实践

简介:这套基于以太坊区块链的去中心化微博系统设计与实现方案,面向计算机、软件工程、信息工程等专业学生与开发者,主要解决区块链社交平台从合约设计到前端落地的问题,适用于毕业设计、课程实践及进阶学习。压缩包共38个文件、约…

2026/9/15 4:54:30

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/15 0:01:16

AI英语单词APP开发:自适应学习算法与移动端优化实践

1. 项目概述 作为一名在移动应用开发领域摸爬滚打多年的老手,我最近完成了一个AI英语单词APP的开发项目。这个项目将传统单词记忆方法与现代AI技术相结合,打造了一款能够智能适应不同用户学习习惯的英语学习工具。 市面上大多数单词APP都存在一个通病&a…

2026/9/15 0:01:16

Flutter与OpenHarmony结合开发手语学习APP实战

1. 项目背景与核心价值作为一名同时接触过Flutter和OpenHarmony的开发者,最近我完成了一个基于Flutter for OpenHarmony的手语学习APP实战项目。这个项目最大的特点在于实现了跨平台框架与国产操作系统深度结合的创新实践——用Flutter开发的应用能完美运行在OpenHa…

2026/9/15 0:01:16

六个月成为机器人工程师:从ROS2到SLAM的实战路径

1. 六个月的紧迫感从哪来:先搞清楚你要成为哪种机器人工程师说实话,六个月的期限并不是一个宽松的时间线。市面上任何一本正经的机器人学教材都超过五百页,ROS2的官方文档可以翻到你怀疑人生,再加上ABB、KUKA这些工业机器人厂家动…

2026/9/14 11:59:31

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/14 13:53:59

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/14 11:22:57

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码