zoukankan      html  css  js  c++  java
  • 《流畅的Python》第二部分 数据结构 【序列构成的数组】【字典和集合】【文本和字节序列】

    第二部分 数据结构

    第2章 序列构成的数组

    内置序列类型
    序列类型 序列 特点
    容器序列 list、tuple、collections.deque - 能存放不同类型的数据;
    - 存放的是任意类型的对象的引用
    扁平序列 str、bytes、bytearray、memoryview、array.array - 只能容纳一种类型;
    - 存放的是数据值;
    - 是一段连续的内存空间;
    - 只能存放字符、字节、数值等基础类型
    可变序列与不可变序列

    可变序列:list、bytearray、array.array、collections.deque、memoryview

    不可变序列:tuple、str、bytes

    当改变了不可变序列的内容时,不可变序列的引用也会发生改变(对于str的修改,实质上是添加一个新的str对象,并将该对象的引用传回原实例),故效率低。他们的区别包括:

    • 函数参数传递

      def funForList(l):
          l.append(4) 		#[1, 2, 3] => [1, 2, 3, 4]
      
      def funForStr(str):
          str = str.lower()	#"ABC" => "abc"
      
      t_list = [1, 2, 3]
      funForList(t_list)
      print(t_list)			#[1, 2, 3, 4] 可变序列经过函数改变后本身发生了改变
      
      t_str = "ABC"
      funForStr(t_str)
      print(t_str)			#"ABC"	不可变序列经过函数改变后本身并不会发生了改变
      
    • 对象之间的传递

    list_1 = []
    list_2 = list_1
    list_2.append(1)
    print(list_1)	#list_1 原本的空序列也发生了改变
    
    str_1 = ""
    str_2 = str_1
    str_2 = "abc"
    print(str_1)	#str_1 没有发生改变
    

    具体相关可以通过http://pythontutor.com/的可视化分析工具查看内部的运行流程

    列表推导式

    语法

    [ 输出表达式 循环1 循环2 .... 过滤表达式]

    # 获取20以内的3的倍数
    list_1 = [x for x in range(1, 20) if not x%3]
    print(list_1) #[0, 3, 6, 9, 12, 15, 18]
    
    特点

    不会有变量泄露的问题,列表推导和生成器表达式,以及集合推导、字典推导等,在Python3里都有了自己的局部作用域。

    生成表达式

    特点

    生成器表达式背后遵守了迭代器协议,可以逐个产出元素,而不是先建立一个完整的表,然后再把这个列表传递到某个构造函数里。前面的方式更能节省内存。

    元组

    * 运算符
    1. 拆分可迭代对象

      def numberAdd(a,b):
          return a+b
      print(numberAdd(*(1,2))) #将元组(1,2)拆成1,2两个单独的元素对象作为参数
      # 3
      
    2. 元素拆包用 * 处理剩下的元素,以 * 为前缀的对象可以出现在赋值表达式的任意位置

      a, *b, c = range(5)  #a=0	b=[1, 2, 3]	 c=4	
      
    具名元组

    collections.namedtuple 是一个工厂函数,可以用来构建一个带字段名的元组和一个有名字的类

    Student = collections.namedtuple('Student','name age gender')
    stu = Student('Ming', 18, 'man')
    print(stu)
    # Student(name='Ming', age=18, gender='man')
    
    多维切片和省略
    • 省略(...)是 Ellipsis 对象的别名,Ellipsis 对象是 ellipsis 类的单一实例。

    • 如果 x 是四维数组,x[i, ...] 就是 x[i, :, :, :] 的缩写

    对序列使用 + 和 *
    • 不修改原有操作对象,而是构建一个全新的序列。

    • [[] *3] *4 不等于 [[] *3 for _ in range(4)] ,前者的元素的引用指向的是同一个值

      l1 = [[] *3] *4
      l1[0].append(1)
      print(l1)
      # [[1], [1], [1], [1]]序列
      
    序列的增量赋值
    • a += b,就地相加,效率高

    • a = a+b,先计算 a+b,然后赋值,产生了新的对象,效率较低

    • 对不可变序列进行重复拼接操作,效率会很低(str 是一个意外,因为对字符串做 += 太普遍了,所以Cpython做了相应的优化)

    • 一个谜题

      t = (1, 2, [30, 40])
      t[2] += [50, 60]
      
      # a. t 变成(1, 2, [30, 40, 50, 60])
      # b. 因为tuple不支持对它的元素赋值,所以会抛出TypeError异常
      # c. 以上两个都不是
      # d. a 和 b都是对的
      
      # 正确答案 d
      
      • 三个教训
        • 不要把不可变对象放在元组里面
        • 增量赋值不是原子操作,虽然抛出异常,但还是可能完成操作
        • 查看Python的字节码对了解代码背后的运行机制很有帮助
    bisect 二分查找
    • bisect_left(nums,target,left, right) #找到nums中第一个 大于等于 target的目标位置
    • bisect.insort_left(nums,target,left, right) #将target 插入到该位置(搜索是O(log n), 插入却是O(n))
    • bisect.bisct(nums,target,left,right) #找到nums中第一个 大于 target的目标位置
    • bisect.bisct_right(nums,target,left,right) #同bisct
    • bisect.insort(nums,target,left, right) #将target 插入到该位置(搜索是O(log n), 插入却是O(n))
    • bisect.insort_right(nums,target,left,right) #同bisct
    数组 array
    • array.fromfile 从二进制文件读双精度浮点数,比从文本文件读取的速度快60倍
    • array.tofile 将浮点数写入二进制文件,比以每行一个浮点数的方式写入到文本文件快7倍
    内存视图

    memoryview 是一个内置类,能够让用户在不复制内容的情况下操作同一个数组的不同切片。

    双向队列
    • collections.deque 类是一个线程安全,可以快速从两端添加或者删除元素的数据类型
    • 添加或者删除元素的操作都是原子操作,可以在多线程中安全使用,不需要担心资源锁的问题
    TimSort

    Timsort 是 sorted 和 list.sort 背后的排序算法

    第3章 字典和集合

    collections.abc 模块
    • 该模块中含有 Mapping 和 MutableMapping 抽象基类
    my_dict = {}
    print(isintance(my_dict, abc.Mapping))
    # True
    
    • dict 映射要求映射的键是 可散列的数据类型(对象的内部状态都是不可变的,例如str,bytes,数值类型,元素全部为不可变类型的tuple)
    字典推导
    my_dict = {key: value for key, value in list}
    
    • 当dict 中的键没有找到时:

      • d[k] 找不到该键时,Python会抛出异常

      • 用 d.get(k, default) 代替 d[k],找不到时返回默认值

      • setdefault

        mydict.setdefault(key, []).append(new_value)
        # 等同于下面,但只进行一次查询
        if key not in my_dict:
        	my_dict[key] = []
        my_dict[key].append(new_value)
        
    映射的弹性键查询
    • collections.defaultdict

      设置默认的函数作为default_dactory 创建一个defaultdict

    d = collections.defaultdict(lambda :None)
    print(d[0])
    # None
    
    d = collections.defaultdict(list)
    print(d[0])
    # []
    
    • 特殊方法 __ missing __

      当键没有找到时,系统将调用 __ missing __ 方法,可以自定义类继承 dict 并实现 __ missing __ 方法

    字典的变种
    • collections.OrderedDict #添加键的时候保持顺序

    • collections.ChainMap #可以容纳不同的映射对象,键查找时,将在不同的映射对象中之一查找直到被找到

    • collections.Counter #给键准备计数器

      ct = collections.Counter("aabbcc")
      # Counter({'a':2, 'b':2, 'c':2})
      ct.update('aaazzz')
      # Counter({'a':5, 'z':3, 'b':2, 'c':2})
      
    不可变映射类型

    types.MappingProxyType

    • 给这个类添加映射,返回一个只读的映射视图,但当原映射视图有变动时,该视图也将变动,且不能直接在只读映射视图上做修改
    d = {1:'A'}
    d_proxy = types.MappingProxyType(d)
    
    print(d_proxy)
    # mappingproxy({1:'A'})
    
    d[2] = 'B'
    print(d_proxy)
    # mappingproxy({1:'A', 2:'B'})
    
    d_proxy[2] = 'C'
    # TypeError:..........
    
    集合
    运算符 方法 描述
    s & z s. __ and __ (z) s 和 z 的交集
    s | z s. __ or __ (z) s 和 z 的并集
    s - z s. __ sub __ (z) s 和 z 的差集
    s ^ z s. __ xor __ (z) s 和 z 的对称差集
    e in s s. __ contains __ (e) s 是否包含元素 e
    s <= z s. __ le __ (z) s 是否为 z 的子集
    s < z s. __ lt __ (z) s 是否为 z 的真子集
    s >= z s. __ ge __ (z) s 是否为 z 的父级
    s > z s. __ gt __ (z) s 是否为 z 的真父级
    dict 和 set 特点
    • dict 键或 set 元素必须是可散列的
    • 字典、集合在内存上的开销巨大
    • dict 键或 set 元素查询很快
    • dict 键或 set 元素的次序取决于添加顺序
    • 往dict 或 set 添加新键可能改变已有键的顺序

    第4章 文本和字节序列

    字符、字节
    • Python3 中采用 Unicode字符标准,以及 Utf-8 编码标准
    • bytes 或 bytearray 对象中各个元素是介于0~255之间的整数
    cafe = bytes('café',encoding='utf-8')
    print(cafe)
    # b'cafxc3xa9'
    print(cafe[0])
    # 99
    print(cafe[:1])
    # b'c'
    # cafe[0] 获取的是一个整数,而cafe[:1]返回的是一个长度为1的bytes对象
    
    结构体和内存视图

    struct模块能处理bytes,bytearray和memoryview对象。

    编码

    在文件顶部添加一个神奇的coding注释

    # coding: cp1252
    
    解码

    解码过程中可能出现三种错误

    • unicodedecodeerror(把二进制序列转化为字符串)
    • unicodeencodeerror(把字符串转化为二进制序列)
    • syntaxerror
    处理文本文件
    Unicode三明治
    • 尽早把输入的字节序列编码成字符串
    • 业务逻辑处理是,不能进行编码或解码
    • 尽量晚地把字符串编码成字节序列
  • 相关阅读:
    C# winform 获取标题栏,状态栏,菜单栏的高度
    <转载>OleDb操作Access数据库:新增记录时获取自动编号的主键值
    《名利场》:微软 “ 失落的十年”
    Lisp的永恒之道(转)
    Google Earth KML数据格式转换成Shp数据格式(转)
    【转】ArcGIS投影转换与坐标转换
    利用Mono.Cecil动态修改程序集来破解商业组件(仅用于研究学习)
    C# mouseDoubleClick与DoubleClick的关系
    ACCESS通用操作数据类
    VS2010单元测试入门实践教程
  • 原文地址:https://www.cnblogs.com/betternow/p/13591480.html
Copyright © 2011-2022 走看看