直到现在才想明白:Python的精髓居然是花括号、圆括号、方括号!

简介: Python

image.png

和其他编程语言相比,什么才是Python独一无二的特色呢?很多程序员会说,缩进。的确,缩进是Python语言的标志性特点,但这只是外在的、形式上的。从语言特性层面讲,Python的特点是什么呢?我尝试着在知乎上搜索了一下,最具代表性的答案分别是语法简洁、简单易学、代码高效、功能强大等四项。仔细品味这四项,我还是觉得,这是Python语言表现出来的使用效果或用户感受,仍然不是语言特性层面的特色。
换个说法,究竟是Python的哪些语言特性使得人们普遍认为Python具有语法简洁、简单易学、代码高效、功能强大的特点呢?我个人认为,这要归功于列表(list)、字典(dict)、元组(tuple)和集合(set)这“四大金刚”。尽管整型(int)、浮点型(float)和字符串(str)也很重要,但这三种对象相对于其他编程语言来说,差异并不像“四大金刚”那样明显。可以毫不夸张地说,列表、字典、元组和集合代表了Python语言的核心和基础,同时也是Python的精髓所在。学会使用列表、字典、元组和集合,就意味着掌握了Python这门编程语言。

如果认可这个观点,那么,Python的精髓就从列表、字典、元组和集合等“四大金刚”,演变成由方括号、花括号和圆括号组成的“括号族”。

  1. 方括号

方括号几乎是所有编程语言的第一符号。这里的第一,并不是指使用频率,而是指这个符号展现出的编程语言的内涵和创造力。事实上,就符号的使用频率而言,方括号也可能排在首位——只是我的直觉,并没有统计数据支持。

1.1 创建列表
对于初学者来说,创建列表最常用的方法就是用一对方括号。

a = []>>> a[]>>> b = [3.14, False, 'x', None]>>> b[3.14, False, 'x', None]123456
即便是老鸟,也会大量使用方括号创建列表,尤其是使用推导式创建列表的情况下。

c = [i**2 for i in range(5)]>>> c[0, 1, 4, 9, 16]123
但我一直觉得,方括号就像口语或俚语,太过随便。我更喜欢使用严谨的list()来创建列表。使用list()创建列表,是list类的实例化的标准方法,可以体会list类的构造函数如何适应不同类型的参数。

a = list()>>> a[]>>> b = list((3.14, False, 'x', None))>>> b[3.14, False, 'x', None]>>> c = list({1,2,3})>>> c[1, 2, 3]>>> d = list({'x':1,'y':2,'z':3})>>> d['x', 'y', 'z']>>> e = list(range(5))>>> e[0, 1, 2, 3, 4]>>> f = list(''i for i in range(5))>>> f['', '', '', '', '']123456789101112131415161718
1.2 列表的索引
方括号可以创建列表,但方括号并不等同于列表,因为方括号还用来索引。

3.14, False, 'x', None'x'>>> 3.14, False, 'x', None'x'>>> 3.14, False, 'x', None[False, 'x', None]>>> 3.14, False, 'x', None[3.14, False, 'x']>>> 3.14, False, 'x', None[3.14, 'x']>>> 3.14, False, 'x', None[None, 'x', False, 3.14]12345678910111213
列表的索引非常灵活,尤其是引入了负数索引,用-1表示最后一个元素或逆序,实属喜大普奔。上面的操作,属于常用索引方式,如果能读懂下面的代码,说明你已经具备了足够深的功力。

a = [3.14, False, 'x', None]>>> a[2:2] = [1,2,3]>>> a[3.14, False, 1, 2, 3, 'x', None]1234
1.3 列表的方法
对于列表对象的方法如果能信手拈来,那就是Python高手了。

a = [3.14, False, 'x', None]>>> a.index('x')2>>> a.append([1,2,3])>>> a[3.14, False, 'x', None, [1, 2, 3]]>>> a[-1].insert(1, 'ok')>>> a[3.14, False, 'x', None, [1, 'ok', 2, 3]]>>> a.remove(False)>>> a[3.14, 'x', None, [1, 'ok', 2, 3]]>>> a.pop(1)'x'>>> a[3.14, None, [1, 'ok', 2, 3]]>>> a.pop()[1, 'ok', 2, 3]>>> a[3.14, None]1234567891011121314151617181920

  1. 花括号

花括号代表字典对象,大多数初学者都这样认为。然而,这是错误的,至少是片面的。下面的代码中,a和b都是用花括号创造出来的对象,却一个是字典,一个是集合。

a = {}>>> a{}>>> b = {'x','y','z'}>>> b{'y', 'z', 'x'}>>> type(a)>>> type(b)12345678910
原来,Python用花括号表示字典和集合两种对象:花括号内是空的,或者是键值对的,表示字典;花括号内是无重复元素的,表示集合。为了不引起误会,我习惯用dict()来生成字典,用set()来生成集合。

dict(){}>>> dict({'x':1, 'y':2, 'z':3}){'x': 1, 'y': 2, 'z': 3}>>> dict((('x',1), ('y',2), ('z',3))){'x': 1, 'y': 2, 'z': 3}>>> dict.fromkeys('xyz'){'x': None, 'y': None, 'z': None}>>> dict.fromkeys('abc', 0){'a': 0, 'b': 0, 'c': 0}>>> set((3,4,5)){3, 4, 5}>>> set({'x':1, 'y':2, 'z':3}){'y', 'z', 'x'}>>> set([3,3,4,4,5,5]){3, 4, 5}12345678910111213141516
编码实践中,虽然在某些情况下集合是无可替代的,但集合的使用频率是“四大金刚”中最低的,我们这里不展开讨论,只说说字典的使用技巧。

2.1 判断一个键是否存在于字典中
Py2时代,dict对象曾经有has_key()的方法,用来判断是否包含某个键。py3舍弃了这个方法,判断一个键是否存在于字典中,只能使用in这样的方法了。

a = dict({'x':1, 'y':2, 'z':3})>>> 'x' in aTrue>>> 'v' in aFalse12345
2.2 向字典中添加一个新键或更新键值
很多人喜欢用对字典的一个键赋值的方法,实现向字典中添加一个新键或更新键值。

a = dict()>>> a['name'] = 'xufive'>>> a{'name': 'xufive'}1234
我不推荐这样的方式,使用update()才更有仪式感,还可以一次添加或修改多个键。

a = dict()>>> a.update({'name':'xufive', 'gender':'男'})>>> a{'name': 'xufive', 'gender': '男'}1234
2.3 从字典中获取一个键值
a[‘age’]是最常用的方式,但是也还会遇到键不存在的异常。下面的方法值得推荐。

a.get('age', 18)1812
2.4 获取字典的全部键、全部值、全部键值对
dict类提供了keys()、values()和items()等三个方法分别返回字典的全部键、全部值和全部键值对。需要注意的是,返回结果并非列表,而是迭代器。如果你需要列表形式的返回结果,请使用list()转换。

a = dict()>>> a.update({'name':'xufive', 'gender':'男'})>>> list(a.keys())['name', 'gender']>>> list(a.values())['xufive', '男']>>> list(a.items())[('name', 'xufive'), ('gender', '男')]12345678
2.5 遍历字典
遍历字典的时候,很多同学或写成遍历字典的keys()。其实,不需要这么麻烦,可以像下面这样直接遍历。

a = dict([('name', 'xufive'), ('gender', '男')])>>> for key in a: print(key, a[key]) name xufivegender 男123456

  1. 圆括号

圆括号代表元组对象,这么说应该没有问题吧?的确,听起来没有问题,但在元组的使用上,我相信每个初学者都会跌进同一个深坑至少一次。

3.1 必入之浅坑
元组不用于列表的最显著的特点,就是无法更新元素的值。忘记或者忽略这一点,就会入坑。

a = (3, 4)>>> a[0] = 5Traceback (most recent call last): File "<pyshell#14>", line 1, in a[0] = 5TypeError: 'tuple' object does not support item assignment123456
3.2 必入之深坑
使用了多年Python之后,我曾经写出的最糟糕的bug,就是下面这一段代码。

import threading>>> def do_something(name): print('My name is %s.'%name) >>> th = threading.Thread(target=do_something, args=('xufive'))>>> th.start()Exception in thread Thread-1:Traceback (most recent call last): File "C:\Users\xufive\AppData\Local\Programs\Python\Python37\lib\threading.py", line 926, in _bootstrap_inner self.run() File "C:\Users\xufive\AppData\Local\Programs\Python\Python37\lib\threading.py", line 870, in run self._target(self._args, *self._kwargs)TypeError: do_something() takes 1 positional argument but 6 were given12345678910111213
我分明只提供了1个参数,却提示说给出了6个参数,为什么呢?原来,元组初始化时,如果只有单个参数,则必须在单个参数之后增加一个逗号(,),否则,初始化结果仅返回原参数。

a = (5)>>> a5>>> type(a)>>> b = ('xyz')>>> b'xyz'>>> type(b)>>> a, b = (5,), ('xyz',)>>> a, b((5,), ('xyz',))>>> type(a), type(b)(, )123456789101112131415
3.3 单星号解包元组
格式化输出字符串时,C语言风格是我的最爱。当有多个%需要匹配时,下面也许是最自然而然的写法。

args = (95,99,100)>>> '%s:语文%d分,数学%d分,英语%d分'%('天元浪子', args[0], args[1], args[2])'天元浪子:语文95分,数学99分,英语100分'123
正确固然正确,但不够精彩。满分写法应该是这样的。

args = (95,99,100)>>> '%s:语文%d分,数学%d分,英语%d分'%('天元浪子', *args)'天元浪子:语文95分,数学99分,英语100分'123
3.4 为什么要使用元组?
既然元组的元素不可改变,那为什么还要使用元组呢?使用列表代替元组不是更方便吗?诚然,在多数情况下,可以使用列表代替元组,但下面的例子却可以证明,列表无法代替元组。

s = {1,'x',(3,4,5)}>>> s{1, (3, 4, 5), 'x'}>>> s = {1,'x',[3,4,5]}Traceback (most recent call last): File "<pyshell#32>", line 1, in s = {1,'x',[3,4,5]}TypeError: unhashable type: 'list'12345678
我们可以将元组加到集合中,但列表不行,因为列表是不可哈希(unhashable)的。理解这一点并不困难:列表元素可以被动态改变,所以没有一个固定不变的哈希值——这与集合要求的元素唯一性冲突;而元组的元素被禁止更新,其哈希值在整个生命周期都不会变化,因此可以成为集合的元素。

显然,元组和列表有着完全不同的存储方式。因为不用考虑更新问题,元组的速度性能要远优于列表。优先使用元组,应该成为Python程序员遵循的一条基本原则。

相关文章
|
6月前
|
编译器 测试技术 C++
【Python 基础教程 01 全面介绍】 Python编程基础全攻略:一文掌握Python语法精髓,从C/C++ 角度学习Python的差异
【Python 基础教程 01 全面介绍】 Python编程基础全攻略:一文掌握Python语法精髓,从C/C++ 角度学习Python的差异
275 0
|
3月前
|
Python
掌握Python算术与反算术精髓,解锁编程新境界,轻松驾驭数值计算,让每一行代码都精准无误!
【8月更文挑战第22天】Python中的算术运算符如加(+)、减(-)、乘(*)、除(/)、整除(//)、取模(%)及幂运算(**)是数值计算的基础,简化了编程过程并使代码更直观。例如,可以轻松计算矩形的面积与周长。而所谓的“反算术”操作,如取反(使用负号-)和求绝对值,则能进一步处理数值结果。这些运算符是编程中不可或缺的工具,帮助我们高效且清晰地解决问题。
33 0
|
5月前
|
Python
掌握Python中循环语句的精髓:基础用法与高级技巧
掌握Python中循环语句的精髓:基础用法与高级技巧
109 0
|
4月前
|
程序员 Python
从零到一,彻底掌握Python闭包与装饰器的精髓,成为编程界的隐藏Boss
【7月更文挑战第7天】探索Python编程的两大基石:闭包与装饰器。闭包是内部函数记住外部作用域的变量,如`make_multiplier_of`返回的`multiplier`,它保持对`n`的引用。装饰器则是函数工厂,接收函数并返回新函数,如`my_decorator`,它在不改变原函数代码的情况下添加日志功能。掌握这些,让代码更优雅,效率更高,助你成为编程高手。
32 3
|
5月前
|
存储 索引 Python
【Python列表解锁】:掌握序列精髓,驾驭动态数据集合
【Python列表解锁】:掌握序列精髓,驾驭动态数据集合
|
6月前
|
大数据 Python
Python中的`yield`:掌握生成器的精髓
【4月更文挑战第17天】`yield`在Python中用于创建生成器,一种节约内存的迭代器。生成器函数在迭代时暂停并保存状态,下次迭代时继续执行,适用于处理大数据、实现协程和优化内存。`yield`不同于普通函数,不立即计算所有结果,而是在需要时生成单个值。使用场景包括生成大列表、实现协程和简化迭代逻辑。注意`yield`后的值不能是表达式,生成器只能调用一次,且`yield`与`return`作用不同。理解并善用`yield`能提升Python编程效率。
|
Python
Python文件路径解谜:深入剖析os.path系列函数的精髓
Python文件路径解谜:深入剖析os.path系列函数的精髓
225 0
|
5天前
|
存储 数据挖掘 开发者
Python编程入门:从零到英雄
在这篇文章中,我们将一起踏上Python编程的奇幻之旅。无论你是编程新手,还是希望拓展技能的开发者,本教程都将为你提供一条清晰的道路,引导你从基础语法走向实际应用。通过精心设计的代码示例和练习,你将学会如何用Python解决实际问题,并准备好迎接更复杂的编程挑战。让我们一起探索这个强大的语言,开启你的编程生涯吧!
|
11天前
|
机器学习/深度学习 人工智能 TensorFlow
人工智能浪潮下的自我修养:从Python编程入门到深度学习实践
【10月更文挑战第39天】本文旨在为初学者提供一条清晰的道路,从Python基础语法的掌握到深度学习领域的探索。我们将通过简明扼要的语言和实际代码示例,引导读者逐步构建起对人工智能技术的理解和应用能力。文章不仅涵盖Python编程的基础,还将深入探讨深度学习的核心概念、工具和实战技巧,帮助读者在AI的浪潮中找到自己的位置。
下一篇
无影云桌面