尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Python三对括号怎么用?一篇文章讲清()、[]、{}的区别与嵌套
如果你刚开始写 Python最先让你怀疑人生的大概就是三对括号。()、[]、{}看起来只是圆、方、花的区别用错一个位置轻则语法报错重则数据变成另一个结构。这个问题在 Python 入门、字典操作、函数定义、文件处理和列表改造里几乎天天都能碰到。很多新手会背“元组用圆括号、列表用方括号、字典用大括号”但一旦代码嵌套到两层以上括号该怎么选马上就开始犹豫。这篇不讲高深理论只把三种括号的用途、混用场景和排查技巧放到一起讲清楚适合正在学 Python 基础、写作业或者刚接触数据处理的人直接对照使用。1. 三种括号的分工定位先把整体框架搭起来在深入细节之前先建立整体框架。每一种括号不是随意的符号选择它对应着 Python 里一类容器或一类操作。圆括号负责“动作和边界”方括号负责“位置和可变序列”大括号负责“映射与去重”。这个对应关系一旦建立后面遇到复杂嵌套就自然知道往哪个方向想。1.1 圆括号函数操作与元组的双重身份圆括号最常见的使用场景是放在函数名后面表示“调用”。无论是print()、len()这样内置函数还是你通过def自己定义的函数只要后面跟着()就代表要执行这个操作。比如len([1, 2])这里的[1, 2]是列表len(...)是对这个列表进行长度统计。括号在这里就是“动作”的标识看到它说明你要触发某段逻辑。圆括号的第二个身份是运算符分组。(2 3) * 4里的括号不是元组它只是把加法先算完跟数学课本上学的一模一样。这个用法太自然以至于很多人会忽略它的存在但它也带来一个经典误解在a (1)里你看到的并不是元组而是整数 1。要写成(1,)才是元组。注意元组的本质由逗号决定圆括号更多是“视觉边界”和“分组符号”它本身并不能凭空创造一个元组。圆括号的第三个身份才是真正容易被新同学忽略的地方构造元组。元组是一种不可变序列适合存放那些不应该被随意修改的数据比如坐标点、颜色值、一个函数返回的多个结果。t (1, 2, 3)是最直白的写法但下面这种写法更容易迷惑人t1 (1, 2) t2 1, 2 print(type(t1)) # class tuple print(type(t2)) # class tuplet1和t2都是元组区别只是有没有外部括号。Python 解释器真正看中的只有一个东西逗号。所以当你看到“函数返回多个值”时其实返回的就是一个元组例如return 1, 2外面不写括号也没关系。1.2 方括号序列索引与可变更容器的标志方括号的第一项工作是创建列表。列表是可伸缩的容器可以增、删、改适合存放“数量会变化”的一组数据。比如一个任务清单今天三条、明天五条那就应该用tasks []来创建。之后可以往里面append、remove、按位置修改元素这一系列操作的前提都是这个容器允许变化。方括号的第二项工作是下标访问和切片。无论是列表、元组还是字符串s[0]取第一个元素s[-1]取最后一个元素s[1:3]取中间一段这一套统一叫“下标操作”统用[]。字典取值也用[]比如d[name]本质是“传一个键进去取回对应的值”。很多初学者分不清“创建列表”和“访问元素”其实它们是同一个符号的两个位置。当方括号跟在变量名后面比如lst[0]是在取位置当它独立出现比如[1, 2, 3]多半是在创建列表。如果你看到的是d[key]那“创建字典用{}取值却用[]”也没有矛盾因为方括号在这里承担的是“按名字找东西”的动作和字典本身的声明符号不是一回事。下面的例子能直观看出方括号的两种用途nums [10, 20, 30] # 创建列表 print(nums[0]) # 按位置读取输出 10 print(nums[1:3]) # 切片输出 [20, 30] nums.append(40) # 列表允许修改 print(nums) # [10, 20, 30, 40]1.3 大括号显式映射与集合的去重工具大括号在 Python 里一共有两种字面量含义一个跟字典有关一个跟集合有关区分方法就藏在有没有冒号。第一种是字典字面量特征是“键: 值”成对出现。{name: A, age: 18}是一个 dict它表达的是“用名字找数值”的映射关系。字典的键可以是字符串、数字、元组等不可变类型值可以是任意对象。日常看到的一堆带名字的属性比如学生信息、配置项、HTTP 请求头都适合用字典。第二种是集合字面量特征是一堆并列元素没有冒号。{python, java, go}是一个 set它自动去重并且不保证顺序。集合适合做成员判断、交集并集差集运算但不能像列表那样按下标访问因为它的存储本来就不强调顺序。这里有一个几乎所有人都会踩的坑{}是空字典不是空集合。想要空集合必须写set()。这是 Python 设计历史留下的约定没有特别深奥的原因但是不知道就是不知道。d {name: A} s {python, java, go} empty {} empty_set set() print(type(empty)) # class dict print(type(empty_set)) # class set另外大括号还有一类容易漏掉的小用途在 f-string 里作为占位符例如fname{name}。这时候的{}既不是字典也不是集合只是告诉 Python“把变量的值填到这里”。这类特殊场景需要单独记忆但不要影响你对大括号主要身份的判断。2. 最容易混淆一行代码里的括号混战我见过很多新手单个括号的规则背得很清楚但一到真实代码就傻眼因为现实里的数据结构往往是嵌套的外层是字典里面是列表列表里又放元组。括号一混读起来就像天书。这一节就解决这个问题。2.1 从一段真实数据开始拆解嵌套结构与其背规则不如直接看一段典型数据。假设我们要管理一个开发小组的信息小组里有多个成员每个成员有自己的名字、级别和标签。我一般会用下面这种结构users { group: dev, members: [ {name: A, level: 3, tags: (python, backend)}, {name: B, level: 2, tags: (golang, ops)}, ], }外层用{}是因为我们想按名字查属性查users[members]得到整个成员列表。成员之间是有顺序的而且未来可能有人加入、有人离开所以用[]列表来装。每个成员又有姓名、级别、标签等多个属性这些属性是无序但有名字的所以用{}字典。最后每个成员的标签是一组固定的身份信息不应该被随意修改所以用()元组。现在要从这个结构里取出第一个成员的第一个标签print(users[members][0][tags][0])从左往右读这个表达式先取字典里的members拿到一个列表再取列表的第 0 个元素得到一个字典再取这个字典里的tags拿到一个元组最后取元组的第 0 个元素得到字符串python。每一步用到的括号都跟当前数据的类型严格对应。记住这个读法后续你写所有嵌套结构都不会慌。2.2 看似是元组却不是元组的场景(1)不是元组(1,)才是元组这是个看起来简单、实际上很阴间的细节。因为 Python 在绝大多数情况下看到圆括号第一反应是“分组”而不是“构造元组”。只有当括号里有逗号或者括号为空它才会被解释成元组。a (1) b (1,) empty () print(type(a)) # class int print(type(b)) # class tuple print(type(empty)) # class tuple还有一个更误导人的场景生成器表达式。(x for x in range(3))的外层确实是圆括号但它最后的类型既不是元组也不是列表而是 generator。生成器是惰性计算的对象能节省内存但只能遍历一次也不能像元组那样按下标读取。同样要留意的是条件判断里看起来很像元组的写法比如if (age 18 and is_student):。这个括号纯粹是运算符分组让逻辑更清晰。你把它去掉结果不变把内容理解成元组再去操作就会出问题。2.3 空容器到底选哪个[]、()、{} 和 set()空容器是初学者最高频的痛点之一因为一眼看过去全是空的符号区别实在不明显。你可以用下面这张表做参考表达式实际类型能否修改典型用途[]list可以存放可变序列后续增删改()tuple不可以存放固定结构防止误改{}dict可以按名字或键存取值set()set可以去重、集合运算如果心里还是没有底就倒着问自己我现在要装的东西需不需要保持顺序列表和元组需要保持顺序字典和集合不用。需不需要频繁增删那就别选元组。需不需要给每个元素再挂一个“名字”需要就选字典。需不需要保证元素不重复需要就选集合。判断空容器的类型最稳妥的方式还是执行一下type()。比如if data:这样写好多人以为是在判断“有没有元素”其实不同类型对这个判断的反应都是一样的空列表、空字典、空元组、空集合在布尔上下文里都是 False。问题不在逻辑判断而在后续你调用的方法dict没有.add()set没有.items()类型选错了方法和数据就直接失配。3. 判断口诀与进阶用法从会用到用对如果上面两节你都有印象那现在可以把经验压缩成几句可以用在写码现场的口诀。这一节还顺便把推导式、切片、函数参数和类型注解里的括号扩展用法讲清楚因为这些场景才是日常“括号焦虑”的重灾区。3.1 一句话快速确定该用哪个括号我教初学者时习惯用三句话判断后面要接“动作”比如调用函数、定义参数、做运算分组用圆括号()。需要“按位置取”或者声明一个“可增删的序列”用方括号[]。需要“键值映射”或者存“不重复元素”用大括号{}。这套话术比表格好记。遇到d[key]这种写法也不用慌乱因为大括号负责的是“声明一个字典”而方括号负责“从字典里取一个值”两个符号担任了不同步骤这是正常现象。把动作、位置、映射这几个关键词记牢能解决八成困惑。再看一个简单的决策对照我想干什么该用什么示例调用一个函数()len(s)存储不可变坐标()position (10, 20)存储可变任务清单[]tasks []读取列表某个位置[]tasks[0]建立年龄和姓名的映射{}ages {A: 18}去重出一组标签{}或set()tags {a, b}注意这张表只能帮你做初判不能死记。比如字典取值必须用[]但创建空字典必须用{}集合不能按下标取但去重几乎离不开{}。判断时始终结合当前“动作”和“容器角色”而不是只认符号。3.2 推导式中的括号选择直接影响生成结果推导式是 Python 里非常能体现“括号即类型”的地方。同样一段循环逻辑最外层括号一变产物就完全不一样a [x * 2 for x in range(5)] # 列表推导式 - [0, 2, 4, 6, 8] b {x: x % 3 for x in range(5)} # 字典推导式 - {0: 0, 1: 1, 2: 2, 3: 0, 4: 1} c {x % 2 for x in range(5)} # 集合推导式 - {0, 1} d (x * 2 for x in range(5)) # 生成器表达式 - generator object ...第一行用方括号结果是一个列表所有元素在创建那一刻就在内存里生成好了。第二行有冒号说明它是在构造键值映射结果是字典。第三行没有冒号元素又有去重需求结果是集合。第四行和第一行长得像但最外层是圆括号结果变成了生成器它不会立刻算出所有元素而是等你去遍历的时候一个个生成。这里有个高频犯错点写生成器表达式之后想用下标去访问比如d[0]结果直接报错。因为生成器不支持下标访问它是一个“消费型”对象遍历一次就空了。如果你真的想要元组就写tuple(x * 2 for x in range(5))先把生成器转成元组。别把“看着像元组的括号”和“真是元组”混为一谈。3.3 切片、函数参数、类型注解进阶用法里的括号增生切片是方括号能力的延伸nums[1:4]、nums[::2]、nums[::-1]都依赖方括号。切片的返回值类型会尽量保持原类型列表切片得到列表元组切片得到元组字符串切片得到字符串。很多人会觉得nums[1:4]中间的冒号像“字典的冒号”其实没有任何关系它只是切片的边界写法。函数参数是圆括号的另一个大舞台。你在定义函数时写的def collect(*args, **kwargs):圆括号负责圈出参数列表星号负责解开序列双星号负责解开字典。当你在调用时写collect(**info)字典本身是用{}创建的**负责把它展开成keyvalue的形式传进去。这里三个括号会同时出现一旦顺序错位解释器立刻翻脸。类型注解也是现代 Python 里很常用的地方它会把之前混乱的直觉重新拉正names: list[str] [A, B] scores: dict[str, int] {math: 90} pos: tuple[float, float] (0.5, 1.0)list[str]、dict[str, int]、tuple[float, float]这种写法方括号不是用来取下标而是用来给容器内元素类型做标注。如果粗心写成pos: (float, float)(float, float)只是一个普通元组对象注释含义就丢了类型检查工具也会失效。这种坑比较隐蔽但只要你理解“元组由逗号定义注解由符号类型决定”就不会再踩。4. 高频报错与排查技巧哪些坑我踩过讲再多理论都不如亲手踩几个坑印象深。我刚开始写 Python 时括号混用造成的报错占了一半以上。下面这些错误是我见过或亲身经历过的每一条都和三种括号的选择直接相关。4.1 最容易发生的四种括号型报错第一种TypeError: tuple object is not callable。这个报错最常见的来源是你把一个变量声明成了元组然后又试图把它当函数调用。比如t (1, 2) # t() # 错误t 是元组不是函数 print(t[0]) # 正确取元组元素要用方括号出现这种问题说明你把“读取元组元素”和“调用函数”两种动作混在一起了。记住一个死规则括号放在变量名后面且前面没有任何函数名只表示“用这个变量去调用”而要取容器里的值一律用[]。第二种TypeError: unhashable type: list。这个报错常见于把列表用作字典键或集合元素。列表是可变的不能计算哈希元组不可变可以计算哈希所以{(1, 2): x}合法{[1, 2]: x}非法。需要表达“多个维度的坐标”时官方答案是元组不是方括号。遇到这种报错优先检查冒号左边和集合元素里有没有列表。第三种TypeError: list indices must be integers or slices, not tuple。这个报错在写矩阵或表格数据时特别容易出。内置的 list 不支持“逗号坐标”写法用matrix[0, 0]会把0, 0解析成元组而列表不认这种下标必须写成matrix [[1, 2], [3, 4]] # value matrix[0, 0] # 错误 print(matrix[0][0]) # 正确先取行再取列某些第三方库和数据处理框架会支持arr[0, 0]这种坐标写法但那是框架自定义的语法不是 Python 内置 list 的行为。除非你明确在用此类工具否则看到这个报错第一反应应该是改成[x][y]。第四种AttributeError: dict object has no attribute add。这基本可以断定你把空集合写成了{}。{}是空字典字典没有.add()想要集合请先s set()再s.add(1)。# 错误写法 # s {} # s.add(1) # 正确写法 s set() s.add(1)4.2 两分钟排查思路确认符号、类型和边界遇到括号报错别直接在原行上一通乱改。我的习惯是把它拆成三个步骤。第一步确认整行的括号是否闭合。有些编辑器会自动补右括号但一旦你手动删除或补写很容易出现外层{}已经结束内层()还没封口或者反过来。把鼠标停在左括号上看编辑器能不能高亮到对应的右括号是最快的检查方式。第二步打印类型不看猜。在报错行之前加一行临时print(type(...))确认你操作的对象到底是列表、元组、字典还是集合。很多时候你脑补的“它应该是个列表”和实际完全不匹配这时候猜是没有用的直接让解释器告诉你答案。第三步把复杂表达式拆行。比如users[members][0][tags][0]这种长链路一旦报错很难定位。你可以先members users[members]再member members[0]再tags member[tags]最后取tags[0]。每拆一步报错位置就变得清晰括号层级也不会再绕晕你。4.3 常用括号用法速查表把今天这些零散知识点整合成一张速查表写代码想不起来时直接看这一张写法含义关键点f(x)调用函数圆括号是动作def f(x):定义函数参数在圆括号里(1, 2)元组逗号决定元组(x for x in ...)生成器表达式惰性只能遍历一次[1, 2, 3]列表可变序列s[0]/s[::2]下标 / 切片统用方括号d[k]字典取值键必须可哈希{a: 1}字典字面量键值对{a, b}集合字面量去重不保序set()空集合不能写成{}f{name}字符串占位大括号的第三类用途list[int]类型注解方括号标注元素类型这张表不能解决所有问题但能让你在最慌的那几秒里快速定位方向。剩下的交给type()和报错信息去验证。5. 练习建议与个人经验从记住到熟练括号用法不是说看一遍就完事的真正掌握需要动手。下面三组练习是我建议刚学 Python 的人按顺序刷一遍的难度不大但覆盖了今天讲的几乎所有括号场景。5.1 三道适合按顺序做的巩固练习练习一用嵌套容器保存两个学生的语文和数学成绩。要求学生之间有顺序成绩字段有名字成绩数字不可随意修改。参考实现students [ {name: A, scores: {chinese: 88, math: 92}}, {name: B, scores: {chinese: 79, math: 85}}, ] print(students[1][scores][math]) # 85这个结构里外层用[]是因为学生按顺序排列且可能增删每个学生用{}是因为我们要按名字取属性成绩内部再用{}但如果你想把单科成绩理解成固定属性不可被替换也可以考虑元组关键是在动手前先想清楚“哪个容器必须可变哪个必须不可变”。练习二输入一个字符串取出所有不重复字符并保持它们在字符串中第一次出现的顺序。直接set()会打乱顺序更好的方式是利用字典键唯一且保序的特性text abracadabra result list(dict.fromkeys(text)) print(result) # [a, b, r, c, d]里面有两层括号值得体会text后面没有括号是普通变量dict.fromkeys(text)是函数调用用圆括号把参数包住最外层list(...)又是函数调用把字典键转成列表最后打印时还要按result的内容逐项输出。这个题目能同时练到函数调用、字典、列表和集合思维。练习三用**把字典展开成函数的关键字参数。这个练习能帮助你把“大括号创建映射”和“圆括号调用函数”串联起来def show_info(name, city): print(f{name} lives in {city}) info {name: A, city: 某城} show_info(**info)执行以后函数收到的name和city分别对应字典里的值。这里的{}声明了字典**负责展开圆括号负责调用函数三对括号在同一行里各司其职。你可以在info里多放几个和函数参数名不一致的键看看解释器报什么错能更直观地理解参数匹配规则。5.2 我踩过的坑和三条实用建议我第一次写去重代码时随手写了一个result {}然后想调用result.add(element)结果直接报AttributeError。当时翻来覆去看了很久才意识到{}是字典而不是集合。这个坑让我彻底记住了在 Python 里空集合必须使用set()。另一个印象深刻的问题是变量复用。我先定义了一个元组变量名字叫t后面又想把一个方法返回的结果赋给它结果中间有一次不小心写了t()解释器立刻报tuple object is not callable。这个错误在刚接触函数和元组的人身上非常常见本质不是因为元组特殊而是你把“访问”写成了“调用”。基于这些经历我给正在入门的朋友三条建议。第一多打印类型。在不确定的位置加一行print(type(x))成本极低收益极高。不用猜直接看。第二写类型注解。哪怕只是给变量加上list[int]、dict[str, int]、tuple[float, float]这种简单标注也会强迫你在写代码前想清楚容器的责任。久而久之三种括号对应的角色会自动刻进直觉里。第三复杂表达式拆开写。一行能写十个括号不代表应该这么写。先给中间结果起个名字再继续往下写报错时定位就是几秒钟的事。代码长一点没关系可读性远比“显得很厉害”重要。我现在的习惯是不管再小的脚本动笔前先用一句话描述数据结构这组数据是要按顺序存还是要按名字查还是要做去重想清楚这个问题括号的答案就自己浮出来了。三种括号说白了就是三种角色分工圆括号负责动作与边界方括号负责位置与可变序列大括号负责映射与去重。把这个分工用顺Python 里那些“突然不会写”的瞬间会少掉一大半。
RELATED

相关推荐

淘宝商品视频怎么保存到本地?四种实测方法一次说清

淘宝商品视频怎么保存到本地?四种实测方法一次说清

刚需要下载淘宝商品视频的时候,很多人都以为只能用录屏来搞定。你看完一个宝贝视频,想给朋友参考对比,或者作为买家秀素材二次编辑,又或者你是代购、运营、商家,想把别人家的视频存下来研究一下拍摄思路,这…

📅 2026/10/9 17:21:41
深入理解Linux IO缓冲区:从stdio到Page Cache的数据落盘之路

深入理解Linux IO缓冲区:从stdio到Page Cache的数据落盘之路

1. 一次printf背后的三层缓冲:数据到底经历了什么先从一个最普通不过的场景说起。你写了这样一段代码:printf("Hello, World!\n");然后程序退出,你在终端看到了这句话。看起来这只是一瞬间的事,但如果我们把时间轴拉长、…

📅 2026/10/9 17:21:41
LibreChat 添加自定义模型:把 Anthropic 兼容接口与华为云 MaaS 标准 API 改到 TaoToken

LibreChat 添加自定义模型:把 Anthropic 兼容接口与华为云 MaaS 标准 API 改到 TaoToken

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

📅 2026/10/9 17:21:41
MORE NEWS

更多资讯

📰

信创适配实战:国产数据库与Web容器改造避坑指南

简介:这份PPT资料面向正在推进应用系统国产化改造的开发与运维人员,聚焦信创环境下的适配落地问题,系统梳理了国产数据库与国产Web应用容器的迁移改造经验。内容涵盖达梦、瀚高数据库的适配案例,以及东方通、宝兰德等国产中间件的…

📰

Linux下make与Makefile从入门到实战:原理、语法与排错指南

在Linux下做C/C开发,早晚都会遇到make这个东西。我刚入行那会儿,项目也就三五个源文件,全靠一条条敲gcc命令硬编,后来文件一多,每次改完代码都要在终端里翻历史记录找上一条编译命令,更别提头文件一变动&am…

📰

Python爬虫实战:抓取网站图片区第一页所有图片

1. 从"图片区第一页"这个需求说起&#xff1a;抓图任务的边界到底在哪很多人拿到"抓取某个网站图片区第一页所有图片"这个需求时&#xff0c;第一反应是打开浏览器、右键查看源码、找到<img>标签、复制链接、写个requests.get循环下载&#xff0c;收…

📰

SNOMED CT 关系数据库实战:建表、导入与图查询优化

简介&#xff1a;这份资源面向医疗信息化开发者、数据工程师及SNOMED CT术语集使用者&#xff0c;提供在关系数据库中表示SNOMED CT的完整脚本方案&#xff0c;解决将RF2分发格式的术语版本导入MySQL、PostgreSQL、MSSQL或Neo4j等数据库的实际问题&#xff0c;适合具备一定SQL与…

📰

高校社团管理系统:需求分析、数据库设计与工程实践全流程

简介&#xff1a;这份资源是面向高校计算机相关专业学生的软件工程大作业完整交付包&#xff0c;以高校社团管理系统为主题&#xff0c;涵盖需求分析、系统设计等全套文档与设计报告&#xff0c;适合作为课程设计、毕业设计、作业或项目初期立项演示的参考方案&#xff0c;也便…

📰

Faust 贡献指南:从报 Bug 到提交代码与发布的完整工作流

流处理消息队列后端 【免费下载链接】faust Python Stream Processing 项目地址&#xff1a; https://gitcode.com/gh_mirrors/fa/faust 点击查看 免费下载 Faust 是一个用于 Python 流处理的库&#xff0c;主要与 Kafka 配合使用&#xff08;README.rst&#xff09;&#xff…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬