• 《流畅的python》阅读笔记 - 第二章:数据结构


    内置序列类型概览

    在《算法》一书中,数组,链表称为数据结构.
    ,队列,称为数据类型,在《流畅的python》第二章中,首先介绍了python几种内置(即不用程序员实现,python自带)的序列类型:
    在这里插入图片描述《流畅的python》中列图示了可变和不可变序列的差异,在我看来,可变数据多了一些可以操作数据的方法,增删,修改值等.list列表是最基础的可变序列,类似C语言的数组,只是它更灵活一些,它是容器序列,存放的元素数据类型可以是不一样的.

    列表推导和生成器表达式

    列表可以用列表推导这种方法来快速构造一个列表,而生成器表达式可以创建其它任何类型的序列.

    symbols = '!@#$%^^&*()_+'
    codes = [ord(symbol) for symbol in symbols]
    print(codes)
    
    • 1
    • 2
    • 3

    ord(parm)将parm转换成数值,这个数值是它对应的的Unicode码位,这里参数是一个字符,所以转换后是一个列表,user_list = [func() for n in N] 这是一个列表生成器,它方便的生成一个列表.第一章初有涉及.其中列表中的 n 是一个局部变量,所以不用担心修改到其他变量.详细见《流畅的python》 2.2.1

    如果把列表推导的[]改为 (),则列表推导变为生成器表达式:

    tuple(ord(symbol) for symbol in symbols)
    
    • 1

    用法类似,区别在于,列表推导会建立一个完整的列表,而生成器会一个一个产出,程序可以逐个操作它们.我能想到的用法是,对于一个列表,生成到某一个值以后,程序就不需要继续生成了,那么生成器表达式是更好的.但是我并没有通过代码验证.

    colors = ['black','white']
    sizes = ['S','M','L']
    for tshirt in ('%s %s'%(c ,s) for c in colors for s in sizes):
        print(tshirt)
    
    • 1
    • 2
    • 3
    • 4

    这是书的源程序(实例2-6),它的输出为:

    black S
    black M
    black L
    white S
    white M
    white L
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    我做了一个小练习,加入一行判断的代码,让其打印出white S后就不再输出:

    colors = ['black','white']
    sizes = ['S','M','L']
    for tshirt in ('%s %s'%(c ,s) for c in colors for s in sizes):
        print(tshirt[:5],tshirt[-1])
        if tshirt[:5] == 'white' and tshirt[-1] == 'S':
            break
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    它的输出为:

    black S
    black M
    black L
    white S
    
    • 1
    • 2
    • 3
    • 4

    可以看到,少打印的最后两行,for循环下print(tshirt[:5],tshirt[-1])无法用c,s来表示,只能用tshirt,我想是前文作用域的原因,如果你不理解中括号里面的:5-1,请查看python列表相关的内容.

    元祖不仅仅是不可变的列表 这小节指出:元组不只是存放一个值,还存放了这个值的位置,.2.25小节有具体的对比,不过我依旧没有看出来元组和不可以被改变的列表有什么不同…

    具名元组指的是元素拥有名字,即是可以给元组里面各个元素命名,然后通过其名字来访问它

    from collections import namedtuple
    City = namedtuple('City','name country population coordinates')
    tokyo = City('Tokyo','JP',36.993,(35.689722,139.691667))
    print(tokyo)
    print(tokyo.name)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    它的输出:

    City(name='Tokyo', country='JP', population=36.993, coordinates=(35.689722, 139.691667))
    Tokyo
    
    • 1
    • 2

    City = namedtuple('City','name country population coordinates')看起来有点奇怪,它的第二个参数不是第一章那样的元组,而是字符串,测试效果来看,使用字符串也是可以的,只要一一对于即可,书中指明:“后者可以是由数个字符串组成的可迭代对象,或者是由空格分隔开的字段名组成的字符串.”
    print(tokyo.name) 通过名字来访问数组的元素,这样比通过位置来访问更具可读性
    此外,还可以使用 namedtuple._asdict()格式化输出具名元组:

    from collections import namedtuple
    City = namedtuple('City','name country population coordinates')
    tokyo = City('Tokyo','JP',36.993,(35.689722,139.691667))
    print(tokyo._asdict())
    
    • 1
    • 2
    • 3
    • 4

    它的输出:

    {'name': 'Tokyo', 'country': 'JP', 'population': 36.993, 'coordinates': (35.689722, 139.691667)}
    
    
    • 1
    • 2

    切片

    一个长度为N(N>x)的列表,user_list[:x],```user_list[x:]``,第一个是[0,x),第二个是[x,N-1],这就是切片和区间会忽略最后一个元素的原因.

    序列的增量赋值

    l = [1,2,3]  #一个列表 l
    t = (1,2,3)  #一个元组 t
    
    l *= 2       #每一个元素都乘2
    t *= 2       #每一个元素都乘2
    
    print(l,t)      
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    它的输出:

    [1, 2, 3, 1, 2, 3] (1, 2, 3, 1, 2, 3)
    
    • 1

    在这段程序中,每个序列都被扩展了,但是如果你使用id()来观察它们各自的位置信息,可以发现,列表的首地址没有改变,但是元组的首地址已经改变了.所以对元组的操作会更加消耗时间.本小节还提到了列表 += 的谜题,在平时中避免使用即可.

    list.sort方法和内置函数sorted

    list.sortlist.sorted都是排序列表(默认小在前,大在后,reverse 参数可以改为 True,这样就会反过来排序),区别在于,sort() 是原地排序,使用这个方法后,list列表的值会改变,它会放回None,而sorted()则在不改变原来列表的情况下,新建预一个排序后的列表,可以使用python的列表推导来生成一个随机的列表,并测试他们的排序,sorted()可自行实现:

    import random
    
    l = [random.randint(0,100) for i in range(20)] #在0-99之间生成20个随机数,存放在 l 中
    print("初始值",l)
    l.sort()
    print("排序后",l)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    输出:

    初始值 [25, 39, 35, 8, 37, 60, 43, 44, 84, 48, 73, 11, 47, 46, 26, 66, 85, 58, 68, 74]
    排序后 [8, 11, 25, 26, 35, 37, 39, 43, 44, 46, 47, 48, 58, 60, 66, 68, 73, 74, 84, 85]
    
    • 1
    • 2

    当列表不是首选时

    列表比较灵活,但是如果数值是统一的,直接使用数组会更加的高效,如果需要频繁的对队列先进先出处理,qeque则更加合适,所以程序员可以了解各种数据结构的优缺点,在设计程序的时候可以做到更优.
    array.array 元素只能是数字,没有列表灵活但是更加的高效,包含.pop(),.insert,.exted,以及操作文件的.frombytes(),.tofile.pickle模块的pickle.dump()方法接近array.tofile(),不过他可以处理几乎所有的内置数据类型.在Python 3.4版本,数组类型就不支持就地排序了,需要新建立一个数组来存放排序后的值.

    numbers = array.array('h',[-2,-1,0,1,2])  #创建一个数组
    
    • 1

    这里数组又2个参数,第一个h表示用 int 类型创建数组:

    CodeC TypePython TypeMin bytes
    bsigned charint1
    Bunsigned charint1
    uPy_UNICODEUnicode2
    hsignedshort int2
    Hunsigned shortint2
    isigned intint2
    Iunsigned intint2
    lsigned longint4
    Lunsigned longint4
    ffloatfloat4
    ddoublefloat8

    表格参考:Python Array

    矩阵的计算,建议使用 NumPySciPy库.注意,这2个库都是第三方库,所以你在使用以下代码,需要确保已经安装了Numpy库.

    imoprt numpy
    
    • 1

    如果使用list来做队列是可以的,但是collections.deque这个类更加的合适,可以理解这个类是针对队列设计的.‘‘collections.deque 类(双向队列)是一个线程安全、可以快速从两端添加或者删除元素的数据类型。’’

  • 相关阅读:
    C++ Reference: Standard C++ Library reference: C Library: cwchar: wcschr
    VM16Pro的Win10虚拟机安装Linux子系统Kali
    JUC源码学习笔记8——ConcurrentHashMap源码分析1 如何实现低粒度锁的插入,如何实现统计元素个数,如何实现并发扩容迁移
    uniapp pc端和移动端列表上拉刷新加载分页
    陆游只爱前妻唐婉,深情大渣男太虐了
    算法·每日一题(详解+多解)-- day15
    使用Jetson AGX Orin进行口罩识别
    计算机网络常见面试题
    Spring Cloud Alibaba Sentinel 初体验
    ThreadLocal InheritableThreadLocal TransmittableThreadLocal简单使用
  • 原文地址:https://blog.csdn.net/qq_17351161/article/details/127840214