• 元组-不仅仅是不可变的列表


    可变的元组

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

    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。

  • 相关阅读:
    SQLServer数据库中开启CDC导致“事务日志空间被占满,原因为REPLICATION”的原因分析和解决办法
    译:SQL Server的Missing index DMV的 bug可能会使你失去理智---慎重看待缺失索引DMV中的信息
    SQLServer中间接实现函数索引或者Hash索引
    MySQL缓存分类和配置
    MySQL系统变量配置基础
    MySQL索引统计信息更新相关的参数
    Sql Server优化---统计信息维护策略
    SQL Server 用角色(Role)管理数据库权限
    sp_executesql 或者 EXECUTE 执行动态sql的权限问题
    关于T-SQL重编译那点事,内联函数和表值函数在编译生成执行计划的区别
  • 原文地址:https://www.cnblogs.com/welan/p/9419828.html
Copyright © 2020-2023  润新知