zoukankan      html  css  js  c++  java
  • 元组-不仅仅是不可变的列表

    可变的元组

    如果熟悉列表的话一定对元组不陌生,一样是容器序列,但是列表确实可变序列,确实不可变序列,因此不少人说元组是不可变的列表。那么来看一下元组究竟能不能变

    tup = (1, 2, 3, [4, 5])
    tup[3] += [6, 7]

    如果执行这个操作将会出现什么

    TypeError: 'tuple' object does not support item assignment

    而tpl[3].extend[6,7 ]却不会出错

    结果报错

    但是当我们打印tup时却又发现

    (1, 2, 3,[4, 5, 6])

    这是因为tup元组在下标为3的位置其实是对列表[4, 5]所在内存空间的引用,你也可以理解为是一个指向内存中的指针,当你对tpl[3]进行“+= [ 6, 7 ]”操作的时候其实是对[4, 5]列表对象进行“.extend([6, 7])”操作,所以操作成功。

    记录:

    元组其实是对数据的记录:元组中的每个元素都存放了记录中一个字段的数据,外加这个字段的位置。正是这个位置信息给数据赋予了意义。

    来看下面例子

    >>> lax_coordinates = (33.9425, -118.408056) ➊
    >>> city, year, pop, chg, area = ('Tokyo', 2003, 32450, 0.66, 8014) ➋
    >>> traveler_ids = [('USA', '31195855'), ('BRA', 'CE342567'), ➌
    ... ('ESP', 'XDA205856')]
    >>> for passport in sorted(traveler_ids): ➍
    ... print('%s/%s' % passport) ➎
    ...
    BRA/CE342567
    ESP/XDA205856
    USA/31195855
    >>> for country, _ in traveler_ids: ➏
    ... print(country)
    ...
    USA
    BRA
    ESP

    ❶ 洛杉矶国际机场的经纬度。
    ❷ 东京市的一些信息:市名、年份、人口(单位:百万)、人口变化(单位:百分比)和面积(单位:平方千米)。
    ❸ 一个元组列表,元组的形式为 (country_code,passport_number)。
    ❹ 在迭代的过程中,passport 变量被绑定到每个元组上。
    ❺ % 格式运算符能被匹配到对应的元组元素上。
    ❻ for 循环可以分别提取元组里的元素,也叫作拆包(unpacking)。因为元组中第二个元素对我们没有什么用,所以它赋值给“_”占位符。
    元组拆包

    就像 ➋中的city, year, pop, chg, area = ('Tokyo', 2003, 32450, 0.66, 8014),只要这一条表达式就可以将一条记录赋值给多个变量,同样('%s/%s' % passport) 也是对元组拆包的应用。元组拆包也有他的规矩,那就是可迭代的对象(元组)的元素数量必须要接受这些元素的空档数一致。除非用“ * ”来接受多余的元素。

    >>> lax_coordinates = (33.9425, -118.408056)
    >>> latitude, longitude = lax_coordinates # 元组拆包
    >>> latitude
    33.9425
    >>> longitude
    -118.408056

    优雅的元组拆包

    实现变量值的互换

    a, b = b, a

    元组拆包在冒泡排序中的应用

    def bubbleSort(alist):
        for passnum in range(len(alist)-1, 0, -1):
            for i in range(passnum):
                if alist[i]>alist[i+1]:
    #                 temp = alist[i]
    #                 alist[i] = alist[i+1]
    #                 alist[i+1] = temp
                    alist[i+1],alist[i] = alist[i], alist[i+1]  #这就是元组拆包的优秀
                    
    alist = [54,26,93,17,77,31.0,31,44,55,20]
    bubbleSort(alist)
    print(alist)

    使用“*”

    (1)可以用 * 运算符把一个可迭代对象拆开作为函数的参数:

    >>> divmod(20, 8)
    (2, 4)
    >>> t = (20, 8)
    >>> divmod(*t)
    (2, 4)
    >>> quotient, remainder = divmod(*t)
    >>> quotient, remainder
    (2, 4)

    (2)上面说用*来接受多余的元素,在写函数时,我们也经常用*arg来获取不确定数量的元素

    >>> a, b, *rest = range(5)
    >>> a, b, rest
    (0, 1, [2, 3, 4])
    >>> a, b, *rest = range(3)
    >>> a, b, rest
    (0, 1, [2])
    >>> a, b, *rest = range(2)
    >>> a, b, rest
    (0, 1, [])

    (3)也可以出现在拆包中的任何位置

    >>> a, *body, c, d = range(5)
    >>> a, body, c, d
    (0, [1, 2], 3, 4)
    >>> *head, b, c, d = range(5)
    >>> head, b, c, d
    ([0, 1], 2, 3, 4)

     小知识

    上面第一节说到,元组的不可变性是相对的,即我们可以改变元组内对其他对象的引用,但是我们知道,在可变序容器列表中,我们可以使用“*+”,或者“+=”,来改变当前列表中的元素,那么对于不可变容器序列元组呢?

    来看下面例子:

     1 >>> l = [1, 2, 3]
     2 >>> id(l)
     3 4311953800 4 >>> l *= 2
     5 >>> l
     6 [1, 2, 3, 1, 2, 3]
     7 >>> id(l)
     8 4311953800 9 >>> t = (1, 2, 3)
    10 >>> id(t)
    11 431268156812 >>> t *= 2
    13 >>> id(t)
    14 4301348296 ➍

    ❶ 刚开始时列表的 ID。
    ❷ 运用增量乘法后,列表的 ID 没变,新元素追加到列表上。
    ❸ 元组最开始的 ID。
    ❹ 运用增量乘法后,新的元组被创建。

    对于列表,在+=和*= 操作之后,id没有发生改变,说明只是在容器中追加元素而已,列表还是原来那个列表,但是对于元组来说,id值却改变了,另外元组本身又是不可变的。其实在进行*= 或者+= 运算时,对不可变序列进行重复拼接操作的话,效率会很低,因为每次都有一个新对象,而解释器需要把原来对象中的元素先复制到新的对象里,然后追加新的元素。也就是  t = t + t, *= 运算符创建一个新元组,然后重新绑定给变量t。

  • 相关阅读:
    初始化ArrayList的两种方法
    MySQL最大连接数设置
    页面按钮的语义和可访问性
    H5+App开发框架汇总
    JS使用模板快速填充HTML控件数据
    Meta标签中的format-detection属性及含义
    java中@Qualifier("string")是什么用法
    MySQL 当记录不存在时insert,当记录存在时update
    美国40岁以上的程序员在干啥
    老程序员都去哪了?
  • 原文地址:https://www.cnblogs.com/welan/p/9419828.html
Copyright © 2011-2022 走看看