2.2. tuple及其操作¶
tuple(元组)是Python语言的一种基本数据类型,与列表型对象相似,但是列表中的每一项都是可以改写的,元组却不能改写。因此, 元组可以看作是“只读的”列表。元组的只读属性,意味着列表的大多数操作函数元组都不支持!
本节教程我们了解Python的元组型对象及其操作。
2.2.1. 定义tuple的方法¶
tuple(元组)使用“()”将各项扩在一起,而列表使用的“[]”,切勿混淆!
使用USB数据项将BlueFi与电脑连接,并打开MU编辑器, 点击“串口”按钮,并按“ctrl+C”让BlueFi进入REPL模式,然后在“>>>”提示符后输入以下脚本代码并按“Enter”键执行对应代码,观察 执行结果。定义一个元组:
1 2 3 4 | >>> c1 = (120, 120, 10, 'RED') >>> c1 (120, 120, 10, 'RED') >>> |
这里定义一个包含有4个项目的元组c1,前三项都是数值,最后一项是字符串。这说明:元组跟列表相同,其中的数据项不必是相同类型的。 那么,我们自然会猜想:能否将一个列表转换为元组呢?答案是“可以的”!
将列表转换为元组的方法: obj_tuple = tuple( list )。我们可以用下面的代码来验证:
1 2 3 4 | >>> l = [0,2,4,6,8] >>> t = tuple(l) >>> t (0, 2, 4, 6, 8) |
首先使用“obj_list = [x, x, ..]”定义一个列表,obj_list是可以改写的,然后使用“obj_tuple = tuple( obj_list )”将列表 转换为元组,即只读的列表。
此时,你是否会猜想:元组可以转换为列表吗?答案仍然是“可以的”!譬如,接着前例执行下面代码:
1 2 3 | >>> lt = list(t) >>> lt [0, 2, 4, 6, 8] |
变量lt是列表类型,将这个变量打印到屏幕上时使用“[]”将其中的数据项扩起来。当然,我们可以使用Python内置的函数“type()”来查询 某个变量的类型,用下面的代码,我们分别查询变量lt和t的类型:
1 2 3 4 5 | >>> type(lt) <class 'list'> >>> type(t) <class 'tuple'> >>> |
显然,变量lt和t分别为列表型和元组型。
注意
元组:只读的列表
- 使用“tuple(obj_list)”将列表对象转换为元组,元组的各项与原列表各项完全相同,但元组的各项不能再改写
- 使用“list(obj_tuple)”将元组对象转换为列表,列表的各项与原元组各项完全相同,但列表的各项允许改写
2.2.2. 何时需要tuple?¶
现在看起来元组与列表并无区别,只是元组的各项不允许改写,元组是只读的而已。我们既然有了列表,为什么还需要元组呢?
这是一个非常好的问题!
元组是只读的列表,既然列表可以搞定一切,何需元组?BlueFi的颜色传感器能够为我们提供三基色和亮度共4个光学通道的值,基于 这些值我们可以编写颜色识别算法感知当前对象的颜色;BlueFi的加速度传感器能够给出x-、y-、z-方向的加速度分量。BlueFi的 多种传感器输出的测量结果都包含有多个分量,将这些结果作为一个整体传递给一个接口函数时,最佳的数据类型就是使用元组!虽然 可以使用列表型,但列表不是最佳选择。
使用元组型变量来表示传感器输出的多分量数据,其意义在于元组的只读属性。对于传感器输出的结果,我们只能使用他们,不允许修改, 这样可以避免某些程序bug试图修改这些结果时会自动报错,因为这些代码违反元组型变量的使用规则。
现在我们来看一看BlueFi的传感器返回的数据,使用以下代码
1 2 3 4 5 6 | >>> from hiibot_bluefi.sensors import Sensors >>> sensors = Sensors() >>> sensors.color (1344, 1486, 957, 3432) >>> sensors.acceleration (-0.671186, -0.595813, -9.56889) |
如果你不记得“Sensors”类的各个接口名称,可以在REPL模式下输入“sensors.”并按“Tab”键即可自动列举“Sensors”类的全部接口 名称。上面的代码中,我们看到颜色传感器“sensors.color”返回的结果是一个四项数据的元组(前三项分别是RGB三基色的分量,最后一项是亮度分量), 加速度传感器“sensors.acceleration”返回的结果是一个三项数据的元组(分别是x-、y-、z-方向的加速度分量)。
2.2.3. 访问tuple的某一项¶
始终记住:tuple是只读的。访问时也只能使用只读的方法,我们将BlueFi的颜色传感器输入结果的最后一项取出来赋给变量brightness:
1 2 3 4 5 6 7 | >>> from hiibot_bluefi.sensors import Sensors >>> sensors = Sensors() >>> sensors.color (1344, 1486, 957, 3432) >>> brightness = sensors.color[3] >>> brightness 3432 |
与列表相似,使用“obj_tuple[index]”来访问元组的某一项。
下面我们使用颜色传感器的亮度通道值来控制白光灯的亮度: 当环境光很亮的时候,白光灯亮度变暗;反之,环境光很暗时,白光灯亮度变得很亮。 这里环境光亮度从哪里获取呢?颜色传感器的亮度分量,即“sensor.color[3]”。示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 | import time from hiibot_bluefi.basedio import PWMLED from hiibot_bluefi.sensors import Sensors sensors = Sensors() led = PWMLED() while True: c = sensors.color[3] print(c) led.white = 65535 - c time.sleep(0.1) |
注意,元组与列表一样都是从第0项开始。
2.2.4. 访问tuple的某些项(切片操作)¶
这一点几乎与列表又是完全相同,支持以下几种切片:
- [index],取第index项,index从0开始
- [:index],截取第0~index-1项,即前index项组成的子元组
- [n:m],截取第n~m-1项,共m-n项,结果是一个子元组
- [index:],截取第index~最后一项,结果是一个子元组
我们只取BlueFi颜色传感器给出的RGB三基色分量时,可以使用“rgb = sensors.color[:3]”,变量rgb是一个三项元组。
2.2.5. tuple嵌套¶
tuple(元组)允许包含tuple,即元组的嵌套。定义嵌套的元组使用“(())”嵌套即可,如下面示例:
1 2 3 4 5 6 7 8 9 | >>> t = ((262, 0.2), (294,0.2)) >>> t ((262, 0.2), (294, 0.2)) >>> t[0] (262, 0.2) >>> t[0][0] 262 >>> t[0][1] 0.2 |
嵌套元组的访问遵循“[index1][index2]..”规则。事实上,如果使用中间变量,嵌套元组的访问几乎没有任何特殊之处。 我们用下面示例来了解嵌套元组的访问:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | import time import board import pulseio import digitalio a4_quarter = (440, 0.25) c4_half = (261, 0.5) notes = (a4_quarter, c4_half) def play_note(note): if note[0] != 0: pwm = pulseio.PWMOut(board.SPEAKER, duty_cycle = 0, frequency=note[0]) pwm.duty_cycle = 0x7FFF time.sleep(note[1]) if note[0] != 0: pwm.deinit() enSpk = digitalio.DigitalInOut(board.SPEAKER_ENABLE) enSpk.switch_to_output() enSpk.value = True play_note(notes[0]) play_note(notes[1]) |
在函数play_note中,输入参数note是一个两项元组,第一项是基本音调的频率,第二项是播放该音调的时长。
2.2.6. tuple的遍历¶
元组是只读的列表,遍历元组本身就是逐项读取元组,这是自然不过的事儿。遍历元组仍然使用
- for term in tuple
程序结构。下面我们完善前一个示例,让喇叭播放一个简单的旋律,从而了解元组的遍历效果。示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | import time import board import pulseio import digitalio c4_half = (261, 0.5) d4_quarter = (293, 0.25) e4_half = (329, 0.5) f4_half = (349, 0.5) g4_quarter = (392, 0.25) a4_quarter = (440, 0.25) b4_half = (493, 0.5) notes = (c4_half, d4_quarter, e4_half, g4_quarter, a4_quarter, b4_half) def play_note(note): if note[0] != 0: pwm = pulseio.PWMOut(board.SPEAKER, duty_cycle = 0, frequency=note[0]) pwm.duty_cycle = 0x7FFF time.sleep(note[1]) if note[0] != 0: pwm.deinit() enSpk = digitalio.DigitalInOut(board.SPEAKER_ENABLE) enSpk.switch_to_output() enSpk.value = True for i in notes: play_note(i) |
本示例程序的第6~12行代码定义了7个基本音调的频率和播放时长的元组,第9行代码将这些元组定义为一个更大的元组notes。 并在最后两行代码使用“for”程序结构来遍历元组notes,实现简单旋律的播放效果。
根据本示例的启发,你是否能设计出播放“生日快乐”、“两只老虎”或“天上星星亮晶晶”等旋律的Python脚本程序?
总结:
- tuple
- 元组的定义
- tuple( obj_list ):列表转换为元组
- list( obj_tuple ):元组转换为列表
- 访问元组中的某一项
- 访问元组中的某些项:元组切片
- 元组的嵌套及其访问
- 元组的遍历
- 元组的应用