Python基础知识


课程笔记

python相关函数查询

官方API文档

菜鸟教程python

w3school教程python

一.基本元素

变量
  • 变量赋值:
    a="hello world"
  • 变量命名:
    • 字母:a-z, A-Z, 其他语言的字母符号
    • 数字:0-9 (不可以出现在首字符)
    • 下划线:_ (可以单用)
  • 注意事项
    • 在赋值时,变量即被创建,变量的值和类
    型在赋值的时候被确定。
    • 不需要声明(declaration)
    • 变量名大小写敏感:A, a是不同的变量
    • 变量可以被重新赋值
    变量类型
  • 数值类型
    • 整数 Integers: 12 0 -12987 0123 0X1A2 10294L
    大致相当于C语言的 ‘int’ 或 ‘long’
    范围可以非常大(大致无限)
    八进制数以“0” 开始 (0981 是非法的!)
    十六进制以0X开始
    • 浮点数Floating point: 12.03 1E1 -1.54E-21
    相当于C语言的double
    • 复数Complex numbers: 1+3J
    语言原生支持

运算注意事项:
• 操作符和C语言类似,例如 +, -, /, , %
• 幂操作:**

• 优先级和括号的作用相似

  • 逻辑类型
    • 预定义值:True False
    • 数值 0 认为是假,其他值认为是真
    • 操作符:not, and, or

运算注意事项:
• 比较运算获得逻辑值,运算符: <, <=, >, >=,
==, !=

  • 字符串类型
    • 使用函数str, int, float等类型名进行转换
    b=int(a)
    c=flaot(a)
    d=str(a)
    • 字符串的拼接和整数乘法
    a="hello"+"world"
    b="hello"*2
    语句
  • 代码缩进
    • Python语 语 言 的 行 前 空 白 是 有 语 法 意 义 的
    • 在源文件中,应该统一采取一种缩进格式
    缩进进4个空格 ( 推 荐 标 准 )
    缩进2个空格
    缩进1制表符(tab)
    上述缩进不可以混用
    • 连续处于相同缩进层次的语句构成一个语句块(Block)
  • 条件语句
    if 条件:
    elif 条件:
    else:
  • 循环语句(for)
    • 循环语句for
    • range(n)表明从0开始,到n-1(含)。
    s = 0
    for i in range(10): # 0,1,...9
      s += i
    print(s)
  • 循环语句(while)
    s = 0
    i = 0
    while s<10:
      s += i
      i += 1
    print(s)
  • 导入语句
    三种写法:
    from math import *
    # use pi, cos, sin, ...
    from math import cos, sin
    # only use cos, sin
    import math
    # use math.cos, math.sin, ...
  • 定义函数
    • 用def定义函数,可以有参数和返回值
    def double(x):
      return x * 2
    turtle库详解
    python:turtle库详解

python类型

类型

• 标量类型
—— 逻辑类型(bool)
—— 整数(int)、浮点数(float)、复数(complex)
—— 空 类型 型(None)
• 集合类型
—— 字符串(str)
—— 列表(list)
—— 字典(dict)
—— 元组(tuple)
—— 集合(set)
• 自定义类型
—— 类 class

数值类型

• 除法有两种:/, // 后者是整除
—— 7/3 = 2.3333333333333335
—— 7//3 = 2
—— 7.0 // 3.0 = 2.0
• 幂运算允许实数
—— 7 ** 2 = 49
—— 7 ** 0.5 = 2.6457513110645907
• 不同类型的数值运算就高不就低
—— int —— float —— complex

三元操作符

• 表达式

 x if c else y 

相当于

 c? x : y
字符串

• 字符串的进阶操作

'p' in s 

• 下标以0为开始

 s[0] # index: offset 0
 s[2:6] # slice: part of string
 s[:6] 
 s[6:]

• 逆序的下标

 s[-1]
 s[-3:-1]
 s[1:-1]
 s[-3:]

• 步长:begin:end:step

 s[::2]
 s[1::3]
 s[5:1::-1]
 "live"[::-1]
不可修改类型 Immutable

• 数值类型、字符串类型是不可修改类型
—— 后续讲解的元组(tuple)类型也是不可修改类型
• 它们的值是常数,不可以修改
—— 我们并不能把“1”修改为“2”,把“abc”改为“def”;
—— 作为值,它的含义是确定的、不变的。
• 赋值语句(Assignment)是给这些常数的值赋予不同的名称

字符串方法
 s = 'I love Python'
 s.count('on') # 查找子串出现次数
 s.find('ove') # 查找子串首见位置
 s.replace('Python', 'C++') # 替换

 three = '3'
 three.isdigit() # 是否为数字字符?
列表
  • 相关事项
    • 表(或称为列表,广义表)是python最重要
    和常用的容器类
    • 由一系列有序排列的对象构成(Ordered
    collection of objects)~ C语言的数组
    • 异构(Heterogenous),一个列表可以包含
    多种类型的对象。

    r = [1, 2.0, 3, 5] # list的字面构造
    r[1] # 正数下标自首部计数,首部为0
    r[-1] # 负数下标自尾部计数,尾部为-1
    r[1:3] # 前闭后开区间
    w = r + [10, 19] # 连接
    t = [0.0] * 10 # 重复
    len(r)
  • 列表操作

    r = [[9, 8], 2.0, 3, 'word']
    r[0:3] = [1, 2, 5, 6] # 修改片段
    
    r[1:3] = [] # 删除元素
    
    r[1:1] = [ 'new' ] # 赋值语句左右侧都是片段;等价于插入[1, 'new', 6, 'word']
    r[len(r):] = [ 'last' ] # 在尾部插入[1, 'new', 6, 'word', 'last']
  • 列表的方法

    r.insert(0, 'f') # 在0位置增加新元素'f'
    del r[0]
    r.append(9) # 尾部增加元素
    r.sort() # in-place 排序
    r.reverse() # 逆序
  • 判断两个变量是否指向同一对象
    • 利用id函数,返回对象的唯一标志
    • id(x) == id(y) 表明x和y实际上是同一对象
    • x is y

  • 列表推导

    [i for i in range(9)]
    [i*2 for i in range(9)]
    [i for i in range(100) if '4' not in str(i)]

    • 补充
    —— Python 一行语句过长,可以用 \ 续行
    —— 若在括号(花方圆均可)内可以自由换行

    字典
  • 基本事项
    • 字典是一种数据组织方式,它根据 key获得对应的value
    • key称为键,key是无序的,或者说不关注其顺序。
    • value称为值,可以是任意的对象。
    • 字典也称为映射(mapping)、哈希(hash)表、查找表(lookup table)等。

  • 字典操作

    g = {'Tom': 'boy', 'Mary': 'girl'}
    g['Tom'] # 以key为索引
    g.has_key('Mary')
    g['Jack'] = 'boy' # 增加键值对
    del g['Tom'] # 删除键,删除键到值的绑定
    
    h = {'Tom': 12, 'Mary': 'good'}
    'Per' in h # 在键的集合中检测
    h.get('Per', 'unknown') # 如果查找失败则返回缺省值
    h.keys() # 由键组成的列表,顺序不确定
    h.values() # 由值组成的列表,顺序不确定
    h.items() # 顺序同上
    len(h) # 键的数量
    元组
  • 注意事项
    • 与list相同,但不可改变(immutable)
    • 一旦创建,不可修改。(Once created, can’t be changed.)

    t = (1, 3, 2)
    t[1] # 3
    (a, b, c) = t # 元组赋值
    a, b, c # (1, 3, 2)
    集合
  • 注意事项
    • 数学中的集合,无序,不重复(set)
    • 去重的时候很有用

    s = set()
    s = {1, 2, 3}
    s.add(4) # {1,2,3,4}
    s.add(1) # {1,2,3,4}
    t = {1,2}
    # &交集,|并集 - 差集
    s - t # {3,4}
    容器间转换

    • list, set, dict 作为类型名可以实现转换
    —— list(“abc”) = [“a”, “b”, “c”]
    —— set([1,2,2]) = {1,2}

    Python语句

    pass语句

    • pass是一个(占位)空语句,不做任何事情
    • 动因
    —— python利用缩进表达语句块,如果语句块是空的,不写会有错;
    —— 这种情况下,可以写上pass

    for循环语句

    • for可以遍历任意的容器
    —— 对词典遍历的是keys()
    • range(n)是一个内置函数,返回0~n-1的列表
    • range(start, stop, step)

    break语句

    • 跳出最内层的循环
    • python没有直接跳出外层循环的语法手段
    —— 通常会借助额外的flag变量
    —— 异常处理

    continue语句

    • 它结束当前迭代,并跳到下一次迭代开头。即跳过循环体中余下的语句,但不结束循环。
    • 可以用等价的if语句描述

    for/while-else语句

    • 只要不是break跳出循环,就执行else语句
    • 相比C语言减少一个flag变量

    r = [1, 3, 10, 98, -2, 48]
    for i in r:
      if i < 0:
          print('input contains negative value!')
          break
    else:
      print('input is OK')
    exec和eval

    • 动态地编写Python代码,并将其作为语句进
    行执行或作为表达式进行计算
    • 函数exec将字符串作为代码执行
    • eval计算用字符串表示的Python表达式的值,
    并返回结果。
    • 如下代码来创建一个Python计算器

    assert断言语句

    • 要求某些条件得到满足,否则将引发异常
    • 确保程序的参数合理
    • 对于不合理的情况,明确引发异常

    异常处理
  • 完整的异常处理

    try:
      1 / 0
    except NameError:
      print("Unknown variable")         出现异常时执行。。。
    else:
      print("That went well!")             没有出现异常时执行
    finally:
      print("Cleaning up.")             任何情况下都会执行
    函数

    • 函数名:规则与变量名相同
    • 参数列表:调用函数时传递给它的值
    —— 可以由零个,一个或者多个参数组成
    —— 当有多个参数时,各个参数用逗号分隔
    • 函数体:函数被调用时执行的代码
    —— 由一个或多个语句组成
    —— 在执行到末尾或return语句时退出函数
    —— 返回结果
    • 函数调用的形式
    —— 函数名( 参数列表 )
    • 形式参数(名):定义函数时,函数名后面圆括号中的变量。形参只在函数内部有效。
    • 实际参数(值):调用函数时,函数名后面圆括号中的变量。

参数能否修改:总结

• 凡是Immutable类型的参数,传入的对象值不可能修改
• 对于Mutable类型的参数:
—— 若对形参进行赋值,并不能改变传入对象的值
—— 若对形参进行in-place的修改,则该修改也反应在传入的对象上

关键字参数的缺省值

• 可以设定一些参数的缺省值(默认值)
• 如果调用者没有提供,则使用缺失值

def hello(name, greeting="Hello"):

• 允许用户提供任意数量的参数

def sum_of_all(*values):
作用域
  • 注意事项
    • 如果没有局部变量和全局变量同名,可以直接读取全局变量。
    • 如果有一个局部变量与待访问的全局变量同名,则无法直接访问全局变量,因为它被局部变量遮住了。
    • 可以使用关键字 global(nonlocal)修饰变量名,表明和全局(外层)变量关联。
    • Python的函数可以作为返回值
    匿名函数
    • lambda可以用来定义函数
    pow2_a = lambda x: x*x
    def pow2_b(x):
        return x*x
    两者功能相同
    模块
    • 对于稍微大型的程序,代码量较大,不宜
    放在一个文件中
    • 模块可以将代码分散在不同的文件
    主模块
    if __name__ == "__main__":
        do_something()

    文本处理

    字符的分类
    • 数字 digits 01234567890
    • 字母 letter
    大写ABCDEFGHIJKLMNOPQRSTUVWXYZ
    小写 abcdefghijklmnopqrstuvwxyz
    • 空白字符:空格,\t\n\r\v
    • 对应Unicode,上述概念有一定拓展。
    字符串对象方法
  • capitalize() 字符串首字母大写
  • lower() 转为小写
  • upper() 转为大写
  • find(s)/rfind(s) 正向/逆向查找子串s的出现位置
  • count(s) 查找s出现的次数
  • strip() 移除开始和结束的空白
  • lstrip()/rstrip()移除开始/结束的空白
  • replace(s, r) 将子串s替换为r(缺省为全替换,可以仅替换指定次数)
  • isalpha()/isdigit() 是否是字母、数字等……
  • isupper()/Islower() 是否大写小写等….
  • startswith(s)/endswith(s) 是否以s作为字符串的开始或结尾
  • s.split(sep) 将字符串sep作为分隔符,对字符串s进行分解,返回列表
  • sep.join(parts) 将各部分用分隔符sep连接在一起
格式化

• 字符串的格式化有三种方法
• %, format, f-string

  • % 操作符

用法: str % parameter_tuple

"the number is %d" % 30
  • %-format

%c character
%s string conversion via str() prior to formatting
%i signed decimal integer
%d signed decimal integer
%u unsigned decimal integer
%o octal integer
%x hexadecimal integer (lowercase letters)
%X hexadecimal integer (UPPERcase letters)
%e exponential notation (with lowercase ‘e’)
%E exponential notation (with UPPERcase ‘E’)
%f floating point real number
%g the shorter of %f and %e
%G the shorter of %f and %E
* argument specifies width or precision
- left justification
+ display the sign
leave a blank space before a positive number
# add the octal leading zero ( ‘0’ ) or hexadecimal leading ‘0x’or ‘0X’, depending on whether ‘x’ or ‘X’ were used.
0 pad from left with zeros (instead of spaces)
% ‘%%’ leaves you with a single literal ‘%’
(var) mapping variable (dictionary arguments)
m.n. m is the minimum total width and n is the number of digitsto display after the decimal point (if appl.)

name = "John"
age = 23
print("%s is %d years old." % (name, age))
  • str.format方法
    • 原先的用法:’%s %s’ % (‘one’, ‘two’)
    • 目前的用法:’{} {}’.format(‘one’, ‘two’)
    "{0} {1}, you may have won ${2}" .format("Mr.", "Smith",10000)
    'int, {0:5}, in a field of width 5'.format(7)
    ' {0:10.5f}, fixed at 5 decimal places.'.format(3.1415926)
  • f-string
    name = "Eric"
    age = 24
    f"Hello, {name}. You are {age}."
    f-string是python3版本的新语法,是一种表达式。
  • split-join
    • split用于将长字符串进行分解
    • join用于合并短字符串
    • 常见的分隔符号有:\t , ; . - /
    "www.ustb.edu.cn".split(".")
    [ int(i) for i in "166.111.4.80".split(".") ]
    ".".join([ f"{i}" for i in [166, 111, 4, 80] ])
    正则表达式
  • 通配符:匹配任意字符
  • 字符组(类)
    • 字符类 [] 用于匹配一组字符
    • 可以用 [^] 表达不匹配组里面的任意字符
    • Ranges 可以表示一个范围的字符
    —— [1-9] 即 [123456789]
    —— [abcde] 即 [a-e]
    —— [abcde123456789] 即 [a-e1-9]
  • 预定义的字符组

\d 数字 [0-9]
\D 非数字 [^0-9]
\s 空白字符 [ \f\n\r\t\v]
\S 非空白字符 [^ \f\n\r\t\v]
\w 字母数字下划线 [A-Za-z0-9_]
\W 非字母数字下划线 [^A-Za-z0-9_]

  • 锚 Anchors
    • ^ 即行首 beginning of the line,在多行模式下匹配每行的开始位置
    • $ 即行尾 means end of the line,在多行模式下匹配每行的结束位置
    • \A 仅行首
    • \Z 仅行尾
    • \b 匹配单词的边界
    —— 从字母数字到非字母数字的过渡边界,\w\W 或 \W\w
  • 重复指示Repetions
    • 三种 * + ?
    • * 指示其前置内容0+inf次出现,也就是任意多次
    • + 1
    +inf
    • ? 0~1
  • 重复数量的范围指示
    • 可以用 {n,m} 指示范围
    —— {n,m} 表示n~m次
    —— {n} 表示恰好n次 exactly n occurrences
    —— {n,} 表示至少n次 at least n occurrences
    • 示例:
    —— .{0,} 等价于 .*
    —— a{2,} 等价于 aaa*
  • 子表达式
    • 重复指示仅修饰其前面的一个符号,如果
    想表示多个符号,需要对正则表达式进行
    分组,用 ()进行划分,称为子表达式
    • 子表达式作为一个整体被修饰
    —— a* 匹配a的0次货多次出现
    —— abc* 匹配 ab, abc, abcc, abccc, …
    —— (abc)* 匹配 abc, abcabc, abcabcabc, …
    —— (abc){2,3} 匹配 abcabc or abcabcabc

  • • 符号 | 表示匹配该符号前面的或后面的子表达式
    —— (T|Fl)an 匹配 Tan or Flan
    —— ^(From|Subject): 匹配邮件头部
    • 优先级最低,可以用 () 改变
    • 示例:
    —— At(ten|nine)tion 匹配Attention or Atninetion
    —— 不能匹配Atten or ninetion 除非未加括号即Atten|ninetion
  • 转义
    • 很多字符(如“.”)在正则表达式中有特殊含义,如果只代表它原本的字面意义就需要转义,例如“.”仅匹配句点本身。
    —— 目标仅匹配单个句点: .
    —— 在正则表达式层面需要看到: .
    —— 在字符串书写时需要写: “\.”
    • 匹配反斜线
    —— 目标仅匹配单个反斜线:
    —— 在正则表达式层面需要看到: \
    —— 在字符串书写时需要写: “\\“
    • 匹配数字\d
    —— 在正则表达式层面需要看到: \d
    —— 在字符串书写时需要写: “\d”

• 匹配国内电话号码:\d{3}‐\d{8}|\d{4}‐\d{7}
—— 如 0511-4405222 或 021-87888822
• 腾讯QQ号:[1‐9][0‐9]{4,}
—— 腾讯QQ号从10000开始
• 中国邮政编码:[1‐9]\d{5}(?!\d)
—— 中国邮政编码为6位数字
• 匹配身份证:\d{15}|\d{18}
—— 中国的身份证为15位或18位
• 匹配ip地址:\d+.\d+.\d+.\d+
—— 提取ip地址时有用

  • 子表达式的引用
    • \n 此处n是一个数字,表示第n个子表达式的值。子表达式的序号按左括号计数。
    • 例如:
    —— (.+) \1 匹配 55 55,或者the the
    • 可以给子表达式予以命名
    • (?P…)
    • (?P=name)

    Python的正则表达式模块

    • 模块导入 import re
    • 匹配:re.match() 查找字符串的开始部分是否匹配,不向后查找(类似字符串startswith)
    • 查找:re.search() 查找是否存在匹配(类似字符串find)
    • 替换:re.sub() 替换正则表达式(类似字符串replace)

  • match的用例

    s = "2019‐03‐20 is a rainy day"
    pat = "\\d‐\\d‐\\d"
    m = re.match(pat, s)
    
    m.start()
    m.end()
    m.group()  #返回匹配对象(Match),有start, end, group方法
  • search的用例

    s = "It is reported that 2019‐03‐20 is a rainyday."
    pat = "\\d‐\\d‐\\d"
    m = re.search(pat, s)
    m.start()
    m.end()
    m.group() 
  • 多次查找findall/finditer

    s = """You smiled and talked to me of nothing and I felt that for this I had been waiting long."
    re.findall("\\b(\\w+ed)\\b", s)
    re.finditer(...) # 类似,但返回一个个Match对象
  • 替换sub
    • 04/30/2018 转换为 2018-04-30
    • 利用re.sub

    import re
    print re.sub("([0‐9]{2})/([0‐9]{2})/([0‐9]{4})",
    "\\3‐\\1‐\\2",
    "This is a test 01/30/2019.")
    文件
  • 基础概念
    • 文件包括两种类型:文本文件和二进制文件
    • 二进制文件:直接由比特0和比特1组成,没有统一字符编码,文件内部数据的组织格式与文件用途有关。
    • 文本文件:以ASCII码方式存储的文件。
    • 二进制文件和文本文件区别:仅编码(人为的理解)存在差异。
    • 文件包括两种类型:文本文件和二进制文件
    • 二进制文件:直接由比特0和比特1组成,没有统一字符编码,文件内部数据的组织格式与文件用途有关。
    • 文本文件:以ASCII码方式存储的文件。
    • 二进制文件和文本文件区别:仅编码(人为的理解)存在差异。

  • 文件操作
    • 打开文件 open
    —— 建立磁盘上的文件与程序中的对象相关联
    —— 通过相关的文件对象获得
    • 文件操作
    —— 读取
    —— 写入
    —— 定位
    —— 其它:追加、计算等
    • 关闭文件 close
    —— 切断文件与程序的联系
    —— 写入磁盘,并释放文件缓冲区

  • 文件打开操作
    • 打开文件
    —— Python使用open()函数打开文件并返回文件对象:

    <变量名>=open(file, mode = 'r')

    —— open函数有两个参数:文件名和打开模式。文件名可以是包含完整路径的名字,或当前路径下的文件名。
    —— 第二个参数制定文件打开模式。
    • open()函数提供7种基本的打开模式

‘r’ 以只读方式打开文件(默认)如果文件不存在,返回异常FileNotFoundError。
‘w’ 以写入的方式打开文件,文件不存在则创建,会覆盖已
存在的文件。
‘x’ 打开一个新文件来写数据。文件不存在则创建,如果数
据已经存在则返回异常FileExistsError。
‘a’ 以写入模式打开,文件不存在则创建,如果文件存在,
则在末尾追加写入。
‘b’ 以 二进制模式打开文件。
‘t’ 以 文本模式打开 (默认)。
‘+’ 可读写模式(可添加到其它模式中使用)。
• 模式的组合使用
—— ‘r’,’w’,’x’,’a’可以和’b’,’t’,’+’组合使用,形成既表达读写又表达文件模式的方式。
例如:
——‘wb’表示“写二进制数据”
——‘x+b’表示读写一个新的二进制文件

  • 文件的读写操作
    • 文件的读写:根据打开方式不同可以对文件进行相应的读写操作,Python提供4个常用的文件内容读取方法。

<file>.readall() 读入整个文件内容,返回一个字符串或字节流。
<file>.read(size=‐1) 从文件读取size个字符,当未给定size或给定负值的时候,读取剩余的所有字符,文件指针指向文件末尾。
<file>.readline(size=‐1) 从文件中读入一行内容,如果给出参数,读入该行前size长度的字符串或字节流。
<file>.readline(hint=‐1)从文件中读入所有行,以每行为元素形成一个列表,如果给出参数,读入hint行。
• Python提供3个与文件内容写入有关的方法。
<file>.write(str) 将字符串str写入文件。
<file>.writelines(lines)将一个元素为字符串的列表写入文件。
<file>.seek(offset,from)改变当前文件操作指针的位置,从from(0代表文件起始位置,1代表当前位置,2代表文件末尾)偏移offset个字节。

  • 文件操作示例
    • 文本文件逐行打印输出
    fo = open(fname ,"rt")
    for line in fo.readlines():
      print(line)
    fo.close()
  • 文件操作示例
    f1 = open(f1name, "rt")
    f2 = open(f1name, "wt")
    f2.write(f1.read().upper())
    f1.close()
    f2.close()
  • with语句
    • 容易忘记关闭(close)文件
    f = open('todos.txt')
    for chore in f
      print(chore, end='')
    tasks.close()
    #使用with语句重写这个代码
    with open('todos.txt') as f:
    for chore in f:
      print(chore, end='')
    • with确保即使发生异常,也可以正确的关闭文件
  • 编码的文件
    • 若打开有编码的文件,需要用codecs模块
    • import codecs
    f1 = codecs.open(fname, "r", "utf‐8")
    f2 = codecs.open(fname, "w", "gb2312")
  • 词频统计
    f = open("alice.txt", "rt")
    all = f.read()
    f.close()
    count_word = {}
    for w in all.split():
      w_lowercase = w.lower()
      count_word[w_lowercase] = \
                                          count_word.get(w_lowercase, 0) + 1
    result = [(v, k) for k, v in count_word.items()]
    result.sort()
    top10 = result[10:]
    for v,k in top10[::1]:
      print(f"Word {k}, occurs {v} times")
    汉字的处理
  • 导入库
    • pip install regex
    • import regex as re
    • \p{han} 匹配汉字
  • 汉字分词
    • jieba是Python中一个重要的第三方中文分词函数库。
    • 第三方库,需要安装

jieba.cut(s) 精确模式,返回一个可迭代的数据类型
jieba.cut(s,cut all=True) 全模式,输出文本s中所有可能单词
jieba.cut_for_search(s) 搜索引擎模式,适合搜索引擎建立索引的分词结果
jieba.lcut(s) 精确模式,返回一个列表类型,建议使用
jieba.lcut(s,cut all=True) 全模式,返回一个列表类型,建议使用
jieba.lcut_for_search(s) 搜索引擎模式,返回一个列表类型,建议使用
jieba.add_word(w) 向分词词典中增加新词w

OOP编程

• 类是类型概念的发展。
—— 对象是广义的“数据值”。
—— 对象所属的数据类型就是“类”。
—— 用于描述复杂数据的静态和动态行为。
• 类(class):描述相似对象的共性。包括
—— 数据
—— 操作:方法(method)
• 对象是类的实例(instance)
—— 创建对象
• 类的封装:数据和操作结合成一个程序单元,对外部隐藏内部实现细节。
—— 不允许用户直接操作类中被隐藏的信息。
—— 用户也无需了解隐藏的信息就能使用该类。
• 类对外公开方法名称和调用格式,即界面。
—— 外界向对象发消息。(方法名及参数)
—— 对象响应消息,执行相应方法。
—— 外界只能按对象允许的方式来处理对象数据。
• 封装的好处
—— 安全:对象自己的方法处理自己的数据
—— 易用:使用者无需了解内部实现细节
—— 易维护:实现者修改内部实现不会影响使用者
—— 标准化:同类甚至不同类的对象对使用者都呈现同样的操作界面
• 方法定义同函数定义

def <methodname>(self, other params):

—— 方法是依附于类的函数,普通函数则是独立的。
—— 方法的第一个参数是专用的,习惯用名字self。
—— 大体上等价于C++的this
—— 只能通过向对象发消息来调用方法。
• 对象是数据和操作的结合。
—— 方法对应于操作
—— 对象的数据以实例变量形式定义。
—— 实例变量:self.varname
—— 对象变量和所指向的数据本质上是一个词典
—— self.varname 即 self[“varname”]
—— 实例变量的赋值主要出现在init()方法中。

  • 类的定义实例
    class Circle:
    """ Class definition for a circle """
    def __init__(self, radius):
      self.radius = radius
    def getRadius(self):
      return self.radius
    def getArea(self):
    " Obtain the area of a circle"
      return math.pi*self.radius**2
  • 创建实例
    • 实例创建
    < 变量> = < 类名> (< 实参> )
    这里<类名>相当于一个函数,称为构造器,用来构造实例。
    • 成员访问
    • 方法调用
    —— 类似函数调用,但需指明实例(对象)
    —— < 实例>.< 方法名>(< 实参>)
    —— <实例>就是与形参self对应的实参
    • 数据成员访问
    —— < 实例>.< 数据成员名>
    继承
    • 在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class) 。
    • 继承是面向对象的重要特征之一,继承是两个类或者多个类之间的父子关系,子类继承了父类的所有实例变量和方法。
    • 继承实现了代码的重用。重用已经存在的数据和行为,减少代码的重新编写。
    • Python在类名后用一对圆括号表示继承关系,括号中的类表示父类。
    class 类名(被继承的类):
  • 实例和类的关系判定
    • isinstance(s, t)函数判定s是否t类型(及其子类型)
    —— isinstance(c, Circle)
    —— isinstance(c, DrawableCircle)
    • 继承关系:is-a (注:相当于c++的公有继承)
    • DrawableCircle is a Circle
    • 一个实例属于某个子类,则也属于父类,反之则不行。
    多态
    • 当对一个对象调用draw()函数时,它会根据自己的对象类型执行不同的draw方法
    —— FilledDrawableCircle.draw()
    —— DrawableCircle.draw()
    • 对于相同的方法,会有不同的实现版本,这就是多态(Polymorphism)

    科学计算与可视化

    Numpy
    • NumPy(Numeric Python)是Python语言的一个扩展包。
    • 由多维数组对象和数组计算函数共同组成的库,支持多维数组、矩阵运算以及大量数值计算功能。
  • Numpy产生动机
    • 标准的Python中用列表(list)保存一组值,可以作为数组使用。
    • Python列表的元素可以是任何对象,因此对象需要额外的信息保存其类型等信息,Python本身是解释型语言。因此,对数值运算来说,效率较低。
    —— 1000*1000的矩阵乘法,基于python实现三层循环超过10分钟。
    —— Numpy 大约0.03秒。
    • 计算效率直接影响了科学计算、机器学习的可用性。
    • Python的列表不支持数值计算语义
    • 能否实现矢量、矩阵的加法?乘法?逆?
    • 因此,需要原生支持数值计算语义的,高效率的Python库
    • NumPy的诞生弥补了这些不足
    • NumPy提供了两种基本的对象
    —— ndarray(ndimensional array object )
    —— ufunc( universal function object)
    • ndarray(数组)是存储单一数据类型的多维数组。
    • ufunc 是对数组进行处理的函数。
    • 安装:pip install numpy
    • 导入:import numpy as np
  • Numpy的优势
    • NumPy 通 常 与 SciPy(Scientific Python)和Matplotlib(绘图库)一起使用,这种组合广泛用于替代Matlab,已成为流行的技术方案。
    • Python:通用语言
    • Matlab:专用语言
    • NumPy是开源的(Open-Source)
  • Numpy做什么
    • 矢量、矩阵和高维数组(张量)的数值运
    算和逻辑运算
    • 线性代数相关的操作
    • 随机数生成
    • 傅立叶变换
    • 图形操作
    • 其他功能

  • • 矢量 Vectors
    • 矩阵 Matrices
    • 图像 Images
    • 张量 Tensors
  • Ndarray
    • ndarray:N维数组类型
    • 描述相同类型的元素集合
    • 使用基于零的索引访集合中的项目
    • ndarray中的每个元素类型(dtype)相同,占用的内存大小也相同。
  • Ndarray的创建
    • numpy.array(object, dtype = None, order =None)
    • object通常是一个容器或迭代器,根据其内容生成一个ndarray对象实例
    • dtype如果不指定,自动从实际数据中推断
    • order和内存中数据排列有关
  • dtype
    • int8, int16, int32, int64
    • uint8, uint16, uint32, uint64
    • float16, float32, float64
    • complex64, complex128
  • 数组属性
    • 数组的维度:ndim
    • 数组的形状:shape
    import numpy as np
    x = np.array([1, 2, 3])
    y = np.array([4.0, 5, 6])
    print(x.dtype, x.shape, x.ndim)
    print(y.dtype, y.shape, y.ndim)
    z = x + y
    print(z)
  • 数组创建
    • 数组创建的其他方法
    —— numpy.empty:空,不初始化值,值可能任意
    —— numpy.zeros:0
    —— numpy.ones:1
    —— numpy.arange:start, stop, step 可以为浮点数,但是不推荐用在浮点数场合。
    —— numpy.linspace:start, stop, number 实现均匀划分(默认含右侧端点),推荐在浮点数场合使用。
    array = np.array([[0,1,2],[2,3,4]])
    # [[0 1 2]
    #  [2 3 4]]
    array = np.zeros((2,3))
    # [[0. 0. 0.]
    # [0. 0. 0.]]
    array = np.ones((2,3))
    # [[1. 1. 1.]
    # [1. 1. 1.]]
    • eye 单位矩阵
    • 浮点数优先用linspace,避免累计误差
    • np.random 类似于random
    array = np.eye(3)
    # [[1. 0. 0.]
    # [0. 1. 0.]
    # [0. 0. 1.]]
    array = np.arange(0, 10, 2)
    # [0, 2, 4, 6, 8]
    array = np.linspace(0, 1, 11)
    # [0. , 0.1, 0.2, 0.3,…, 0.7, 0.8, 0.9, 1. ]
    array = np.random.randint(0, 10, (3,3))
    # [[6 4 3]
    # [1 5 6]
    # [9 8 5]])
  • 索引和切片(slice)
    • 一维数组的索引和切片大体与list相同
    a = np.arange(9)
    a[0]
    # 0
    a[3:7]
    # array([3, 4, 5, 6])
    a[:7:2]
    # array([0, 2, 4, 6])
    a[::1]
    #array([8, 7, 6, 5, 4, 3, 2, 1, 0])
    • 多维数组:每一个维度都可以进行索引或切片,
    返回一个标量或多维的子数组(view)。
    • 对此子数组的修改可能会反应在原数据上!
    b = np.array([[0,1,2],[3,4,5]])
    #[[0 1 2]
    #  [2 3 4]]
    b[0,1]
    # 1
    b[1,:]
    #[3,4,5]
    b[:,2]
    #[2,5]
  • 数组的运算
    • shape相同的多维数组,支持+ ‐ * / % < > == >= <= 等运算,对应的元素逐个进行运算,返回具有相同shape的多维数组
    • 单目运算作用在数组上,对每个元素逐个实施,包括负号 ‐ 以及单自变量函数 sin,cos 等
    • 上述运算是element-wise意义上的
    arr = np.array([[1., 2., 3.], [4., 5., 6.]])
    print(arr)
    [[1. 2. 3.]
    [4. 5. 6.]]
    print(arr * arr)
    [[ 1. 4. 9.]
    [16. 25. 36.]]
    print(arr ‐ arr)
    [[0. 0. 0.]
    [0. 0. 0.]]
  • 数组的运算:广播
    • shape不相同的数组如何运算?
    • 一般意义的逐元素的运算不可实现。
    • 但可以通过广播实现,小的数组被广播为大的数组,从而使得两个数组兼容。
    • 在下列规则满足时可以广播:
    —— 维数小的数组,在它的shape前面补“1”
    —— 在某个维度两个数组大小或者相同或者有一个是“1”
    —— 如果在某个维度是“1”,则需要任何下标[*]时,用[0]元素代替(相当于复制为很多份)
    • 等价地说,广播运算在下列情况之一成立时可以执行
    —— 具有相同的shape
    —— 具有相同的维度,shape每一维的值或者相同或者有一方为1
    —— 具有不同的维度,但是维数少的在前面补齐“1”后符合上述条件
  • 逻辑型数组索引
    • 逻辑型数组可以作为索引
    —— 如比较运算的结果为一个逻辑型数组
    • 掩码(Mask),表示仅取索引True的元素,构成一个子数组。
    x = np.arange(10)
    mod5 = x % 1 == 1
    x [ mod5 ] # [1, 6]
    x [ x > 5 ] ?
    • 整数型数组(或list)可以作为索引
    • 逐个取出每个整数对应下标的元素,得到ndarray数组的子集
x = np.arange(10)*10
# array([ 0, 10, 20, 30, 40,
50, 60, 70, 80, 90])
x[[1,3]]
# array([ 10, 30])
x[[5,3,7]]
# array([ 50, 30, 70])
  • view和copy
    • 为了提高效率、节约空间,有些numpy操作返回的是view,对view的修改可以改动原始数组中的数据改动原始数组中的数据。
    • 具体返回view或copy需要查看函数说明。
    • 显式的复制可以用copy函数。
    —— a.copy()
    —— np.copy(a)
  • 数组的拼接
    • np.concatenate([a1, a2, …],axis=0, out=None)
    • 参数说明:
    —— a1, a2, … : 一系列的ndarray,必需是相同的shape,除非在第axis维可以存在差异。
    —— axis : int, 缺省为0
    • 按照第axis维把上述数组拼接在一起
    A = np.ones((4,1))
    array([[1.],
    [1.],
    [1.],
    [1.]]
    B = np.zeros((4,2))
    array([[0., 0.],
    [0., 0.],
    [0., 0.],
    [0., 0.]])
    C = np.concatenate([A, B], axis=1)
    array([[1., 0., 0.],
    [1., 0., 0.],
    [1., 0., 0.],
    [1., 0., 0.]])
  • 数组的创建
    • np.zeros_like
    • np.ones_like
    • np.empty_like
    • 参数是另一个数组,按照其形状创建一个0/1/空的数组
  • reshape
    • 在保持总元素的数目不变的条件下,数组的形状可以更改
    • 默认的order是row-major
    a = np.array([1,2,3,4,5,6])
    a = a.reshape(3,2)
    """array([[1, 2],
    [3, 4],
    [5, 6]])"""
    a = a.reshape(2,1)
  • 平坦化
    • .ravel()
    • .flat
    x = np.array([[1, 2, 3], [4, 5, 6]])
    print(np.ravel(x))
    [1 2 3 4 5 6]
    for i in x.flat: #属性,不需要加(),返回iterator
      print(i)
  • 转置
    • .transpose 交换两个轴 axes
    • .T 相当于transposes前两个轴
    x = np.arange(4).reshape((2,2))
    """array([[0, 1],
    [2, 3]])"""
    np.transpose(x) # x.transpose((1,0)), or x.T
    """array([[0, 2],
    [1, 3]])"""
  • 数组的IO
    • 可以存储为NPY/NPZ文件
    • 可以同时存储多个数组
    • save存储为非压缩格式
    • savez存储压缩格式
    np.savez('data.npz', a=a)
    data = np.load('data.npz')
    a = data['a'] # data是一个词典
    • 读入文本文件
    • 可以指定注释、分隔符、编码等
    from io import StringIO
    # 用字符串模拟一个file对象
    c = StringIO("0 1\n2 3")
    np.loadtxt(c)
    array([[ 0., 1.],
    [ 2., 3.]])
    • 读入图像文件
    from scipy.misc import imread
    im = imread("lenna.png")
    print(im.shape, im.dtype)
    # (330, 330, 3) uint8
    im_grey = im[:,:,0]*0.299 + im[:,:,1]*0.587 + im[:,:,2]*0.114
    import matplotlib.pyplot as plt
    plt.imshow(im_grey, cmap='gray')
    plt.show()
  • ufunc
    • 除了四则运算,常见的数学函数也作为ufunc提供,可以在数组上操作.
    • 单次numpy.sin的速度只有math.sin的1/4,但大数组的numpy.sin比math.sin快20多倍。这是因为numpy.sin在C语言级别进行循环计算。
  • 聚集运算
    • np.sum(a) 对数组a求和
    • 其他参数:
    —— axis=None 在特定的维度上求和,默认为全部
    求和
    —— out=None 输出直接存入该参数
    —— initial=初始值
    np.sum([[0, 1], [0, 5]])
    #6
    np.sum([[0, 1], [0, 5]], axis=0)
    #array([0, 6])
    np.sum([[0, 1], [0, 5]], axis=1)
    #array([1, 5])
    np.sum([])
    #0.0
  • 其他聚集操作
    • all 布尔型:与
    • any 布尔型:或
    • max 最大值
    • min 最小值
    • mean 均值
    • std 标准差
  • 类型转换
    .astype(T) 转为T类型
    x = array([[0, 1],
    [2, 3]])
    x.astype(np.float32)
    """
    array([[0., 1.],
    [2., 3.]], dtype=float32)
    """
  • 矩阵运算
    • NumPy对于多维数组的运 算,缺省情况下并不使用矩阵运算(特指 乘除法)。
    • numpy库提供了matrix类,使用matrix类创建矩阵对象,它们的加减乘除运算缺省采用矩阵方式计算
    • NumPy中同时存在ndarray和matrix对象,容易混淆,需要注意。
  • 矩阵运算
    • 矩阵的乘积可以使用dot函数进行计算。
    • dot
    —— 对于两个一维的数组,计算的是这两个数组对
    应下标元素的乘积和(内积)。
    —— 对于二维数组,计算的是两个数组的矩阵乘积。
    —— 对于多维数组,通用计算公式为数组a的最后一维上的所有元素与数组b的倒数第二维上的所有元素的乘积和:
    • dot(a, b)[i,j,k,m] = sum(a[i,j,:] * b[k,:,m])
    a = np.array([[2, 0], [0, 1]])
    b = np.array([[4, 1], [2, 2]])
    c = np.dot(a, b)  
    """
    array([[8, 2],
    [2, 2]])
    """
  • 排序
    • .sort() 对数组进行排序,将改变数组的内容。
    • .argsort() 返冋数组的排序下标
    a = np.array([5,3,2,4,1])
    a.argsort()
    array([4, 2, 1, 3, 0], dtype=int64)
  • NumPy模块
    • numpy.linalg模块
    —— 包含线性代数的函数。可以计算逆矩阵、求特征值、奇异值分解、解线性方程组以及求解行列式、秩等
    • numpy.fft模块
    —— 提供了快速傅里叶变换及其逆变换。
    • numpy.random 模块
    —— 支持二项分布、超几何分布、正态分布等
  • numpy.linalg
    • 解方程
    3 * x0 + x1 = 9
    x0 + 2 * x1 = 8
    a = np.array([[3,1], [1,2]])
    b = np.array([9,8])
    x = np.linalg.solve(a, b)
    x
    array([ 2., 3.])
    np.allclose(np.dot(a, x), b)
    MATPLOTLIB
    • Python绘图库。
    • 由 John Hunter (1968-2012) 创建。
    • 拥有一套和Matlab几乎相同语法的绘图库。
    • 也拥有另一套面向对象的绘图库。
    http://matplotlib.org/ 参考 Example 和 Gallery。
  • 导入
    • import matplotlib.pyplot as plt
    • from matplotlib.pyplot import *
    • pyplot模块模拟了matlab接口
  • 入门示例
    import numpy as np
    from matplotlib.pyplot import *
    #or: from matplotlib.pylab import * 
    # pylab = pyplot + numpy
    x = np.linspace(0, 5, 10)
    y = x ** 2
    figure()
    plot(x, y, 'r‐o')
    xlabel('x')
    ylabel('y')
    title('title')
    show()
  • Plot
    • x:如果缺少x则按照(0,1,2,3…)
    • y
    • “r‐o”: red, 实线, 圆点
    —— 类似有 “g‐‐x” 绿色虚线X
    • plot改为semilogx, semilogy, loglog
    可以变为对数坐标尺度
  • 颜色
    • 单词,如’red’
    • 字母,如’r’
    • 6位16进制数,如’#FF0000’或’#ff0000’
    • 三(RGB)或四(RGBA)元组,如(1, 0, 0)或(1,0,0,1)
    • 灰度字符串,如’0.8’
    import numpy as np
    import matplotlib.pyplot as plt
    a = b = np.linspace(0, 3, 50)
    c = np.exp(a)
    d = c[::1]
    plt.plot(a, c, 'r‐‐', label='Model length')
    plt.plot(a, d, 'b:', label='Data length')
    plt.plot(a, c+d, 'k', label='Total message length')
    legend = plt.legend(loc='upper center', shadow=True)
    legend.get_frame().set_facecolor('#00FFCC')
    plt.show()
  • 保存绘图
    • plt.savefig()
    —— 文件名是必需参数。
    —— 示例:plt.savefig(“abc.png”, bbox_inches=’tight’)
    —— bboxinches=’tight’ 去掉不需要的白边。
    • plt.show()
    —— 只在屏幕上显示。
  • 多个绘图
    x = np.linspace(0.0, 6.28, 100)
    y1 = np.cos(x)
    y2 = np.sin(x)
    plt.subplot(2, 1, 1)
    plt.plot(x, y1, 'yo‐')
    plt.grid(True)
    plt.subplot(2, 1, 2)
    plt.plot(x, y2, 'r.‐')
    plt.xlabel('time (s)')
    plt.show()
  • 直方图
    mu, sigma = 100, 15
    x = mu + sigma * np.random.randn(10000)
    n, bins, patches = plt.hist(x, 50,
    normed=1,
    facecolor='g',
    alpha=0.75)
    plt.xlabel('Smarts')
    plt.ylabel('Probability')
    plt.title('Histogram of IQ')
    plt.text(60, .025,
    r'$\mu=100,\ \sigma=15$')
    plt.axis([40, 160, 0, 0.03])
    plt.grid(True)
    plt.show()
  • 散点图
    x = np.random.random(50)
    y = np.random.random(50)
    c = np.random.random(50)  # color of points
    s = 500 * np.random.random(50)  # size of points
    fig, ax = plt.subplots()
    im = ax.scatter(x, y, c=c, s=s, cmap=plt.cm.jet)
    # Add a colorbar
    fig.colorbar(im, ax=ax)
    # set the color limits
    im.set_clim(0.0, 1.0)

    网络爬虫

    检查网站地图
    • Sitemap(网站地图)
    • 网站提供的Sitemap文件可以帮助爬虫定位网站所有网页的链接;
    • Sitemap文件提供了爬取网站的有效方式,但该文件经常存在缺失、过期或不完整。
    检测网站构建技术
    • 构建网站的技术类型会对爬取产生影响。
    —— 例如网页是动态生成的还是静态页面。
    • 安装 builtwith 库,将URL作为参数,该库
    返回网站使用的技术特征。
    • pip install builtwith
    调研网站的所有者
    • 根据网站的所有者,判定爬虫的下载速度等;
    • 为了找到网站的所有者,可以使用WHOIS协议查询域名的注册者。
    • 安装:pip install python-whois
    下载单个网页
    • python提供了urllib2, requests等库
    import requests
    url = 'http://www.weather.com.cn/weather/101010100.shtml' # URL地址
    header = {
    'User‐Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36
    (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36
    Core/1.53.3226.400 QQBrowser/9.6.11681.400'
    }
    req = requests.get(url, headers=header, timeout=60)
    req.encoding = 'utf‐8' # 设置文本编码
    code = req.status_code # 返回状态,200代表OK
    print(code)
    • 遇到错误怎么办?(code!=200)
    • 下载时遇到的错误经常是临时性的:
    _ 如服务器过载时返回的503 Service Unavailable错误;
    _ 对于此类错误,可以尝试重新下载。
    • 非临时性错误
    _ 如果服务器返回的是404 Not Found错误,说明该网页目前并不存在,再次尝试同样的请求也通常会再次出错。
    • 400+错误发生在客户端,500+错误则发生在服务端。
    • 在code为500+时可以重试下载,但通常应该等待一段时间。
    分析网页的三类技术
    • 正则表达式
    _ 无视HTML语言,直接利用正则表达式筛选出所需的部分,包括天气和URL;
    • BeatifulSoup
    _ 将HTML进行解析,利用树结构进行分析;
    • lxml
    _ 将HTML进行解析,基于XPATH查询语言进行分析。
  • BeatifulSoup
    • Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库;
    • 支持惯用的文档导航、查找、修改文档的方式;
    • 提高效率,通常较正则表达式可以节省数小时甚至数天的工作时间。
    • pip install beautifulsoup4
    from bs4 import BeautifulSoup
    html_doc = """<html><head><title>The Dormouse's story</title></head>
    <body>
    <p class="title"><b>The Dormouse's story</b></p>
    <p class="story">Once upon a time there were three little sisters;
    and their names were
    <a href="http://example.com/elsie" class="sister"
    id="link1">Elsie</a>,
    <a href="http://example.com/lacie" class="sister"
    id="link2">Lacie</a> and
    <a href="http://example.com/tillie" class="sister"
    id="link3">Tillie</a>;
    and they lived at the bottom of a well.</p>
    <p class="story">...</p>
    """
    soup = BeautifulSoup(html_doc)
    print(soup.prettify()) # 排版
    soup.title
    # <title>The Dormouse's story</title>
    soup.title.name
    # 'title'
    soup.title.string
    # 'The Dormouse's story'
    soup.title.parent.name
    # 'head'
    soup.p
    # <p class="title"><b>The Dormouse's story</b></p>
    soup.p['class']
    # 'title'
    soup.a
    # <a class="sister" href="http://example.com/elsie"
    id="link1">Elsie</a>
    soup.find_all('a')
    # [<a class="sister" href="http://example.com/elsie"
    id="link1">Elsie</a>,
    #  <a class="sister" href="http://example.com/lacie"
    id="link2">Lacie</a>,
    #  <a class="sister" href="http://example.com/tillie"
    id="link3">Tillie</a>]
    soup.find(id="link3")
    # <a class="sister" href="http://example.com/tillie"
    id="link3">Tillie</a>
    • 从文档中找到所有a标签的链接
    for link in soup.find_all('a'):
        print(link.get('href'))
    # http://example.com/elsie
    # http://example.com/lacie
    # http://example.com/tillie
    • 从文档中获取所有文字内容
    print(soup.get_text())
    # The Dormouse's story
    #
    # The Dormouse's story
    #
    # Once upon a time there were three little sisters; and their\names were
    # Elsie, Lacie and ...
  • 如何遍历网页内容
    • BS4提供了children, parents, next_element等
    一系列方法,可以对元素的子元素、父元
    素、兄弟元素等进行导航,从而遍历整个
    网页。
    • BS4也提供了正则表达式等方法。
    • BS4的介绍可以参考:
    https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html
  • 链接爬虫
    • 链接爬虫表现得更像普通用户,它跟踪链接,访问感兴趣的内容。
    • 通过跟踪所有链接的方式,可以下载整个网站的页面。
    • 这种方法会下载大量并不需要的网页,通常应该利用正则表达式匹配/过滤需要爬取的网页。
    • 避免链接爬虫陷阱
    • 某些网站会动态生成页面内容,有可能造成理论上无限多的页面。
    ——例如:日历网站,链接指向“下个月”
    • 通常应该定义爬虫最大深度,避免爬虫陷阱。

    图形界面开发GUI

    python图形化GUI:pyQt5详解
    python图形化GUI:pyQt5-tools详解
    MVC
    • Model(模型)是应用程序中用于处理应用程序数据逻辑的部
    分,通常模型对象负责在数据库中存取数据。
    • View(视图)是应用程序中处理数据显示的部分。通常视图是依据模型数据创建的。
    • Controller(控制器)是应用程序中处理用户交互的部分。通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
    • MVC 分层有助于管理复杂的应用程序,因为您可以在一个时间内专门关注一个方面。例如,您可以在不依赖业务逻辑的情况下专注于视图设计。同时也让应用程序的测试更加容易。
    • MVC 分层同时也简化了分组开发。不同的开发人员可同时开发视图、控制器逻辑和业务逻辑。

python:PIL图像处理

自动化

EXCEL自动化

• Excel 是 Windows 环境下流行的、强大的电子表格应用。
—— 包括LibreOffice Calc,OpenOffice Calc,WPS等软件也可以读写xlsx格式。
• openpyxl 模块让 Python 程序能读取和修改Excel 电子表格文件。最新版本2.6.2。
https://openpyxl.readthedocs.io
• 安装:pip install openpyxl

  • 取得工作簿及工作表
    import openpyxl
    wb = openpyxl.load_workbook('example.xlsx')
    wb.sheetnames
    sheet = wb['Sheet3']
    sheet.title
    anotherSheet = wb.active
    anotherSheet
  • 取得单元格
    sheet = wb['Sheet1']
    sheet['A1']
    sheet['A1'].value
    c = sheet['B1']
    c.value
    for i in range(1, 5):
      print(i, sheet.cell(row=i, column=2).value)
  • 取得矩形区域
    for rowOfCellObjects in sheet['A1':'C3']:
        for cellObj in rowOfCellObjects:
              print(cellObj.coordinate, cellObj.value)
        print('‐‐‐ END OF ROW ‐‐‐')
  • 取得行或者列:支持循环迭代
    for i in sheet.rows:
        print(i)
    for i in sheet.columns:
        print(i)
  • 数据结果的保存
    • 保存在txt文件中
    • 保存在csv文件中
    • 保存在py文件中
    import pprint
    resultFile = open('result.py', 'w')
    resultFile.write(
    'pay_sum = ' + pprint.pformat(pay_sum)
    )
    resultFile.close()
  • 创建空白工作簿和表
    import openpyxl
    wb = openpyxl.Workbook()
    print(wb.sheetnames)
    sh = wb.active
    sh.title = "My Data"
    wb.save("mydata.xlsx")
  • 创建和删除工作表
    import openpyxl
    >>> wb = openpyxl.Workbook()
    >>> wb.get_sheet_names()
    ['Sheet']
    >>> sh1 = wb.create_sheet()
    <Worksheet "Sheet1">
    >>> wb.get_sheet_names()
    ['Sheet', 'Sheet1']
    >>> wb.create_sheet(index=0, title='First Sheet')
    <Worksheet "First Sheet">
    >>> wb.get_sheet_names()
    ['First Sheet', 'Sheet', 'Sheet1']
    >>> wb.remove_sheet(sh1)   #删除表
    >>> wb.get_sheet_names()
    ['First Sheet', 'Sheet']
  • 将值写入单元格
    import openpyxl
    wb = openpyxl.Workbook()
    sheet = wb.active
    sheet['A1'].value = 'Hello world!'
    wb.save("hello.xlsx")
  • 其他功能
    • 改变字体
    • 使用公式
    • 设置行高和列宽
    • 单元格拆分
    • 绘制图表
    例子:乘法表
    import openpyxl
    wb = openpyxl.Workbook()
    sheet = wb.active
    for i in range(1, 10):
    sheet.cell(row=i+1, column=1).value = i
    sheet.cell(row=1, column=i+1).value = i
    for i in range(1, 10):
    for j in range(1, 10):
    sheet.cell(row=i+1, column=j+1).value=i*j
    wb.save("99.xlsx")
    WORD自动化
    • Microsoft公司的Word是一套功能丰富的办公软件,所提供的docx格式可以存储文本以及字体、颜色等丰富的信息。
    • docx的读写比txt文件要复杂,需要第三方库的支持。
    • pip install python‐docx
    • 注意:导入的时候用 import docx
  • docx文件结构
    • docx 文件有很多结构。
    • 这些结构在 python-docx 中用 3 种不同的类型来表示。
    • Document 对象表示整个文档。
    • Document 对象包含一个 Paragraph 对象的列表,Paragraph即文档中的段落。
    • 每个 Paragraph 对象都包含一个 Run 对象的列表。
  • 读取文档
    import docx
    doc = docx.Document('libai.docx')
    print(len(doc.paragraphs)
    # 8
    print(doc.paragraphs[0].text)
    # '铁杵成针'
    print(doc.paragraphs[2].text)
    # '李白是唐代的大诗人,但是小时候读书并不用功。...'
    print(doc.paragraphs[2].runs)
    #[<docx.text.run.Run at 0x1e0e56a3c50>,...]
    print(doc.paragraphs[2].runs[0].text)
    #'李白是唐代的大诗人,'
    print(doc.paragraphs[2].runs[1].text)
    #'但是小时候读书并不用功'
  • 获取Word中的纯文本
    • 如果不关注样式,只希望获得所有的文本
    • 参考代码实现:
    import docx
    def getText(filename):
        doc = docx.Document(filename)
        fullText = []
        for para in doc.paragraphs:
              fullText.append(para.text)
        return '\n'.join(fullText)
  • Word中的样式
    • Word有很多样式,可以通过段落或run对象的style属性获得。
    • 可以通过设置下列属性产生不同的样式
  • 修改样式
    import docx
    doc = docx.Document('libai.docx')
    doc.paragraphs[2].runs[0].underline = True
    doc.save('restyled‐libai.docx')
  • 生成Word文档
    • doc.add_paragraph(text) 新建一个段落,返回段落对象。
    • para.add_run(text) 新建一个run,返回run对象。
    • doc.add_heading(text, level) 新建一个标题,层级为level
    • doc.add_picture(filename) 新建一个图片
    import docx
    doc = docx.Document()
    doc.add_heading('静夜思', 0)
    doc.add_heading('李白', 1)
    for s in ["床前明月光", "疑是地上霜", "举头望明月",
    "低头思故乡"]:
    para = doc.add_paragraph(s)
    para.add_run("/")
    doc.add_picture("green.jpg")
    doc.save('mydoc.docx')
    PDF自动化
    • PDF 表示 Portable Document Format 便携式文件格式,由Adobe Systems在1993年用于文件交换所发展出的文件格式。
    • 本部分专注两件事:
    —— 从 PDF 读取文本内容
    —— 从已有的文档页面生成新的 PDF。
    • pip install pyPDF2
  • PDF读取文字
    import PyPDF2
    with open('04067093.pdf', 'rb') as pdfFile:
    pdfReader = PyPDF2.PdfFileReader(pdfFile)
    print("Total pages: ", pdfReader.numPages)
    page0 = pdfReader.getPage(0)
    print(page0.extractText())
  • 合并PDF
    import PyPDF2
    pdf1File = open('00294849.pdf', 'rb')
    pdf2File = open('04067093.pdf', 'rb')
    pdf1Reader = PyPDF2.PdfFileReader(pdf1File)
    pdf2Reader = PyPDF2.PdfFileReader(pdf2File)
    pdfWriter = PyPDF2.PdfFileWriter()
    for pageNum in range(pdf1Reader.numPages):
        pageObj = pdf1Reader.getPage(pageNum)
        pdfWriter.addPage(pageObj)
    for pageNum in range(pdf2Reader.numPages):
        pageObj = pdf2Reader.getPage(pageNum)
        pdfWriter.addPage(pageObj)
    pdfOutputFile = open('combined.pdf', 'wb')
    pdfWriter.write(pdfOutputFile)
    pdfOutputFile.close(); pdf1File.close(); pdf2File.close()
  • 页面旋转和叠加
    • rotateClockwise(0, 90, 180, 270)
    • rotateCounterClockwise(…)
    _ 可以将页面对象旋转
    • mergePage(anotherPage)
    _ 可以将页面叠加(水印)
    • 综合上述功能,可以实现pdf文件的合并、页面抽取、旋转、叠印等功能。
  • PDF中文编码问题
    • pyPDF2不能读取中文编码的文字;
    • 可以使用pdfminer库或其他类似的库。
    import io
    from pdfminer.converter import TextConverter
    from pdfminer.pdfinterp import PDFPageInterpreter
    from pdfminer.pdfinterp import PDFResourceManager
    from pdfminer.pdfpage import PDFPage
    def extract_text_from_pdf(pdf_path):
      resource_manager = PDFResourceManager()
      fake_file_handle = io.StringIO()
      converter = TextConverter(resource_manager, fake_file_handle)
      page_interpreter = PDFPageInterpreter(resource_manager, converter)
      with open(pdf_path, 'rb') as fh:
          for page in PDFPage.get_pages(fh, caching=True):
              page_interpreter.process_page(page)
          text = fake_file_handle.getvalue()
      converter.close()
      fake_file_handle.close()
      if text:
          return text
    if __name__ == '__main__':
    print(extract_text_from_pdf('CH9‐图形界面开发A.pdf'))
    图像处理自动化
    • 图像处理已经是深入日常生活,Photoshop的缩写已经成为图像处理的代名词。
    • 如果需要编辑大量的图像,手工编辑可能是漫长、枯燥的工作。
    • Pillow 是一个第三方 Python 模块,用于处理图像文件。该模块包含一些函数,可以很容易地裁剪图像、调整图像大小,以及编辑图像的内容,从而轻松地自动编辑成千上万的图像。
  • 颜色和 RGBA 值
    • 计算机程序通常将图像中的颜色表示为RGBA 值。RGBA 值是一组数字,指定顔色中的红、绿、蓝和 alpha(透明度)的值。
    • 这些值是从 0到 255(最高)的整数。
    • 这些 RGBA 值分配给单个像素,像素是计算机屏幕上能显示一种颜色的最小点。
    • 像素的 RGB 设置准确地告诉它应该显示哪种颜色的色彩。
  • Alpha通道
    • 图像也有一个 alpha 值,用于生成 RGBA 值。如果图像显示在屏幕上,遮住了背景图像或桌面墙纸,alpha 值决定了“透过”颜色可以看到多少程度的背景。
    • 如果alpha 值为 0,表示完全透明。
    • 如果alpha 值为 255,表示完全不透明。
  • 获取颜色
    >>> from PIL import ImageColor
    >>> ImageColor.getcolor('red', 'RGBA')
    (255, 0, 0, 255)
    >>> ImageColor.getcolor('RED', 'RGBA')
    (255, 0, 0, 255)
    >>> ImageColor.getcolor('Black', 'RGBA')
    (0, 0, 0, 255)
    >>> ImageColor.getcolor('chocolate', 'RGBA')
    (210, 105, 30, 255)
    >>> ImageColor.getcolor('CornflowerBlue', 'RGBA')
    (100, 149, 237, 255)
  • 图像坐标系
    • 左上角坐标为(0,0)
    • y正方向向下
    • x正方向向右
  • Box
    • 一个矩形元组参数,表示图像中的一个矩形区域。四个整数按顺序分别是:
    _左:该矩形的最左边的 x 坐标。
    _顶:该矩形的顶边的 y 坐标。
    _右:该矩形的最右边右面一个像素的 x 坐标。
    _底:该矩形的底边下面一个像素的 y 坐标。
    • 矩形元组(3, 1, 9, 6)
  • 图像的打开和存储
    >>> from PIL import Image
    >>> img = Image.open('horse.jpg')
    >>> img.size
      (1674, 1116)
    >>> width, height = img.size
    >>> img.format
    'JPG'
    >>> img.save('horse.png')
  • 生成新图像
    from PIL import Image
    im = Image.new('RGBA', (100, 200), 'purple')
    im.save('purpleImage.png')
    im2 = Image.new('RGBA', (20, 20))
    im2.save('transparentImage.png')
  • 裁剪图片
    croppedIm = img.crop(
    (600, 200, 1000, 800))
    croppedIm.save('cropped‐horse.png')
  • 复制和粘贴
    from PIL import Image
    img = Image.open('horse.jpg')
    croppedIm = img.crop((600, 200, 1000, 800))
    horsehead = croppedIm.copy()
    img.paste(horsehead, (1200, 200))
    img.save('horse2.jpg')
  • 调整图像大小及旋转图像
    from PIL import Image
    img = Image.open('horse.jpg')
    width, height = img.size
    img44 = img.resize((width//4, height//4), Image.NEAREST)
    img42 = img.resize((width//4, height//2), Image.NEAREST)
    imgr30 = img.rotate(30)
    img44.save('horse44.jpg')
    img42.save('horse42.jpg')
    imgr30.save('horse_r30.jpg')
  • 更改单个像素
    • 单个像素的颜色通过 getpixel()和putpixel()方法取得和设置。它们都接受一个元组,表示像素的 x 和 y坐标。
    • putpixel()方法还接受一个元组,作为该像素的颜色。这个顔色参数是四整数 RGBA 元组或三整数 RGB 元组。
    • 注:1. 能改一个像素就能进行任意的图像编辑;
  1. 图片像素很多时,本方法很慢。
    img = Image.new('RGB', (200, 100), 'black')
    print(img.getpixel((0, 0)))
    for x in range(100):
    for y in range(50):
    img.putpixel((x, y), (210, 210, 210))
    img.save('putPixel.png')
  • 绘制形状
    • ImageDraw 方法在图像上绘制各种形状。
    • 点:point(xy, fill)方法绘制单个像素。xy 参数表示要画的点的列表。该列表可以是 x和 y 坐标的元组的列表,例如[(x, y), (x, y), …],或是没有元组的 x和 y 坐标的列表,例如[x1, y1, x2, y2, …]。
    • 线:line(xy, fill, width)方法绘制一条线或一系列的线。xy 是一个元组的列表,例如[(x, y), (x,y), …],或整数列表,例如[x1, y1, x2, y2, …]。每个点都是正在绘制的线上的一个连接点。
    • 矩形、椭圆、多边形、文字等。
    from PIL import Image, ImageDraw
    im = Image.new('RGBA', (200, 200), 'white')
    draw = ImageDraw.Draw(im)
    draw.line([(0, 0), (199, 0), (199, 199), (0, 199), (0,
    0)], fill='black')
    draw.rectangle((20, 30, 60, 60), fill='blue')
    draw.ellipse((120, 30, 160, 60), fill='red')
    draw.polygon(((57, 87), (79, 62), (94, 85), (120, 90),
    (103, 113)), fill='brown')
    for i in range(100, 200, 10):
    draw.line([(i, 0), (200, i ‐ 100)], fill='green')
    im.save('drawing.png')
    键盘鼠标自动化
    • 白盒:完成了解docx/xlsx格式细节,通过python直接生成符合格式的文档。
    • 灰色:Word/Excel提供某种控制接口(如COM接口),通过COM接口操作Word/Excel软件达到预期目标。
    • 黑色:缺乏控制接口,仅能通过模拟键盘和鼠标事件驱动GUI软件。
  • pyautogui
    • pyautogui模块可以模拟鼠标移动、按键和滚动鼠标滚轮等。
    • 本节仅介绍pyautogui的部分功能。
    http://pyautogui.readthedocs.org/
    • 安装:
    _ pip install PyGetWindow==0.0.1
    _ pip install pyautogui
  • 注意事项
    • Python 能以想象不到的高速移动鼠标并击键。它可能太快,导致被控程序跟不上。
    • 如果出了问题,而程序仍然继续到处移动鼠标,计算机就会失去控制(因为你的键盘和鼠标被人控制了)。
    —— 如果程序自己在移动鼠标,停止它可能很难。你可能无法点击“关闭”按钮
    • Windows 和 Linux 上,注销的热键是 Ctrl-Alt-Del ,有可能会失去目前没有保存的文档。
  • 预防措施
    • 设置脚本在每次函数调用后暂停一段时间,让用户有很短的时间窗口来控制鼠标和键盘。
    —— 将pyautogui.PAUSE 变量设置为要暂停的秒数。如设置:pyautogui.PAUSE = 1.5。
    • 开启pyautogui 自动防故障功能。
    —— 将鼠标移到屏幕的左上角,将导致pyautogui.FailSafeException 异常。
    —— 故障时应尽可能快地向左上移动鼠标,以触发异常。
    —— 该异常可以用try语句捕获。
  • 屏幕坐标系
    • 左上角为原点
    • x向右为正方向
    • y向下为正方向
    import pyautogui as ag
    width, height = ag.size()
    print(width, height)
    #1366, 768
  • 移动鼠标
    import pyautogui
    for i in range(10):
    ag.moveTo(100, 100, duration=0.25)
    ag.moveTo(200, 100, duration=0.25)
    ag.moveTo(200, 200, duration=0.25)
    ag.moveTo(100, 200, duration=0.25)
  • 获取鼠标位置
    • position()函数获得鼠标当前的位置。
    • 为了持续跟踪获得鼠标位置,可以采用下述代码:
    print('Press Ctrl‐C to quit.')
    try:
      while True:
          x, y = pyautogui.position()
          print(f"mouse at {x:4d}, {y:4d}")
    except KeyboardInterrupt:
      print('\nDone.')
  • 点击鼠标
    • 当前位置点击 click() 方法。
    • 若在位置(x,y) 点击,采用click(x,y)方法。
    • 默认情况下点击左键。若指定鼠标按键,则需要button关键字参数,取值为 ‘left’、’middle’或’right’。
    • 例:
    _ click(100, 150, button=’left’)
    _ click(200, 250, button=’right’)
    • 模拟鼠标按下:mouseDown()
    • 释放鼠标按键:mouseUp()
    • 函数参数与 click()
    _ click = mouseDown + mouseUp
    • 鼠标双击:doubleClick()
  • 拖动鼠标
    • Drag即按住一个按键不放同时移动鼠标。
    _ 通过拖动文件图标,在文件夹之间移动文件;
    _ 可以拖动绘图。
    • dragTo() 和 dragRel() 函数将鼠标拖动到一个新的位置,或相对当前的位置。
    _ 函数的参数与moveTo() 和 moveRel() 相似。
    import pyautogui as ag
    import time
    time.sleep(5)
    ag.click()
    distance = 200
    while distance > 0:
      ag.dragRel(distance, 0, duration=0.2) # move right
      distance = distance ‐ 5
      ag.dragRel(0, distance, duration=0.2) # move down
      ag.dragRel(‐distance, 0, duration=0.2) # move left
      distance = distance ‐ 5
      ag.dragRel(0, ‐distance, duration=0.2) # move up
  • 获取屏幕内容
    import pyautogui
    im = pyautogui.screenshot()
    im.save("capture.png")
    • 做GUI自动测试时,可以利用截图分析按钮是否正常或者变灰(利用Pillow库的getpixel方法)。
    • 可以做一个软件,随着鼠标移动,自动取得不同位置的颜色。
  • 屏幕图像识别
    • 提前准备一幅(截图后取出)的局部图像:
    • locateOnScreen(‘want.png’)
    • 找到屏幕上完全匹配的图像所在的box,然后可在box的中心(或其他位置)进行点击。
  • 键盘
    • typewrite()方法模拟发送按键
    _ typewrite(‘Hello world!’)
    _ typewrite([‘a’, ‘b’, ‘left’, ‘left’,’X’, ‘Y’])
    _ 前者均为正常按键
    _ 后者的’left’表示“左方向键”
  • 键盘:特殊键
  • 键盘模拟
    • keyDown()和keyUp()将向计算发送虚拟的按键和释放。
    • press() 函数模拟完整的击键。
    keyDown('shift');
    press('1');
    keyUp('shift')
    相当于 Shift-1 ,即“ ! ”键
    • hotkey() 按参数自左向右依次模拟按键倒序模拟释放。
    _ hotkey(‘ctrl’, ‘alt’, ‘shift’, ‘s’)
  • 可能完成的任务
    • 模拟键盘及鼠标,实现自动填表;
    • 填写Excel表格;
    • 编写Word文件。
    • 自动玩游戏;
    • 网络爬虫:
    • 模拟键盘输入关键字,发送“回车”键,获得页面;
    • 利用键盘另存当前页面;
    • 点击“下一页”,继续另存当前页面
    • 聊天机器人
    • 模拟键盘输入微信、QQ等
    • 在AI时代,视觉、听觉和模拟发声、模拟形象都可以实现。

    数据存储与程序调试

    数据转换存储
    • 数据的存储交换发生在:
    _ 在同一程序的不同片段之间;
    _ 在不同的程序之间;
    _ 在不同主机之间。
    • 这些数据可能存储一些简单的文本和数值,也可能是非常复杂具有结构的一组数据。
    • 为了实现数据的存储和交换,有多种相对流行的数据存储交换方式:
    _ 文件或数据库。
  • INI文件
    • INI用来表示简单的、分层次的配置文件,其内涵类似于Python的词典。
    • 本质是纯文本文件,但有一些简单的格式。
  • INI文件的读写
    • 由于格式非常简单,可以基于一般文件的read/write进行存取。
    • Python提供了内置库:
    import configparser
    config = configparser.ConfigParser()
    config.add_section('Init')
    config.set('Init', 'Server', '127.0.0.1')
    config.set('Init', 'Port', '12000')
    with open('my.ini', 'wt') as configfile:
      config.write(configfile)
  • pickle
    • Pickle库可以实现任意python对象的存储。
    import pickle
    todo = ['write a blog post',
    'reply an email',
    'read a book']
    pickle_file = open('todo.pickle', 'wb')
    pickle.dump(todo, pickle_file)
  • Pickle & cPickle
    • Pickle
    pickle_file = open('todo.pickle', "rb")
    todo = pickle.load(pickle_file)
    pickle_file.close()
    print(todo)
  • JSON
    • Pickle仅限于Python程序使用,如何和其他语言交互?
    • JSON (JavaScript Object Notation) 是跨语言的轻量级数据交换格式。
    • 易于被人工读取、修改,也容易被机器读取和写入。
    • 符合 ECMA-262 3rd Edition标准。
    • JSON语言无关,它可以方便的被 C, C++, C#,Java, JavaScript, Perl, Python等语言读取和生成。
    • 结论:JSON是理想的数据交换格式,可以实
    现跨语言的、跨计算机的复杂数据传输。
    import json
    datastore = { "room‐number": 100,
    "use": "reception",
    "sq‐ft": 50,
    "price": [100, 200, 300]
    }
    with open("ds.json", 'w') as f:
      json.dump(datastore, f)
    with open("ds.json", 'r') as f:
      data = json.load(f)
    print(data)
  • 数据库
    • 文件存储不适用于大项目,此时需要使用数据库。
    • 数据管理系统 Database Management System= DBMS
    _ 一系列存储数据的文件;
    _ 一系列程序用于访问和更新其中的数据。
    • 目前最流行的数据库是关系型数据库。
  • SQLite
    • SQlite 是开源的数据库,可以嵌入在其他程序中,不需要安装。
    • 单机版本,不能并发、不能网络访问、不需要用户名密码鉴权(但可以加密)。
    • Portable – 仅使用了ANSI-standard C语言,因此可在各种平台编译;
    • Reliable – 良好的测试,开源代码;
    • Small – 300 kb 的库,只需要16kb的stack和100kb的heap,甚至可以运行在单片机上。
  • 建库
    import sqlite3
    conn = sqlite3.connect('example.db')
    c = conn.cursor()
    c.execute('''CREATE TABLE money
    (日期, 姓名, 支出)''')
    for d, n, m in [("2019‐4‐1", "Li Lei", 52),
    ("2019‐4‐2", "Han Meimei", 300),
    ("2019‐4‐5", "Li Lei", 230),
    ("2019‐4‐8", "Li Lei", 170),
    ("2019‐4‐10", "Han Meimei", 96)]:
      c.execute("INSERT INTO money VALUES (?,?,?)",(d,n,m))
    conn.commit()
    conn.close()
  • 用库
    import sqlite3
    conn = sqlite3.connect('example.db')
    c = conn.cursor()
    result = c.execute('''select 姓名, 支出
        from money where 支出>100;''')
    for row in result:
      name = row[0]
      pay = row[1]
      print(f"{name} pay {pay}>100")
    conn.close()
  • 其他格式
    • MAT:Matlab数据存储格式
    • Python可以直接读取MAT文件,Python也可以调用Matlab完成特定任务。
    目录处理
    • 查找目录下的子目录和文件
    _ glob库
    • 遍历目录
    _ os.walk方法
  • 实例
    import os
    from os.path import join, getsize
    for root, dirs, files in os.walk('.'):
    print("root=", root)
    print(sum(getsize(join(root, name)
    ) for name in files), end="")
    print("bytes in", len(files),
    "non‐directory files")
    测试和调试
  • 测试驱动Test-driven开发
    • pytest是一个强大的Python测试工具。
    • pytest是软件测试框架,它会自动找到用户写的测试用例,运行测试并报告结果。
    • 支持插件或第三方扩展
    • 容易与其他工具对接。
    • pip install pytest
  • 规则
    • pytest 测试样例的规则:
    _ 测试文件以 test_ 开头(以 test 结尾也可以)
    _ 测试类以 Test 开头,并且不能带有 init 方法
    _ 测试函数以 test
    开头
    _ 断言使用基本的 assert 即可
    • pytest自动执行所有的测试,并报告通过和失败的测试用例数量。
  • print-调试
  • 使用日志文件
    • 对大规模程序长期运行而言,故障的机会是很少的,难以通过print获得;
    • 日志是一种非常好的手段,可以用于记录程序运行过程中的各种信息。
    • 理想的日志可以用来恢复和重现程序的运行过程。
    • 内置的logging库。
  • 日志等级
  • 利用IPython.embed调试
    • from IPython import embed
    • 在需要调试的位置加入embed()函数
    • 可以在现场运行python解释器,可以自由执行任何python语句,包括:
    _ 打印输出任何变量
    _ 修改和删除任何变量
    • print/logging应对复杂数据结构的能力不足,embed()是较为理想的选择。

文章作者: JackHCC
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 JackHCC !
评论
  目录