• 2
  • 3
分享
  • Python精髓之括号家族:方括号、花括号和圆括号的用法总结
  • 北极 2022-11-14 13:50:14 字数 5551 阅读 4168 收藏 3

Python独一无二的特色除了缩进还有哪些特色呢?大多数的回答一定是语法简洁、简单易学、代码高效、功能强大等四项。那究竟是Python的哪些语言特性使得人们普遍认为Python具有语法简洁、简单易学、代码高效、功能强大的特点呢?其实很大程度上,这要归功于列表(list)、字典(dict)、元组(tuple)和集合(set)这“四大金刚”。尽管整型(int)、浮点型(float)和字符串(str)也很重要,但毫不夸张地说,列表、字典、元组和集合才代表了Python语言的核心和基础,同时也是Python的精髓所在。学会使用列表、字典、元组和集合,就意味着掌握了Python这门编程语言。

我们来一起回顾一下由列表、字典、元组和集合“四大金刚”,而演变成的由方括号、花括号和圆括号组成的“括号族”。

1. 方括号

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

1.1 创建列表

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

>>> a = []
>>> a
[]
>>> b = [3.14, False, 'x', None]
>>> b
[3.14, False, 'x', None]

即便是老鸟,也会大量使用方括号创建列表,尤其是使用推导式创建列表的情况下。

>>> c = [i**2 for i in range(5)]
>>> c
[0, 1, 4, 9, 16]

但其实方括号就像口语或俚语,太过随便。大家要习惯使用严谨的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
['', '*', '**', '***', '****']

1.2 列表的索引

方括号可以创建列表,但方括号并不等同于列表,因为方括号还用来索引。

>>> [3.14, False, 'x', None][2]
'x'
>>> [3.14, False, 'x', None][-2]
'x'
>>> [3.14, False, 'x', None][1:]
[False, 'x', None]
>>> [3.14, False, 'x', None][:-1]
[3.14, False, 'x']
>>> [3.14, False, 'x', None][::2]
[3.14, 'x']
>>> [3.14, False, 'x', None][::-1]
[None, 'x', False, 3.14]

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

>>> a = [3.14, False, 'x', None]
>>> a[2:2] = [1,2,3]
>>> a
[3.14, False, 1, 2, 3, 'x', None]

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]

2. 花括号

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

>>> a = {}
>>> a
{}
>>> b = {'x','y','z'}
>>> b
{'y', 'z', 'x'}
>>> type(a)
<class 'dict'>
>>> type(b)
<class 'set'>

原来,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}

编码实践中,虽然在某些情况下集合是无可替代的,但集合的使用频率是“四大金刚”中最低的,我们这里不展开讨论,只说说字典的使用技巧。

2.1 判断一个键是否存在于字典中

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

>>> a = dict({'x':1, 'y':2, 'z':3})
>>> 'x' in a
True
>>> 'v' in a
False

2.2 向字典中添加一个新键或更新键值

很多人喜欢用对字典的一个键赋值的方法,实现向字典中添加一个新键或更新键值。

>>> a = dict()
>>> a['name'] = 'xufive'
>>> a
{'name': 'xufive'}

我不推荐这样的方式,使用update()才更有仪式感,还可以一次添加或修改多个键。

>>> a = dict()
>>> a.update({'name':'xufive', 'gender':'男'})
>>> a
{'name': 'xufive', 'gender': '男'}

2.3 从字典中获取一个键值

a[‘age’]是最常用的方式,但是也还会遇到键不存在的异常。下面的方法值得推荐。

>>> a.get('age', 18)
18

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', '男')]

2.5 遍历字典

遍历字典的时候,很多同学或写成遍历字典的keys()。其实,不需要这么麻烦,可以像下面这样直接遍历。

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

3. 圆括号

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

3.1 必入之浅坑

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

>>> a = (3, 4)
>>> a[0] = 5
Traceback (most recent call last):
  File "<pyshell#14>", line 1, in <module>
    a[0] = 5
TypeError: 'tuple' object does not support item assignment

3.2 必入之深坑

我们一起来看一下下面这段代码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 given

分明只提供了1个参数,却提示说给出了6个参数,为什么呢?

原来,元组初始化时,如果只有单个参数,则必须在单个参数之后增加一个逗号(,),否则,初始化结果仅返回原参数。

>>> a = (5)
>>> a
5
>>> type(a)
<class 'int'>
>>> b = ('xyz')
>>> b
'xyz'
>>> type(b)
<class 'str'>
>>> a, b = (5,), ('xyz',)
>>> a, b
((5,), ('xyz',))
>>> type(a), type(b)
(<class 'tuple'>, <class 'tuple'>)

3.3 单星号解包元组

格式化输出字符串时,下面也许是很多人的写法。

>>> args = (95,99,100)
>>> '%s:语文%d分,数学%d分,英语%d分'%('天元浪子', args[0], args[1], args[2])
'天元浪子:语文95分,数学99分,英语100分'

正确固然正确,但不够精彩。满分写法应该是这样的。

>>> args = (95,99,100)
>>> '%s:语文%d分,数学%d分,英语%d分'%('天元浪子', *args)
'天元浪子:语文95分,数学99分,英语100分'

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 <module>
    s = {1,'x',[3,4,5]}
TypeError: unhashable type: 'list'

我们可以将元组加到集合中,但列表不行,因为列表是不可哈希(unhashable)的。理解这一点并不困难:列表元素可以被动态改变,所以没有一个固定不变的哈希值——这与集合要求的元素唯一性冲突;而元组的元素被禁止更新,其哈希值在整个生命周期都不会变化,因此可以成为集合的元素。

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


作者:医生也来编个程

原文链接:https://www.jianshu.com/p/342789a436bb

  • 【留下美好印记】
    赞赏支持
登录 后发表评论
+ 关注

热门文章

    最新讲堂

      • 推荐阅读
      • 换一换
          • “好多QA转PM,因为QA(的地位)始终是要低一些”“我现在做的事情跟几年前没有区别”“资深QA在项目上做的事情新来的毕业生也能做”上面的话你是不是也有同感?我相信大部分人会这么认为,因为这些表面上看起来的确是这样的!那么,软件测试人员或者说QA真的有这么惨淡吗?对于开篇引用的几句话,我们一一来分析一下。测试工作的价值不容怀疑“好多QA转PM,因为QA(的地位)始终是要低一些”说这话是没有看到QA所做工作带来的价值。相反的,我认为QA之所以可以转PM是QA工作过程中获得的锻炼挺多的,不仅可以转PM,可以转PO,技术型的QA还可以转Dev。其实,QA和PM并没有地位高低之分,只是分工和职责不一样...
            0 0 2140
            分享
          • 课程背景大家好,今天,我给大家带来的分享是:《测试工程师需要掌握的核心基础——如何设计测试用例》。随着科技的快速发展,越来越多的信息技术产品进入了我们的生活,给我们的生活带来巨大便利。而这些便利的背后,就是一款款经过测试的软件、硬件产品。我们——测试工程师——作为这些产品的质量守护者,在其中的作用不言而喻。很多次血淋淋的事故都在告诉着我们测试质量的重要性。当年红极一时的FPS游戏「CSonline」因为一个小小的bug,导致游戏最终走向破产;某券商交易系统因为一个小小的bug,致多名客户透支十余亿元……通过这些例子,我们看到了测试的重要性,而如何能让我们我们负责的产品(这里主要指的是软件产品)...
            0 0 48
            分享
          •   在过去的二十五年里,世界发生了翻天覆地的变化,日本已经停止使用一种奇特的指标来衡量列车上的拥挤程度:在车厢里阅读报纸或杂志的难易程度。做出这一决定的原因很容易理解,现在大多数人在通勤时都盯着手机,而不是报纸。  据《The Reg》报道,日本国土交通省定期报告该国主要大都市地区的列车拥堵率。到目前为止,该部门一直使用下面的插图来显示列车的繁忙程度。  最不拥堵等级(100%)是指在列车满员时,旅客仍可坐在座位上、抓紧带子或握住车门附近的支柱。  在 150% 的情况下,人们可以轻松地打开报纸阅读,而在 180% 的情况下,虽然也可以这样做,但要折叠报纸则需要费一番功夫。  接下来是 200...
            0 0 183
            分享
          •       沐沐在性能测试过程中,主要使用的是JMeter,但是不管性能测试采用什么工具,都需要在性能测试执行过程中监控服务器资源情况,去分析性能瓶颈。本文将主要介绍一下top和htop命令。top:为linux自带的命令,能够实时监控系统给的运行状态,top命令执行后如下截图:load average:系统的运行队列的平均利用率,也可以认为是可运行进程的平均数。三个值分别表示在最后1分钟、5分钟、15分钟的平均负载值。例如在单核CPU的load average的值为1时表示满负荷状态。同理在多核CPU中满负载的load average的值是1*cpu核数。%Cp...
            2 0 3694
            分享
          • 又属于一篇普及文,希望自己在被各种技术吸引的同时,能时常来整理和总结软件测试最基本的知识。从刚工作时接触的第一个缺陷管理工具禅道,到redmine、JIRA、bugzilla,再到现在的QC,当然还有其它种的开源的或商业的缺陷管理工具,它们的本质是一样的,就是来管理缺陷的生命周期。其实,你理解任意的一款工具,其它的工具也一定能无师自通。这不谈某款工具,单把它本质的一些东西抽离出来与大家分享。Bug的属性Bug重现环境这个应该是我们重现bug的一个前提,如果没有这个前提,我们可能会无法重现问题,或者跟本就无从下手。操作系统这个是一般软件运行的一大前提,基本上所有的软件都依赖于操作系统之上的,对于...
            0 0 1397
            分享
      • 51testing软件测试圈微信