Python教程

《零基础学Python》——极客时间——学习笔记

本文主要是介绍《零基础学Python》——极客时间——学习笔记,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

第二章 Python基础语法

Python程序的书写规则

在这里插入图片描述

基础数据类型

在这里插入图片描述

类型判断

type()
在这里插入图片描述

强制类型转换

目标类型(要转换的数据)
在这里插入图片描述

变量的定义和常用操作

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

习题

题目:

练习一 变量的定义和使用

  1. 定义两个变量分别为美元和汇率
  2. 通过搜索引擎找到美元兑人民币汇率
  3. 使用Python计算100美元兑换的人民币数量并用print( )进行输出

代码:
在这里插入图片描述

第三章 序列

序列的概念

案例

在这里插入图片描述

概念

在这里插入图片描述

代码

在这里插入图片描述

字符串的定义和使用

在这里插入图片描述

字符串的常用操作

序列的基本操作

在这里插入图片描述

成员关系操作符

在这里插入图片描述

连接操作符

在这里插入图片描述

重复操作符

在这里插入图片描述

元组的定义和常用操作

元组中数字大小的比较

单个数字:
在这里插入图片描述
两个数字:
可当成是两个数字的叠加
在这里插入图片描述
120 < 220,故而结果为False。

列表和元组的区别

  • 列表是中括号[],元组是小括号()
  • 列表中的内容可变更,元组中的内容不可变更

fliter的功能

格式:
filter(lambda x: x < b, a)
取出a中小于b的元素

展示取出的元素
list(filter(lambda x: x < b, a))

例子:
在这里插入图片描述
统计取出元素的个数:
格式:
len (list (filter(lambda x: x < b, a)))
取出a中小于b的元素的个数

例子:
在这里插入图片描述

实现生肖查找功能

在这里插入图片描述

列表的定义和常用操作

基本操作:

  • 增加一个元素
  • 移除一个元素

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

习题

练习一 字符串

题目:

  1. 定义一个字符串Hello Python 并使用print( )输出
  2. 定义第二个字符串Let‘s go并使用print( )输出
  3. 定义第三个字符串"The Zen of Python" – by Tim Peters 并使用print( )输出

代码:
在这里插入图片描述

练习二 字符串基本操作

题目:

  1. 定义两个字符串分别为 xyz 、abc
  2. 对两个字符串进行连接
  3. 取出xyz字符串的第二个和第三个元素
  4. 对abc输出10次
  5. 判断a字符(串)在 xyz 和 abc 两个字符串中是否存在,并进行输出

代码:
在这里插入图片描述

练习三 列表的基本操作

  1. 定义一个含有5个数字的列表
  2. 为列表增加一个元素 100
  3. 使用remove()删除一个元素后观察列表的变化
  4. 使用切片操作分别取出列表的前三个元素,取出列表的最后一个元素

练习四 元组的基本操作

题目:

  1. 定义一个任意元组,对元组使用append() 查看错误信息
  2. 访问元组中的倒数第二个元素
  3. 定义一个新的元组,和 1. 的元组连接成一个新的元组
  4. 计算元组元素个数

代码:
在这里插入图片描述

第四章 条件与循环

条件语句

语法

在这里插入图片描述

代码

在这里插入图片描述
在这里插入图片描述

for循环

在这里插入图片描述
用途:
经常用for循环遍历序列
代码:
在这里插入图片描述

while循环

在这里插入图片描述

用法

通常和if条件判断语句连用

break语句

功能:
终止当前循环
在这里插入图片描述

continue语句

功能:
跳过本次循环
在这里插入图片描述

总结

在这里插入图片描述

for语句中的if嵌套

用for循环实现的判断星座:
在这里插入图片描述

while循环语句中的if嵌套

在这里插入图片描述

习题

练习一 条件语句的使用

题目:

  1. 使用if语句判断字符串的长度是否等于10,根据判断结果进行不同的输出
  2. 提示用户输入一个1-40之间的数字,使用if语句根据输入数字的大小进行判断,如果输入的数字在 1-10,11-20,21-30,31-40,分别进行不同的输出

代码:
在这里插入图片描述

练习二 循环语句的使用

题目:

  1. 使用for语句输出1-100之间的所有偶数
  2. 使用while语句输出1-100之间能够被3整除的数字

代码:
在这里插入图片描述

第五章:映射与字典

字典的定义和常用操作

在这里插入图片描述

定义和添加元素

在这里插入图片描述

生肖与星座案例完善

在这里插入图片描述
代码:

chinese_zodiac = "猴鸡狗猪鼠牛虎兔龙蛇马羊"  # 定义字符串类型,存储12生肖

zodiac_name = (u"魔羯座", u"水瓶座", u"双鱼座", u"白羊座", u"金牛座", u"双子座",
               u"巨蟹座", u"狮子座", u"处女座", u"天秤座", u"天蝎座", u"射手座")
zodiac_days = ((1, 20), (2, 19), (3, 21), (4, 21), (5, 21), (6, 22),
               (7, 23), (8, 23), (9, 23), (10, 23), (11, 23), (12, 23),)

# 定义字典
cz_num = {}
z_num = {}
# 初始化关键字
for i in chinese_zodiac:
    cz_num[i] = 0  # 将chinese_zodiac关键字依次赋值为0

for i in zodiac_name:
    z_num[i] = 0  # 将zodiac_name关键字依次赋值为0

while True:
    # 用户输入出生年份、月份和日期
    year = int(input('请输入年份:'))
    month = int(input('请输入月份:'))
    day = int(input('请输入日期:'))

    n = 0
    while zodiac_days[n] < (month, day):
        if month == 12 and day > 23:
            break
        n += 1
    # 输出生肖和星座
    print('您的星座是:%s' % (zodiac_name[n]))

    print('%s 年的生肖是 %s' % (year, chinese_zodiac[year % 12]))

    # 将值赋给初始化的字典
    cz_num[chinese_zodiac[year % 12]] += 1  # 用户当前的生肖, 出现一次就加一,生肖的名字对应的值加一
    z_num[zodiac_name[n]] += 1  # 用户当前的星座,出现一次就加一,星座的名字对应的值加一

    # 输出生肖和星座的统计信息
    for each_key in cz_num.keys():  # .keys() 取出字典中所有的key
        print('生肖 %s 有 %d 个' % (each_key, cz_num[each_key]))

    for each_key in z_num.keys():
        print('星座 %s 有 %d 个' % (each_key, z_num[each_key]))

结果:

请输入年份:2018
请输入月份:1
请输入日期:3
您的星座是:魔羯座
2018 年的生肖是 狗
生肖 猴 有 0 个
生肖 鸡 有 0 个
生肖 狗 有 1 个
生肖 猪 有 0 个
生肖 鼠 有 0 个
生肖 牛 有 0 个
生肖 虎 有 0 个
生肖 兔 有 0 个
生肖 龙 有 0 个
生肖 蛇 有 0 个
生肖 马 有 0 个
生肖 羊 有 0 个
星座 魔羯座 有 1 个
星座 水瓶座 有 0 个
星座 双鱼座 有 0 个
星座 白羊座 有 0 个
星座 金牛座 有 0 个
星座 双子座 有 0 个
星座 巨蟹座 有 0 个
星座 狮子座 有 0 个
星座 处女座 有 0 个
星座 天秤座 有 0 个
星座 天蝎座 有 0 个
星座 射手座 有 0 个
请输入年份:2021
请输入月份:3
请输入日期:25
您的星座是:白羊座
2021 年的生肖是 牛
生肖 猴 有 0 个
生肖 鸡 有 0 个
生肖 狗 有 1 个
生肖 猪 有 0 个
生肖 鼠 有 0 个
生肖 牛 有 1 个
生肖 虎 有 0 个
生肖 兔 有 0 个
生肖 龙 有 0 个
生肖 蛇 有 0 个
生肖 马 有 0 个
生肖 羊 有 0 个
星座 魔羯座 有 1 个
星座 水瓶座 有 0 个
星座 双鱼座 有 0 个
星座 白羊座 有 1 个
星座 金牛座 有 0 个
星座 双子座 有 0 个
星座 巨蟹座 有 0 个
星座 狮子座 有 0 个
星座 处女座 有 0 个
星座 天秤座 有 0 个
星座 天蝎座 有 0 个
星座 射手座 有 0 个
请输入年份:

列表推导式与字典推导式

在这里插入图片描述

习题

练习一 字典的使用

题目:

  1. 定义一个字典,分别使用a、b、c、d作为字典的关键字,值为任意内容
  2. 为该字典增加一个元素‘c’:'cake’后,将字典输出到屏幕
  3. 取出字典中关键字为d的值

代码:
在这里插入图片描述

练习二 集合的使用

题目:

  1. 将字符串hello中每个字符赋值给一个集合,将这个集合输出到屏幕’

代码:
在这里插入图片描述

第六章 文件的输入输出

在这里插入图片描述

文件的内建函数

在这里插入图片描述
在这里插入图片描述

文件的常用操作

代码:

# # 将小说的主要人物记录在文件中
#
# # 写入文件 的 基本流程:open() -> write() -> close()
# file1 = open('name.txt', 'w')  # 打开的文件名称为"name.txt",模式为"写入模式"  并将其赋值给一个变量
#
# file1.write(u'诸葛亮')  # 写入人物
# file1.close()  # 关闭并保存
#
# # 读取文件 的 基本流程:open() -> read() -> close()
# file2 = open('name.txt')  # mode默认为“mode=r”——只读模式
# print(file2.read())
# file2.close()
#
# # 写入一个新人物
# file3 = open('name.txt', 'a')
# file3.write('刘备')
# file3.close()

# # 读取多行中的一行
# file4 = open('name.txt')
# print(file4.readline())
#
# # 读取每一行同时进行操作(以行的方式读取,逐行操作)
# file5 = open('name.txt')
# for line in file5.readlines():  # readlines 逐行读取
#     print(line)
#     print('=====')

# 进行一个操作,操作完成后回到文件的开头,然后再次对文件进行操作
file6 = open('name.txt')
file6.tell()  # 告诉用户“文件指针”在哪
# 指针的功能:当没有进行人为操作时,程序会记录当前操作的位置,然后继续向后进行操作
print('当前文件指针的位置 %s' % file6.tell())

print('当前读取到了一个字符,字符的内容是 %s' % file6.read(1))  # 只读取文件的 1个字符
print('当前文件指针的位置 %s' % file6.tell())

# 需求:操作完成后,向回到文件的开头,再次进行操作
# 操纵指针
# 第一个参数:偏移位置(偏移量)  第二个参数:0——表示从文件开头偏移  1——表示从当前位置偏移  2——表示从文件结尾偏移
file6.seek(0)  # file6.seek(5, 0) 从文件开头 向后偏移 5个位置
print('我们进行了seek操作')
print('当前文件指针的位置 %s' % file6.tell())
# 又一次读取一个字符
print('当前读取到了一个字符,字符的内容是 %s' % file6.read(1))  # 只读取文件的 1个字符
print('当前文件指针的位置 %s' % file6.tell())
file6.close()

结果:

当前文件指针的位置 0
当前读取到了一个字符,字符的内容是 a
当前文件指针的位置 1
我们进行了seek操作
当前文件指针的位置 0
当前读取到了一个字符,字符的内容是 a
当前文件指针的位置 1

练习一 文件的创建和使用

题目:

  1. 创建一个文件,并写入当前日期
  2. 再次打开这个文件,读取文件的前4个字符后退出

代码:

# 1. 创建一个文件,并写入当前日期
import datetime

now = datetime.datetime.now()  # now变量 存储 现在的时间

new_file = open('date.txt', 'w')
new_file.write(str(now))
new_file.close()

# 2. 再次打开这个文件,读取文件的前4个字符后退出
again_file = open('date.txt')

print(again_file.read(4))  # 打印 读取的4个字符

print(again_file.tell())  # 文件指针,提示 读取了 4个字符

again_file.close()

结果:

2021
4

第七章 错误和异常

异常的检测和处理

在这里插入图片描述

常见错误

1. NameError

在这里插入图片描述
在这里插入图片描述

2. SyntaxError

在这里插入图片描述
在这里插入图片描述

3. IndexError

在这里插入图片描述
在这里插入图片描述

4. KeyError

在这里插入图片描述
在这里插入图片描述

5. ValueError

在这里插入图片描述
在这里插入图片描述

6. AttributeError

在这里插入图片描述
在这里插入图片描述

7. ZeroDivisionError

在这里插入图片描述
在这里插入图片描述

8. TypeError

在这里插入图片描述
在这里插入图片描述

捕获所有错误

except Exception

在这里插入图片描述
在这里插入图片描述

异常处理

在这里插入图片描述
在这里插入图片描述

except可捕获多个异常

格式:
在这里插入图片描述
注意:
多个错误,需用圆括号括起来作为一个参数

捕获成功后显示额外错误信息

在这里插入图片描述
在这里插入图片描述
注意:一般在调试程序时使用

手动抛出异常

在这里插入图片描述
在这里插入图片描述

Python raise用法

finally

不管是否产生错误都要去执行。
在这里插入图片描述

总结

在这里插入图片描述

习题

练习一 异常

题目:

  1. 在Python程序中,分别使用未定义变量、访问列表不存在的索引、访问字典不存在的关键字观察系统提示的错误信息
  2. 通过Python程序产生IndexError,并用try捕获异常处理

代码:
在这里插入图片描述

第八章 函数

函数的定义和常用操作

在这里插入图片描述
无函数版:
在这里插入图片描述
函数版:
在这里插入图片描述
完整版:

import re


def find_main_characters(character_name):
    with open('sanguo.txt', encoding='UTF-8') as f:
        data = f.read().replace("\n", "")
        name_num = re.findall(character_name,data)

    return character_name, len(name_num)

name_dict = {}
with open('name.txt') as f:
    for line in f:
        names = line.split('|')
        for n in names:
            char_name, char_number = find_main_characters(n)
            name_dict[char_name] = char_number

weapon_dict = {}
with open('weapon.txt', encoding="UTF-8") as f: # 默认按行读取
    i = 1
    for line in f:
        if i % 2 == 1:
            weapon_name, weapon_number = find_main_characters(line.strip('\n')) # 读取 删除'\n'的 该行内容
            weapon_dict[weapon_name] = weapon_number
        i = i + 1

name_sorted = sorted(name_dict.items(), key=lambda item: item[1], reverse=True)
print(name_sorted[0:10])

weapon_sorted = sorted(weapon_dict.items(), key=lambda item: item[1], reverse=True)
print(weapon_sorted[0:10])

结果:
在这里插入图片描述

函数的可变长参数

关键字参数

作用:
当没有按顺序写入参数时调用。

优点:

  1. 可以不用按顺序写入参数
  2. 更明确输入的参数究竟是什么含义

代码:
在这里插入图片描述
在这里插入图片描述

可变长参数

在这里插入图片描述

函数的变量作用域

全局变量

在这里插入图片描述

函数的迭代器与生成器

迭代器

功能

取列表当中每一个元素,对每一个元素依次进行处理,这种方法叫做迭代,能实现这种方法的函数,叫迭代器

两种函数(方法)

iter()和next()
在这里插入图片描述

生成器

定义

自己制作的迭代器叫生成器。
带yield的迭代器

自定义的迭代器

代码1:

 for i in range(10, 20, 0.5):
     print(i)

会报错,range()函数不允许令float数作为其步长。

代码2:

# 实现一个支持小数步长增长的range
def frange(start, stop, step):
    x = start
    while x < stop:
        yield x  # yield 运行到yield时会进行暂停,并记录当前的位置,当再次调用next()时,它会通过当前位置再去返回一个值
        x += step


for i in frange(10, 20, 0.5):
    print(i)

结果:

10
10.5
11.0
11.5
12.0
12.5
13.0
13.5
14.0
14.5
15.0
15.5
16.0
16.5
17.0
17.5
18.0
18.5
19.0
19.5

Lambda表达式

作用

简化函数。
代码:

def true():
	return True
# 等于
def true():return True
# 等于
lambda: True
def add(x, y):
	return x + y
# 等于
def add(x, y):return x + y
# 等于
lambda x, y:x + y   # 参数是 x,y 返回是 x+y

lambda返回的是lambda的表达式:
<function at 0x0000015D077E20D0>

用途

代码1:

lambda x: x <= (month, day)  # 参数是:x,返回的是:x <= (month, day)
# 转换成函数
def find(x):
    return x <= (month, day)

代码2:

lambda item: item[1]  # 参数是:item,返回的是:item[1]
# 转换成函数
def find2(item):  # 传入一个字典元素,取字典的值
    return item[1]


adict = {'a': '123', 'b': '456'}
for i in adict.items():
    print(find2(i)) # 取字典的值

Python 字典(Dictionary) items() 函数的用法。

Python内建函数

filter

功能:
filter(function, sequence)
过滤 sequence 中满足funciton的数

代码:

a = [1, 2, 3, 4, 5, 6, 7]
b = list(filter(lambda x: x > 2, a))  # 过滤 a 中 满足 大于2的数
print(b)

结果:

[3, 4, 5, 6, 7]

必须转化成list,否则lambda不会被执行

map

功能:
map(function, sequence)
对sequence中的值依次按function处理

代码1:

c = [1, 2, 3]
map(lambda x: x, c)  # 将 c 中的值 依次 返回 x
d = list(map(lambda x: x, c))
print(d)

map(lambda x: x + 1, c)  # 将 c 中的值 依次+1 返回
e = list(map(lambda x: x + 1, c))
print(e)

结果:

[1, 2, 3]
[2, 3, 4]

代码2:

a = [1, 2, 3]
b = [4, 5, 6]
map(lambda x, y: x + y, a, b)
c = list(map(lambda x, y: x + y, a, b))
print(c)

结果:

[5, 7, 9]

对应项依次相加输出。

reduce

功能:
reduce(function, sequence[, initial])
把序列的元素依次和初始值按照函数的方式做运算。

代码:

from functools import reduce

total = reduce(lambda x, y: x + y, [2, 3, 4], 1)  # 1 和 列表中第一个元素 按照 func 进行操作
print(total)
# ((1+2)+3)+4

结果:

10

zip

功能一:纵向整合

代码:

exchange = zip((1, 2, 3), (4, 5, 6))

for i in exchange:
    print(i)
# 进行了纵向整合,类比线性代数中的“矩阵转换”

结果:

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

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

功能二:字典中 key 和 value 对调

代码:

dicta = {'a': '123', 'b': '456'}
dictb = zip(dicta.values(), dicta.keys())
# ('a', 'b'), ('1', '2') --> ('a', '1'), ('b', '2')
print(dictb)
print(dict(dictb))  # 需将其类型强制转换为 dict

结果:

<zip object at 0x0000016A531F7E40>
{'123': 'a', '456': 'b'}

闭包的定义

闭包

定义:
外部函数中的变量被内部函数引用,就叫做 “闭包”

代码:

def func():
    a = 1
    b = 2
    return a + b


def sum(a):
    def add(b):
        return a + b  # 返回的是int
	# 返回 内部函数的函数名称
    return add  # 返回的是function,add是内部函数的函数名称,引用add的函数


num1 = func()
num2 = sum(2)  # num2 相当于 sum外部函数 里面的 内部函数add
print(num2(4))  # 将 num2 当成函数去调用(相当于add()),传入第二个参数

# print(type(num1)) --- int
# print(type(num2)) --- function

结果:

6

add 是 函数名称或函数的引用
add() 是 函数的调用

计数器

功能:
实现一个计数器counter,每次调用它计数就会+1

代码1:

# 实现一个计数器counter,每次调用它计数就会+1
def counter():
    cnt = [0]  # 定义一个列表,只有一个元素为0

    def add_one():
        cnt[0] += 1  # 每次调用函数计数器就+1
        return cnt[0]  # 返回增加后的值

    return add_one  # 返回内部函数


num1 = counter()  # 将 counter()函数 返回结果 赋值给 变量num1
print(num1)  # 输出 num1 这个函数 相当于 add_one
print(num1())  # 输出 add_one 这个函数的调用
print(num1())
print(num1())
print(num1())
print(num1())

结果:

1
2
3
4
5

代码2:

# 实现一个计数器counter,按指定初始值,每次调用它计数就会+1
def counter(FIRST=0):  # 若没传入参数,则默认以0开始
    cnt = [FIRST]  # 定义一个列表,只有一个元素为FIRST

    def add_one():
        cnt[0] += 1  # 每次调用函数计数器就+1
        return cnt[0]  # 返回增加后的值

    return add_one  # 返回内部函数


num5 = counter(5)
num10 = counter(10)

print(num5())
print(num5())
print(num5())
print(num10())
print(num10())

结果:

6
7
8
11
12

闭包的使用

案例:数学运算

闭包写法:

# a * x + b = y
# 欲保证a, b不变,仅x变化时,可使用闭包
def a_line(a, b):
    def arg_y(x):
        return a * x + b

    return arg_y


# a = 3, b = 5
# x = 10, y = ?
# x = 20, y = ?

line1 = a_line(3, 5) # line1 相当于 arg_y
print(line1(10)) # line1(10) 相当于 arg_y(10)
print(line1(20)) # line1(20) 相当于 arg_y(20)

# 求另一条直线
# a = 5, b = 10

line2 = a_line(5, 10)
print(line2(10))
print(line2(20))

结果:

35
65
60
110

外部函数是不变的量,内部函数是可变的量。

普通函数写法:

def func1(a,b,x):
	return a * x + b

每次均需传入a, b, x三值,不够简洁优雅

lambda写法:

def a_line2(a, b):
    return lambda x: a * x + b


# a = 3, b = 5
# x = 10, y = ?
# x = 20, y = ?

new_line1 = a_line2(3, 5)
print(new_line1(10))
print(new_line1(20))

更简洁优雅!

闭包和函数的区别

  1. 函数传递变量,闭包传递函数;
  2. 闭包比函数调用的参数更少;
  3. 闭包的代码更优雅。

装饰器的定义

描述:
想给函数增加一些功能,但又不想在函数内部添加相应的代码,就可以用“装饰器”。

time库

sleep()方法

功能:运行时停几秒

import time

time.sleep(3) # 停3s

time()方法

功能:
统计1970年1月1日到现在的时间。
代码:

import time

print(time.time())  # 1970年1月1日到现在走了多少秒

结果:

1611718601.273848

案例

统计函数运行时间:

# 统计函数运行了多长时间
def i_can_sleep():
    time.sleep(3)


start_time = time.time()

i_can_sleep()

stop_time = time.time()

print('函数运行了 %s 秒' % (stop_time - start_time))

装饰器

功能:
将重复性的事情只做一次。

闭包和装饰器的区别:

  • 闭包传入的是变量,内部函数引用的也是变量
  • 装饰器传入的是函数,内部函数引用的也是函数

代码:

def timer(func):
    def wrapper():
        start_time = time.time()
        func()
        stop_time = time.time()
        print("运行时间是 %s 秒" % (stop_time - start_time))

    return wrapper


# 统计函数运行了多长时间
@timer  # 语法糖,timer——装饰函数  i_can_sleep——被装饰函数,额外代码封装在装饰函数内
def i_can_sleep():
    time.sleep(3)


i_can_sleep()  # 相当于  num = timer(i_can_sleep())  num()

结果:

运行时间是 3.0005228519439697 秒

装饰器的使用

对带参数的函数增加装饰器

代码:

# 对带参数的函数增加装饰器
def tips(func):
    def nei(a, b):
        print('start')
        func(a, b)
        print('stop')

    return nei


# 实现加法
@tips
def add(a, b):
    print(a + b)


# 实现减法
@tips
def sub(a, b):
    print(a - b)


print(add(4, 5))
print(sub(4, 5))

结果:

start
9
stop
None
start
-1
stop
None

装饰器带参数

代码1:

# 装饰器带参数
# 针对不同的函数装饰器有所变化——为装饰器带上参数

def new_tips(argv):
    def tips(func):
        def nei(a, b):
            print('start %s' % argv)
            func(a, b)
            print('stop')

        return nei

    return tips


@new_tips('add')
def add(a, b):
    print(a + b)


@new_tips('sub')
def sub(a, b):
    print(a - b)


print(add(4, 5))
print(sub(4, 5))

结果:

start add
9
stop
None
start sub
-1
stop
None

代码2:

# 装饰器不仅取参数,亦可取函数名
def new_tips(argv):
    def tips(func):
        def nei(a, b):
            print('start %s %s' % (argv, func.__name__))  # 输出函数的名称
            func(a, b)
            print('stop')

        return nei

    return tips


@new_tips('add_module')
def add(a, b):
    print(a + b)


@new_tips('sub_module')
def sub(a, b):
    print(a - b)


print(add(4, 5))
print(sub(4, 5))

结果:

start add_module add
9
stop
start sub_module sub
-1
stop

装饰器的好处

  1. 调用函数时,不用重复编写相应的修饰代码,可以放在装饰器内;
  2. 装饰器代码易复用——@装饰器名称。

习题

练习一 定义装饰器,用于打印函数执行的时间

  1. 统计函数开始执行和结束执行的时间
  2. 扩展练习:为装饰器传入超时时间,函数执行超过指定时间后退出

代码:

# 1. 统计函数开始执行和结束执行的时间
import time


def timer(func):
    def nei():
        print('start time %s' % time.time())
        func()
        print('end time %s' % time.time())

    return nei


@timer
def i_can_sleep():
    time.sleep(3)


i_can_sleep()

结果:

start time 1612241463.787381
end time 1612241466.787973

练习二 定义装饰器,实现不同颜色显示执行结果的功能

  1. 向装饰器传递参数,通过传递的参数获取到输出的颜色
  2. 被装饰函数的print( )输出根据装饰器得到的颜色进行输出

代码:

# 1. 向装饰器传递参数,通过传递的参数获取到输出的颜色
# 2. 被装饰函数的print( )输出根据装饰器得到的颜色进行输出

import sys


def make_color(code):
    def decorator(func):
        if (code == 0):
            s = 'white'
            return func(s)
        elif (code == 1):
            s = 'black'
            return func(s)
        else:
            print('wrong')

    return decorator


@make_color(0)
def color_func(s):
    print('颜色是:%s' % s)

结果:

颜色是:white

自定义上下文管理器

代码:

fd = open('name.txt')
try:
    for line in fd:
        print(line)
finally:
    fd.close()

# 上下文管理器
# 使用with就不用写finally了,因为当其出现异常时,with会自动调用finally来将文件关闭(后面详细讲)
with open('name.txt') as f:
    for line in f:
        print(line)

结果:

諸葛亮|關羽|劉備|曹操|孫權|關羽|張飛|呂布|周瑜|趙雲|龐統|司馬懿|黃忠|馬超
諸葛亮|關羽|劉備|曹操|孫權|關羽|張飛|呂布|周瑜|趙雲|龐統|司馬懿|黃忠|馬超

总结

在这里插入图片描述

习题

练习一 函数

  1. 创建一个函数,用于接收用户输入的数字,并计算用户输入数字的和
  2. 创建一个函数,传入n个整数,返回其中最大的数和最小的数
  3. 创建一个函数,传入一个参数n,返回n的阶乘

代码:

# 1. 创建一个函数,用于接收用户输入的数字,并计算用户输入数字的和


def func1():
    two_num = input('请输入两个数字,用空格做分隔:')
    # 检查用户输入是否合法
    func2(two_num)
    # print(type(two_num))
    num1, *_, num2 = two_num
    print('%s 和 %s 之和是:' % (num1, num2))
    print(int(num1) + int(num2))


def func2(check_number):
    pass


func1()


# 2. 创建一个函数,传入n个整数,返回其中最大的数和最小的数
def func3(*nums):
    print('最大的数是: %s' % max(nums))
    print('最小的数是: %s' % min(nums))


func3(1, 5, 8, 32, 654, 765, 4, 6, 7)


# 3. 创建一个函数,传入一个参数n,返回n的阶乘
def func4(n):
    if n == 0 or n == 1:
        return 1
    else:
        return n * func4(n - 1)


num = input('请输入要阶乘的数:')
print('%s 的阶乘结果是:%s' % (num, func4(num)))

第九章 模块

模块的定义

在这里插入图片描述

重命名模块

将长的模块名重命名,从而简化名称。

import time as t  # 重命名模块

t.time()  # 引用time文件中的函数

不写模块名称的方法:

from time import sleep  # 不推荐此写法,害怕导致重命名

sleep()

自定义模块及其调用

自己的模块:

def print_me():
    print('me')

# print_me() 一般很少有直接调用的,一般都是函数的定义

调用模块:

import mymod  # 导入是不加 .py 后缀名

mymod.print_me()  # 将此文件中的 函数 引用进来

习题

练习一 模块

  1. 导入os模块,并使用help(os)查看os模块的帮助文档
# 1. 导入os模块,并使用help(os)查看os模块的帮助文档
import os

print(help(os))

第十章 语法规范

PEP8编码规范

课上相关说明:

https://www.python.org/dev/peps/pep-0008/



pycharm 安装PEP8
cmd窗口输入:pip install autopep8
Tools→Extends Tools→点击加号

Name:Autopep8(可以随便取)
- Tools settings:
    - Programs:`autopep8` (前提是你已经安装了哦)
    - Parameters:`--in-place --aggressive --aggressive $FilePath$`
    - Working directory:`$ProjectFileDir$`
- 点击Output Filters→添加,在对话框中的:Regular expression to match output中输入:`$FILE_PATH$\:$LINE$\:$COLUMN$\:.*`

如不成功,请参照下文:
pycharm设置autopep8

第十一章 面向对象编程

类与实例

面向过程编程

特点:

  • 根据程序执行的顺序从上到下去编写相应的函数

代码:

# 面向过程
user1 = {'name': 'tom', 'hp': 100}
user2 = {'name': 'jerry', 'hp': 80}


def print_role(rolename):
    print('name is %s , hp is %s' % (rolename['name'], rolename['hp']))


print_role(user1)

面向对象编程

定义:
不同对象相同特征的提取,提取出来的东西就叫做

代码:

# 面向对象
class Player():  # 定义一个类   类名开头要用 大写字母
    def __init__(self, name, hp): # __init__ 是一个特殊的方法,在类实例化之后,它会自动执行
        self.name = name  # self 表示 Player 这个类进行了实例化之后,这个实例的本身 self 相当于 java的this吗
        self.hp = hp

    def print_role(self):  # 定义一个方法
        print('%s: %s' % (self.name, self.hp))


user1 = Player('tom', 100)  # 类的实例化
user2 = Player('jerry', 90)
user1.print_role()
user2.print_role()

# 注意:在一个类中,所有的函数(方法)第一个参数一定要带着 self

注意:

  • 在一个类中,所有的函数(方法)第一个参数一定要带着 self
  • 类名开头要用 大写字母

如何增加类的属性和方法

增加一个属性和方法

代码:

# 面向对象
class Player(): 
    def __init__(self, name, hp, occu): 
        self.name = name 
        self.hp = hp  
        self.occu = occu  # 增加一个职业属性

    def print_role(self): 
        print('%s: %s %s' % (self.name, self.hp, self.occu))

    def updateName(self, newname):  # 创建一个改名的方法
        self.name = newname

user1 = Player('tom', 100, 'war')  # 类的实例化
user2 = Player('jerry', 90, 'master')
user1.print_role()
user2.print_role()

user1.updateName('wilson')
user1.print_role()


class Monster():
    '定义怪物类'
    pass

类的封装

类的属性不想让别人访问到。

  • 在类的属性前面加两个下划线"__"

代码:

# 面向对象
class Player(): 
    def __init__(self, name, hp, occu): 
        self.__name = name 
        self.hp = hp  
        self.occu = occu  # 增加一个职业属性

    def print_role(self): 
        print('%s: %s %s' % (self.__name, self.hp, self.occu))

    def updateName(self, newname):  # 创建一个改名的方法
        self.__name = newname

user1 = Player('tom', 100, 'war')  # 类的实例化
user2 = Player('jerry', 90, 'master')
user1.print_role()
user2.print_role()

user1.updateName('wilson')
user1.print_role()

结果:

name is tom , hp is 100
tom: 100 war
jerry: 90 master
wilson: 100 war
wilson: 100 war

这样类的属性就不会被类的实例访问到。
只能通过方法去改变类的属性。

类的继承

继承

代码:

# 猫科动物 猫  猫 继承了 猫科动物 所使用的方法
# 猫科动物 就叫做 猫 的 父类        猫 就叫做 猫科动物 的 子类

class Monster():
    '定义怪物类'

    def __init__(self, hp=100):  # 初始化时已经有生命值了
        self.hp = hp

    def run(self):
        print('移动到某个位置')


class Animals(Monster):  # 子类继承父类   子类括号内写入父类名字
    '普通怪物'

    def __init__(self, hp=10):
        self.hp = hp


class Boss(Monster):
    'Boss类怪物'
    pass


# 父类
a1 = Monster(200)
print(a1.hp)
a1.run()

# 子类
a2 = Animals(1)
print(a2.hp)
a2.run()

子类可以调用父类中的属性和方法。

super

作用:
在父类中初始化的属性,子类不用重复初始化。

代码:

class Animals(Monster):  # 子类继承父类   子类括号内写入父类名字
    '普通怪物'
    def __init__(self,hp=10):
        super().__init__(hp) # Animals中的hp不用再进行初始化了,父类已经初始化完成了

子类方法和父类方法重名

子类调用时,子类的方法会把父类同名的方法覆盖掉。

多态

重名方法只有在实际使用时,才知道调用它的是子类还是父类的方法,说明这个方法在运行时有多种状态,这个特性被称作“多态”。

判断类的继承关系

代码:

# 判断类的继承关系
print('a1的类型是 %s' % type(a1))
print('a2的类型是 %s' % type(a2))
print('a2的类型是 %s' % type(a3))

print(isinstance(a2, Monster))  # 判断a2是否为Monster的子类,若是,则输出True,若否,则输出False

结果:

a1的类型是 <class '__main__.Monster'>
a2的类型是 <class '__main__.Animals'>
a2的类型是 <class '__main__.Boss'>
True

额外知识

元组、列表、字符串等形式都是“class”

# 元组、列表、字符串等形式都是“class”
print(type(tuple))
print(type(list))
print(type('123'))
<class 'type'>
<class 'type'>
<class 'str'>

所有对象都继承object这样一个父类

# 所有对象都继承object这样一个父类
print(isinstance(tuple, object))
print(isinstance(list, object))
print(isinstance('123', object))
True
True
True

总结

  1. 类是描述具有相同属性和方法这样一个对象的集合;
  2. 封装性、继承性、多态性;
  3. 类需要实例化才能使用。

类的使用-自定义with语句

功能:

  • 自动处理异常
  • 异常和面向对象结合起来

自定义with方法:
代码:

class Testwith():
    def __enter__(self):  # 开始时调用
        print('run')

    def __exit__(self, exc_type, exc_val, exc_tb):  # 结束时调用
        if exc_tb is None:  # 如果exc_tb没有异常的话,它的值就是None   判断是否为空用“is None”
            print('正常结束')
        else:
            print('has error %s' % exc_tb)


# 类和抛出异常结合
# 用with简化异常的编写
with Testwith():
    print('Test is running')
    raise NameError('testNameError')  # 手动抛出异常

结果:

run
Test is running
has error <traceback object at 0x000002016D762B80>
Traceback (most recent call last):
  File "D:\Python\pythonProject\with_test.py", line 15, in <module>
    raise NameError('testNameError')  # 手动抛出异常
NameError: testNameError

重点:

  • with可以简化抛出异常的编写(try…catch…)

第十二章:多线程编程

多线程编程的定义

进程:
程序运行的状态

多线程编程:
同时有大量的请求过来,我们需要对这些请求进行处理,这些处理的方法就是多线程编程。

没有线程运行

代码:

def myThread(arg1, arg2):
	print('%s %s' %(arg1, arg2)

for i in range(1, 6, 1):
	t1 = myThread(i, i + 1)

结果:

1 2
2 3
3 4
4 5
5 6

多线程方法运行

代码:

import threading


def myThread(arg1, arg2):
	print('%s %s' %(arg1, arg2)

for i in range(1, 6, 1):
	# t1 = myThread(i, i + 1)
	t1 = threading.Thread(target = myThread, args = (i, i + 1))
	t1.start()  # 运行多线程程序

结果:

1 2
2 3
3 4
4 5
5 6

引入sleep()暂停多线程:
代码:

import threading
import time


def myThread(arg1, arg2):
	print('%s %s' %(arg1, arg2)
	time.sleep(1)

for i in range(1, 6, 1):
	# t1 = myThread(i, i + 1)
	t1 = threading.Thread(target = myThread, args = (i, i + 1))
	t1.start()  # 运行多线程程序

结果:

1 2
2 3
3 4
4 5
5 6

程序直接全部打印出所有内容,运行完等了1s才结束。

把当前线程运行状态进行显示:

import threading
import time
from threading import current_thread  # 当前线程运行的状态,进行显示


def myThread(arg1, arg2):
    print(current_thread().getName(), 'start')  # 将当前线程的名字做标志   第一个:线程的名称;第二个:想要添加的注释
    print('%s %s' % (arg1, arg2))
    time.sleep(1)  # 程序没有等待1s,直接输出,说明程序是 并行的 在运行的
    print(current_thread().getName(), 'stop')


for i in range(1, 6, 1):
    # t1 = myThread(i, i + 1) # 没有线程
    t1 = threading.Thread(target=myThread, args=(i, i + 1))  # 第一个参数:函数名;第二个参数:传入的参数   产生5个新的线程
    t1.start()  # 运行多线程程序

print(current_thread().getName(), 'end')
# 主程序结束之后,线程才结束   先“MainThread end”后“stop”
# 主线程先结束,Thread1-5后结束

结果:

Thread-1 start
1 2
Thread-2 start
2 3
Thread-3 start
3 4
Thread-4 start
4 5
Thread-5 start
5 6
MainThread end
Thread-1 stop
Thread-3 stop
Thread-2 stop
Thread-4 stop
Thread-5 stop

主程序结束之后,线程才结束 先“MainThread end”后“stop”。

线程之间的同步

有一个线程运行时,可以等待另一个线程结束。

代码:

# 实现 先“stop”后“end”
import threading
from threading import current_thread  # 方法名非常时使用


# threading.Thread().run()  # 线程中的函数调用
# 继承 threading.Thread() 然后 重写 run() --- 多态性

class Mythread(threading.Thread):  # 继承时不加括号
    def run(self):  # 重新实现run()方法
        # 1. 获取当前线程的名称——判断是否进行 线程的等待
        print(current_thread().getName(), 'start')
        print('run')
        print(current_thread().getName(), 'stop')


t1 = Mythread()
t1.start()
# Thread先结束,main后结束
t1.join()

print(current_thread().getName(), 'end')  # 打印主线程的显示结果

结果:

Thread-1 start
run
Thread-1 stop
MainThread end

经典的生产者和消费者问题

当程序运行时,会不断制造大量数据,同时用户会对数据进行一系列的消耗,这个过程就是生产者和消费者问题。(类比水槽的注水与放水)

队列

同步不同线程之间的数据。

代码:
在这里插入图片描述

# 队列的实现
import queue

q = queue.Queue()  # 产生一个队列
q.put(1)  # 向队列中增加一个数据
q.put(2)
q.put(3)
q.get()  # 读取队列   按照加入的顺序进行读取

代码实现

代码1:

from threading import Thread, current_thread  # 可以实现多个生产者和消费者并行的去生产和消费
import time  # 休眠
import random  # 产生随机数据
from queue import Queue  # 导入队列库

queue = Queue(5)  # 定义队列的长度


class ProducerThread(Thread):
    def run(self):
        name = current_thread().getName()  # 获取生产者的线程的名字
        nums = range(100)
        global queue  # 定义一个队列的全局变量
        while True:
            num = random.choice(nums)  # 随机选择一个数字
            queue.put(num)  # 将随机选择的数字放入到队列当中
            print('生产者 %s 生产了数据 %s' % (name, num))
            t = random.randint(1, 3)  # 随机的休眠时间
            time.sleep(t)  # 令生产者休眠
            print('生产者 %s 睡眠了 %s 秒' % (name, t))


class ConsumerThread(Thread):
    def run(self):
        name = current_thread().getName()  # 获取消费者的线程名称
        global queue

        while True:
            num = queue.get()  # 在队列中取得想要的数字
            queue.task_done()  # 封装好了 线程等待和同步的代码
            print('消费者 %s 消耗了数据 %s' % (name, num))  # 随机的休眠时间
            t = random.randint(1, 5)  # 随机等待几秒
            time.sleep(t)
            print('消费者 %s 睡眠了 %s 秒' % (name, t))


# 一个生产者和两个消费者
p1 = ProducerThread(name='p1')
p1.start()
c1 = ConsumerThread(name='c1')
c1.start()

结果:

生产者 p1 生产了数据 74
消费者 c1 消耗了数据 74
生产者 p1 睡眠了 1 秒
生产者 p1 生产了数据 82
生产者 p1 睡眠了 1 秒
生产者 p1 生产了数据 67
消费者 c1 睡眠了 3 秒
消费者 c1 消耗了数据 82
生产者 p1 睡眠了 1 秒
生产者 p1 生产了数据 28
生产者 p1 睡眠了 1 秒
生产者 p1 生产了数据 75

代码2:

from threading import Thread, current_thread  # 可以实现多个生产者和消费者并行的去生产和消费
import time  # 休眠
import random  # 产生随机数据
from queue import Queue  # 导入队列库

queue = Queue(5)  # 定义队列的长度


class ProducerThread(Thread):
    def run(self):
        name = current_thread().getName()  # 获取生产者的线程的名字
        nums = range(100)
        global queue  # 定义一个队列的全局变量
        while True:
            # 经过随机的休眠时间,往队列里添加随机的数字
            num = random.choice(nums)  # 随机选择一个数字
            queue.put(num)  # 将随机选择的数字放入到队列当中
            print('生产者 %s 生产了数据 %s' % (name, num))
            t = random.randint(1, 3)  # 随机的休眠时间
            time.sleep(t)  # 令生产者休眠
            print('生产者 %s 睡眠了 %s 秒' % (name, t))


class ConsumerThread(Thread):
    def run(self):
        name = current_thread().getName()  # 获取消费者的线程名称
        global queue

        while True:
            # 经过随机的时间,往队列里提取随机的数字
            num = queue.get()  # 在队列中取得想要的数字
            queue.task_done()  # 封装好了 线程等待和同步的代码
            print('消费者 %s 消耗了数据 %s' % (name, num))  # 随机的休眠时间
            t = random.randint(1, 5)  # 随机等待几秒
            time.sleep(t)
            print('消费者 %s 睡眠了 %s 秒' % (name, t))


# # 一个生产者和两个消费者 (生产慢消费快)
# p1 = ProducerThread(name='p1')
# p1.start()
# c1 = ConsumerThread(name='c1')
# c1.start()

# 三个生产者和两个消费者 (生产快消费慢)
p1 = ProducerThread(name='p1')
p1.start()
p2 = ProducerThread(name='p2')
p2.start()
p3 = ProducerThread(name='p3')
p3.start()
c1 = ConsumerThread(name='c1')
c1.start()
c2 = ConsumerThread(name='c2')
c2.start()
# 队列满时,生产者就不再去生产数据,待消费者消耗之后再进行生产

结果:

生产者 p1 生产了数据 70
生产者 p2 生产了数据 33
生产者 p3 生产了数据 95
消费者 c1 消耗了数据 70
消费者 c2 消耗了数据 33
消费者 c1 睡眠了 1 秒
消费者 c1 消耗了数据 95

第十三章 标准库

Python标准库的定义

Python标准库官方文档

重点掌握:

  • Text Processing Services
  • Data Types
  • Generic Operating System Services
  • Internet Data Handling
  • Development Tools
  • Debugging and Profiling

正则表达式库re

匹配

代码:

import re

# 匹配
p = re.compile('a')  # 定义一个要匹配的字符串
print(p.match('a'))  # 被匹配的字符串     可以成功匹配
print(p.match('b'))  # 不能匹配上

# 匹配一串有规律的字符
# 引入一些特殊的字符(表示字符的重复等规律),这种特殊的字符被称作“元字符”
p = re.compile('cat')
print(p.match('caaaaat'))  # 匹配不成功,为None
# 正则表达式的好处:把一些特殊的功能,用特殊的符号来表示
p = re.compile('ca*t')  # 重复a用*a代替
print(p.match('caaaaat'))  # 匹配成功

结果:

<re.Match object; span=(0, 1), match='a'>
None
None
<re.Match object; span=(0, 7), match='caaaaat'>

正则表达式的元字符

常用元字符

元字符功能
.匹配任意的单个字符
^匹配以什么样的内容做开头的字符串
$匹配以什么样的内容做结尾的字符串
*匹配前面的字符出现0次到多次
+匹配前面的字符出现1次到多次
?匹配前面的字符出现0次到1次
{m}表示前面的字符要出现指定的次数为m次
{m,n}示前面的字符要出现指定的次数为m~n次
[]表示中括号内的任意一个字符匹配成功即可
表示字符选择左边或者是右边,通常和括号用在一起(常和()搭配使用)
\d表示匹配的内容是一串数字 相当于 [1234567890]+ 或 [0-9]+ 中的一个数字
\D表示匹配的内容不包含数字
\s表示匹配的是一个字符串(a-z)
()进行分组
^$表示这一行是空行,匹配文本时,有一行是空行,什么都不包括
.*?不使用贪婪模式

. 元字符

功能:
匹配任意的单个字符

代码:

import re

p = re.compile('.')
print(p.match('c'))
print(p.match('d'))

# 匹配三个字符
p = re.compile('...')
print(p.match('abc'))

结果:

<re.Match object; span=(0, 1), match='c'>
<re.Match object; span=(0, 1), match='d'>
<re.Match object; span=(0, 3), match='abc'>

^ 和 $ 元字符

功能:
^:匹配以什么样的内容做开头的字符串
$:匹配以什么样的内容做结尾的字符串

代码:

# ^  以什么样的内容做开头   $   以什么样的内容做结尾(从后向前进行匹配)
# 搜索:表示从开头进行搜索。
import re

p = re.compile('^jpg')  # 匹配以jpg开头的字符串
print(p.match('jpg'))
p = re.compile('jpg$')  # 匹配以jpg结尾的字符串   匹配到所有以"jpg"为扩展名的文件
print(p.match('jpg'))

结果:

<re.Match object; span=(0, 3), match='jpg'>
<re.Match object; span=(0, 3), match='jpg'>

* 元字符

功能:
匹配前面的字符出现0次到多次。

代码:

# *  匹配前面的字符出现0次到多次
import re

p = re.compile('ca*t')
print(p.match('ct'))  # 匹配出现0次的cat —— 成功
print(p.match('caaaaaat'))  # 匹配出现多次的cat —— 成功

结果:

<re.Match object; span=(0, 2), match='ct'>
<re.Match object; span=(0, 8), match='caaaaaat'>

+ 和 ? 元字符

功能:
+:匹配前面的字符出现1次到多次
?:匹配前面的字符出现0次到1次

代码:

# + 匹配前面的字符出现1次到多次
# ? 匹配前面的字符出现0次到1次
import re

p = re.compile('c?t')
print(p.match('t'))  # 匹配出现0次的c
print(p.match('ct'))  # 匹配出现1次的c

q = re.compile('c+t')
print(q.match('ct'))  # 匹配出现1次的c
print(q.match('cccct'))  # 匹配出现多次的c

结果:

<re.Match object; span=(0, 1), match='t'>
<re.Match object; span=(0, 2), match='ct'>
<re.Match object; span=(0, 2), match='ct'>
<re.Match object; span=(0, 5), match='cccct'>

{m} 元字符

功能:
表示前面的字符要出现指定的次数为m次

代码:

import re

p = re.compile('ca{4}t')  # 匹配出现4次的a
print(p.match('caaaat'))
<re.Match object; span=(0, 6), match='caaaat'>

{m,n} 元字符

功能:
表示前面的字符要出现指定的次数为m~n次

代码:

import re

p = re.compile('ca{4,6}t')  # 匹配出现4~6次的a
print(p.match('caaaaat'))

结果:

<re.Match object; span=(0, 7), match='caaaaat'>

[] 元字符

功能:
表示中括号内的任意一个字符匹配成功即可。

代码:

# [] 表示中括号内的任意一个字符匹配成功即可
import re

p = re.compile('c[bcd]t')  # 表示bcd任意一个字符匹配成功即可
print(p.match('cat'))  # 匹配失败
print(p.match('cbt'))  # 匹配成功
print(p.match('cct'))  # 匹配成功
print(p.match('cdt'))  # 匹配成功

结果:

None
<re.Match object; span=(0, 3), match='cbt'>
<re.Match object; span=(0, 3), match='cct'>
<re.Match object; span=(0, 3), match='cdt'>

| 元字符

功能:
表示字符选择左边或者是右边,通常和括号用在一起(常和()搭配使用)

\d 元字符

功能:
表示匹配的内容是一串数字 相当于 [1234567890]+ 或 [0-9]+ 中的一个数字

\D 元字符

功能:
表示匹配的内容不包含数字

\s 元字符

功能:
表示匹配的是一个字符串(a-z)

() 元字符

功能:
进行分组

代码:

# () 进行分组
# 提取年月日份
# 2018-03-04
# (2018)-(03)-(04)
# (2018)-(03)-(04).group()  提取其中的某一组

# 匹配不同内容,但长相很相似
# 2018-03-04
# 2018-04-12
# 希望提取2018-03或2018-04
# (03|04) 只提取03或04

^$ 元字符

功能:
表示这一行是空行,匹配文本时,有一行是空行,什么都不包括

.*? 元字符

功能:
不使用贪婪模式

代码:

# .*? 不使用贪婪模式
# 贪婪模式
# abcccccd
# abc* # 会匹配到d前面所有的c           *匹配时,会尽可能长的进行匹配

# # 非贪婪模式
# abcccccd
# abc*?
# # 只匹配第一个匹配上的内容,编写网页的内容匹配上非常常用
# <img   /img>
# <img   /img>

正则表达式分组功能实例

代码:

# 利用正则实现分组功能
# 出现的字符和我们想要的字符是不是相符的
import re

p = re.compile('.{3}')  # 匹配三个任意字符 相当于 '...'
print(p.match('bat'))

# 匹配年月日,之后取出年、月、日
# q = re.compile('....-..-..')
# 如果是判断数字而且是连续的情况
q = re.compile('\d-\d-\d')
q = re.compile(r'\d-\d-\d')  # r 告诉python程序 后面的内容 原样输出 不要进行转义
q = re.compile(r'(\d)-(\d)-(\d)')  # ()把想要取出的部分进行分组
q = re.compile(r'(\d+)-(\d+)-(\d+)')  # 增加加号,因为数字可能出现多次 匹配的内容:连续的数字(05和5都能匹配上)

print(q.match('2018-05-10'))
print(q.match('2018-05-10').group())  # 取出某一部分 .group() 取出所有的部分
print(q.match('2018-05-10').group(1))  # 取出某一部分 .group(1) 取出第一个括号包括的内容
print(q.match('2018-05-10').group(2))  # 取出某一部分 .group(2) 取出第二个括号包括的内容
print(q.match('2018-05-10').groups())  # 全取出来
year, month, day = q.match('2018-05-10').groups()  # 赋给变量
print(year, month, day)

# 希望在正则匹配时,不让特殊符号进行转义
print('\nx\n')
print(r'\nx\n')

结果:

<re.Match object; span=(0, 3), match='bat'>
<re.Match object; span=(0, 10), match='2018-05-10'>
2018-05-10
2018
05
('2018', '05', '10')
2018 05 10

x

\nx\n

Process finished with exit code 0

正则表达式库函数match与search的区别

match

代码:

# match
# 匹配的字符串必须和正则一一对应,匹配之前,要清楚知道字符串是以什么样的形式出现的
import re

p = re.compile(r'(\d+)-(\d+)-(\d+)')
print(p.match('aa2018-05-10bb').group(2)) # 匹配失败 无法进行分组,进而无法进行匹配
print(p.match('2018-05-10').group())

结果:

Traceback (most recent call last):
  File "D:\Python\pythonProject\43.py", line 129, in <module>
    print(p.match('aa2018-05-10bb').group(2)) # 匹配失败 无法进行分组,进而无法进行匹配
AttributeError: 'NoneType' object has no attribute 'group'

search

代码:

import re

p = re.compile(r'(\d+)-(\d+)-(\d+)')
# search
# 不完全进行匹配   不要求把元字符和输入的内容完全匹配
print(p.search('aa2018-05-10bb'))  # 不断搜索匹配,直到能够匹配成功     只要包含了相应的正则表达式,就能匹配成功

结果:

<re.Match object; span=(2, 12), match='2018-05-10'>

match和search各自的用法

  • search经常用作在函数里面搜索指定的字符串
  • match经常完全匹配之后进行分组

正则表达式库替换函数sub()的实例

功能:
进行字符串的替换。

代码:

# sub
# 功能:进行字符串的替换
# sub(arg1, arg2, arg3)   arg1:要匹配的内容+匹配规则(元字符)   arg2:目标替换内容     arg3:替换的字符串

# 将#后面的内容替换成空的
import re
phone = '123-456-789 # 这是电话号码'
p2 = re.sub(r'#.*$', '', phone)  # arg1:匹配#后面多个任意内容,并以之结尾  arg2:目标替换为‘’空字符串   arg3:替换的字符串为phone
print(p2)
# 将中间的-也替换掉
p3 = re.sub(r'\D', '', p2)  # 将所有非数字字符替换成空的
print(p3)

代码:

<re.Match object; span=(2, 12), match='2018-05-10'>
123-456-789 
123456789

重点:

  • match和search只能match和search 到第一个匹配上的字符
  • findall 可以匹配多次

日期与时间函数库

time模块

作用:
日期和时间的查看。

代码:

import time

# 日期和时间的查看
print(time.time())  # 1970.1.1 至今的秒数
print(time.localtime())  # 年月日
print(time.strftime('%Y-%m-%d %H:%M:%S'))  # 以特定格式输出年月日(自定义格式)
print(time.strftime('%Y%m%d'))

结果:

1612482375.7951758
time.struct_time(tm_year=2021, tm_mon=2, tm_mday=5, tm_hour=7, tm_min=46, tm_sec=15, tm_wday=4, tm_yday=36, tm_isdst=0)
2021-02-05 07:46:15
20210205

datatime模块

作用:
日期和时间的修改。

代码:

# datatime
# 1. 日期和时间的修改
# 获取10min之后的时间
import datetime

print(datetime.datetime.now())  # 取现在的时间
newtime = datetime.timedelta(minutes=10)  # 10min后的时间   timedelta——偏移量
print(datetime.datetime.now() + (newtime))  # 现在的时间 + 偏移量
# 2. 获取指定日期的指定之后的时间
# 2018-5-27之后的10天
one_day = datetime.datetime(2008, 5, 27)
new_date = datetime.timedelta(days=10)
print(one_day + new_date)

结果:

2021-02-05 08:48:36.233056
2021-02-05 08:58:36.233056
2008-06-06 00:00:00

数学相关库

random

功能:
根据限定条件,取随机数

代码:

import random

# 根据限定条件,取随机数

r = random.randint(1, 5)  # 1~5随机整数
print(r)

s = random.choice(['aa', 'bb', 'cc'])  # 随机字符串
print(s)

结果:

1
aa

使用命令行对文件和文件夹操作

文件与目录操作库

os.path库

代码:
功能:
文件和目录访问。

# 文件和目录访问
import os

# 1. 根据相对路径. 来获取当前的绝对路径
jd = os.path.abspath('.')
print(jd)

# 根据相对路径. 来获取上一级的绝对路径
last_jd = os.path.abspath('..')
print(last_jd)

# 2. 判断文件是否存在
isExise = os.path.exists('/Python')  # 括号内是对应的目录
print(isExise)

# 3. 判断是否是文件
isFile = os.path.isfile('/Python')
print(isFile)

# 判断是否是目录
isDir = os.path.isdir('/Python')
print(isDir)

# 4. 路径拼接
dirJoint = os.path.join('/tmp/a/', 'b/c')  # 后面跟着需要连接的路径
print(dirJoint)

结果:

D:\Python\pythonProject
D:\Python
True
False
True
/tmp/a/b/c

pathlib库

代码:

from pathlib import Path

# 1. 获取相对路径的.  对应的绝对路径
p = Path('.')  # 先将. 封装成Path这种类型
print(p.resolve())  # 得到相对路径对应的绝对路径 相当于 os.path.abspath('.')

# 2. 列举当前路径下的所有目录 —— 列表推导式

# 3. 判断是否是目录
p.is_dir()

# 4. 新建一个目录(重点)
q = Path('/Python/a/b/c/d/e')  # 注意要用斜杠'/'      格式不能错

Path.mkdir(q, parents=True)  # 建立目录 
# arg1:建立的路径 arg2:自动创建上一层目录      parents=True 让自动创建 parents=False 不让自动创建

Path.rmdir('/Python/a/b/c/d/e')  # 删除指定目录,非空目录无法删除

结果:

D:\Python\pythonProject

Process finished with exit code 0

第十四章 机器学习库

机器学习的一般流程与NumPy安装

通用处理步骤

数据采集:

  1. 调查问卷
  2. 网络信息的采集

数据预处理:

  1. 单位统一
  2. 格式调整

数据清洗:

  1. 数据的缺失值和异常值的删减
  2. 得到优质数据

数据建模:

  1. 结合想要做的事情,设计相应的算法
  2. 把数据喂给机器
  3. 机器通过数据和算法得到结果
  4. 结果通过测试,算法可行,建立成模型

数据测试:

  1. 利用模型,完成自动驾驶、图像分类、语音预测等功能

NumPy库

功能:
进行数据预处理。
在这里插入图片描述

NumPy的数组与数据类型

在这里插入图片描述
代码:

import numpy as np

# 根据输入数据的类型自动进行转换
arr1 = np.array([2, 3, 4])  # 定义一个列表
print(arr1)  # 这个列表已经经过了numpy的封装,计算效率要远远高于自带的列表
print(arr1.dtype)  # 整型

arr2 = np.array([1.2, 2.3, 3.4])
print(arr2)
print(arr2.dtype)

# 数学计算:列表累加
print(arr1 + arr2)

结果:

[2 3 4]
int32
[1.2 2.3 3.4]
float64
[3.2 5.3 7.4]

NumPy数组和标量的计算

代码:

import numpy as np

# 标量运算
arr = np.array([1.2, 2.3, 3.4])
print(arr * 10)

# 定义二维数组(矩阵)
data = [[1, 2, 3], [4, 5, 6]]  # 两个列表嵌套在一个列表中
# 通过列表转换为numpy的二维矩阵
arr2 = np.array(data)
print(arr2)
print(arr2.dtype)

# 使二维矩阵全部为0或1
one = np.zeros(10)  # 定义了一个一维的,长度为10的数组,且将数值初始化为0
print(one)

two = np.zeros((3, 5))  # 定义了一个二维的,3×5的数组,且将数值初始化为0
print(two)

# 使矩阵内容均为1
all_one = np.ones((4, 6))  # 定义了一个二维的,4×6的数组,且将数值初始化为1
print(all_one)

# 使矩阵内容均为“空值”
all_empty = np.empty((2, 3, 2))  # 定义了一个三维的,2×3×2的数组,且将数值初始化为"空值"
print(all_empty)  # 结果为随机值(因为空值对程序运算不安全)

结果:

[12. 23. 34.]
[[1 2 3]
 [4 5 6]]
int32
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[[0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]]
[[1. 1. 1. 1. 1. 1.]
 [1. 1. 1. 1. 1. 1.]
 [1. 1. 1. 1. 1. 1.]
 [1. 1. 1. 1. 1. 1.]]
[[[0. 0.]
  [0. 0.]
  [0. 0.]]

 [[0. 0.]
  [0. 0.]
  [0. 0.]]]

NumPy数组的索引和切片

代码:

# 切片操作
import numpy as np

arr = np.arange(10)
print(arr)

print(arr[5])
print(arr[5:8])

# 对切片直接赋值
arr[5:8] = 10
print(arr)

# 重新赋值但不改变原有数值
arr_slice = arr[5:8].copy()  # 副本

arr_slice[:] = 15  # [:] 表示从第一个元素到最后一个元素全都进行了赋值

print(arr)
print(arr_slice)

结果:

[0 1 2 3 4 5 6 7 8 9]
5
[5 6 7]
[ 0  1  2  3  4 10 10 10  8  9]
[ 0  1  2  3  4 10 10 10  8  9]
[15 15 15]

pandas安装与Series结构

pandas功能:
数据预处理和数据清洗。

代码:

from pandas import Series, DataFrame
import pandas as pd

# 把数据自动或按照自定义的方式进行对齐显示
# 可以很灵活的处理缺失的数据(基于大部分熟知的平均值进行填充或指定的值)
# 连接操作

# pandas的一维数组的相关操作
obj = Series([4, 5, 6, -7])  # 对numpy的array进行了封装
print(obj)
# 好处:前面自动添加了索引,从而更方便访问到数据

# 取出索引 pandas的索引可以重复
print(obj.index)
# 取出数值
print(obj.values)

# 哈希运算(字典中的key不可重复)
# 经过一个简单字符 经过哈希运算后 得到唯一一个复杂的字符
# 'a' --> 'asdfasdfasdfasd'  # 哈希算法相同,得到的结果均一样
# 哈希值的内部存储形式——链接形式
{'a': 1, 'b': 2, 'c': 3}
# 1. 将abc分别映射成一串较为复杂的字符,存储在内存中
# a -> asdhfljasdf
# b -> askldjfaisddf
# c -> dofjwoifjife
# 字典中的key可以是:int float string tuple等
# 字典中的key不可以是:list, set # 因为他们可以重新赋值
{['a']: 1}

结果:

0    4
1    5
2    6
3   -7
dtype: int64
RangeIndex(start=0, stop=4, step=1)
[ 4  5  6 -7]
Traceback (most recent call last):
  File "D:\Python\pythonProject\pandas_test.py", line 29, in <module>
    {['a']: 1}
TypeError: unhashable type: 'list'

Series的基本操作

代码:

import pandas as pd
from pandas import Series

# 对pandas中的一维数组(Series)的操作
obj2 = Series([4, 7, -5, 3], index=['d', 'b', 'c', 'a'])  # 手动指定索引
print(obj2)
# 对索引赋值
obj2['c'] = 6
print(obj2)

# 查看索引是否在Series中
print('a' in obj2)
print('f' in obj2)

# 字典转化为Series
sdata = {'beijing': 35000, 'shanghai': 71000, 'guangzhou': 16000, 'shenzhen': 5000}
obj3 = Series(sdata)
print(obj3)

# 修改Series的索引
obj3.index = ['bj', 'gz', 'sh', 'sz']
print(obj3)

结果:

d    4
b    7
c   -5
a    3
dtype: int64
d    4
b    7
c    6
a    3
dtype: int64
True
False
beijing      35000
shanghai     71000
guangzhou    16000
shenzhen      5000
dtype: int64
bj    35000
gz    71000
sh    16000
sz     5000
dtype: int64

Dataframe的基本操作

代码:

from pandas import Series, DataFrame  # 类似于 电子表格

# 生成dataframe
# 传入等长的列表 或 numpy的数组
# 利用字典 ,字典内用等长列表方式创建一个DataFrame
data = {'city': ['shanghai', 'shanghai', 'shanghai', 'beijing', 'beijing'],
        'year': [2016, 2017, 2018, 2017, 2018],
        'pop': [1.5, 1.7, 3.6, 2.4, 2.9]}

# 将字典赋给DataFrame
frame = DataFrame(data)
print(frame)

# 按指定顺序排序
frame2 = DataFrame(data, columns=['year', 'city', 'pop'])  # 按year city pop 显示
print(frame2)

# 提取一维数据(二维 -> 一维)
print(frame2['city'])
print(frame2.year)

# 增加一列
frame2['new'] = 100
print(frame2)
# 利用计算生成新列
# city 是 beijing 新列为True     不是 beijing 新列为False
frame2['cap'] = frame2.city == 'beijing'
print(frame2)

# 字典嵌套
pop = {'beijing': {2008: 1.5, 2009: 2.0},
       'shanghai': {2008: 2.0, 2009: 3.6}
       }
frame3 = DataFrame(pop)
print(frame3)

# 行列互换(行列式的转置)
print(frame3.T)

# 重新索引(对当前的索引重新修改)
obj4 = Series([4.5, 7.2, -5.3, 3.6], index=['b', 'd', 'c', 'a'])
obj5 = obj4.reindex(['a', 'b', 'c', 'd', 'e'])
print(obj5)  # NaN代表空值

# 过滤缺失值
# 统一填充空值
obj6 = obj4.reindex(['a', 'b', 'c', 'd', 'e'], fill_value=0)
print(obj6)

# 统一填充空值为相邻元素的值
# 填充当前值上面的或下面的值
obj7 = Series(['blue', 'purple', 'yellow'], index=[0, 2, 4])
obj7_new = obj7.reindex(range(6))
print(obj7_new)
# 利用前面的值进行填充
obj7_newf = obj7.reindex(range(6), method='ffill')
print(obj7_newf)
# 利用后面的值进行填充
obj7_newb = obj7.reindex(range(6), method='bfill')
print(obj7_newb)

# 把缺失的数据删除
from numpy import nan as NA  # 从numpy导入一个缺失值并将其重命名为NA

data = Series([1, NA, 2])
print(data)
print(data.dropna())  # 删除 缺失值

# DataFrame 的删除缺失数据
data2 = DataFrame([[1., 6.5, 3], [1., NA, NA], [NA, NA, NA]])
print(data2)
print(data2.dropna())  # 出现NA的行列均会被删除

# 删除全是缺失值的一行,而有部分缺失值的一行进行保留
print(data2.dropna(how='all'))

data2[4] = NA
print(data2)
# 删除全是缺失值的一列,而有部分缺失值的一列进行保留
print(data2.dropna(axis=1, how='all'))

# 填充方法:fillna   把缺失值全部填充为0
data2.fillna(0)  # 修改的只是data2的副本
print(data2.fillna(0))
print(data2.fillna(0, inplace=True))  # 对data2直接进行修改
print(data2)

结果:

       city  year  pop
0  shanghai  2016  1.5
1  shanghai  2017  1.7
2  shanghai  2018  3.6
3   beijing  2017  2.4
4   beijing  2018  2.9
   year      city  pop
0  2016  shanghai  1.5
1  2017  shanghai  1.7
2  2018  shanghai  3.6
3  2017   beijing  2.4
4  2018   beijing  2.9
0    shanghai
1    shanghai
2    shanghai
3     beijing
4     beijing
Name: city, dtype: object
0    2016
1    2017
2    2018
3    2017
4    2018
Name: year, dtype: int64
   year      city  pop  new
0  2016  shanghai  1.5  100
1  2017  shanghai  1.7  100
2  2018  shanghai  3.6  100
3  2017   beijing  2.4  100
4  2018   beijing  2.9  100
   year      city  pop  new    cap
0  2016  shanghai  1.5  100  False
1  2017  shanghai  1.7  100  False
2  2018  shanghai  3.6  100  False
3  2017   beijing  2.4  100   True
4  2018   beijing  2.9  100   True
      beijing  shanghai
2008      1.5       2.0
2009      2.0       3.6
          2008  2009
beijing    1.5   2.0
shanghai   2.0   3.6
a    3.6
b    4.5
c   -5.3
d    7.2
e    NaN
dtype: float64
a    3.6
b    4.5
c   -5.3
d    7.2
e    0.0
dtype: float64
0      blue
1       NaN
2    purple
3       NaN
4    yellow
5       NaN
dtype: object
0      blue
1      blue
2    purple
3    purple
4    yellow
5    yellow
dtype: object
0      blue
1    purple
2    purple
3    yellow
4    yellow
5       NaN
dtype: object
0    1.0
1    NaN
2    2.0
dtype: float64
0    1.0
2    2.0
dtype: float64
     0    1    2
0  1.0  6.5  3.0
1  1.0  NaN  NaN
2  NaN  NaN  NaN
     0    1    2
0  1.0  6.5  3.0
     0    1    2
0  1.0  6.5  3.0
1  1.0  NaN  NaN
     0    1    2   4
0  1.0  6.5  3.0 NaN
1  1.0  NaN  NaN NaN
2  NaN  NaN  NaN NaN
     0    1    2
0  1.0  6.5  3.0
1  1.0  NaN  NaN
2  NaN  NaN  NaN
     0    1    2    4
0  1.0  6.5  3.0  0.0
1  1.0  0.0  0.0  0.0
2  0.0  0.0  0.0  0.0
None
     0    1    2    4
0  1.0  6.5  3.0  0.0
1  1.0  0.0  0.0  0.0
2  0.0  0.0  0.0  0.0

层次化索引

代码:

# 层次化索引
# 多层次索引
# Series——一维数据    DataFrame——二维数据
from pandas import Series, DataFrame
import numpy as np

data3 = Series(np.random.randn(10),
               index=[['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'd', 'd'],
                      [1, 2, 3, 1, 2, 3, 1, 2, 2, 3]])
print(data3)
# 提取索引b下边的数据
print(data3['b'])

# 提取多个索引
print(data3['b':'c'])

# Series转化成DataFrame      一维数据转化成二维数据
print(data3.unstack())

# DataFrame转化成Series      二维数据转化成一维数据
print(data3.unstack().stack())

结果:

a  1    0.254799
   2    1.096555
   3    0.283251
b  1    1.009634
   2   -0.643421
   3    1.774040
c  1    0.550576
   2   -0.687114
d  2    0.308054
   3    0.788189
dtype: float64
1    1.009634
2   -0.643421
3    1.774040
dtype: float64
b  1    1.009634
   2   -0.643421
   3    1.774040
c  1    0.550576
   2   -0.687114
dtype: float64
          1         2         3
a  0.254799  1.096555  0.283251
b  1.009634 -0.643421  1.774040
c  0.550576 -0.687114       NaN
d       NaN  0.308054  0.788189
a  1    0.254799
   2    1.096555
   3    0.283251
b  1    1.009634
   2   -0.643421
   3    1.774040
c  1    0.550576
   2   -0.687114
d  2    0.308054
   3    0.788189
dtype: float64

Matplotlib的安装与绘图

代码:

import matplotlib.pyplot as plt
import numpy as np

# # 绘制简单的曲线
# plt.plot([1, 3, 5], [4, 8, 10])  # x轴   y轴
# plt.show()  # 显示曲线
#
# # 绘制numpy中的数据
# x = np.linspace(-np.pi, np.pi, 100)  # x的定义域为 -3.14~3.14,中间间隔100个元素
# plt.plot(x, np.sin(x))  # 横坐标:x值     纵坐标:sinx值
# plt.show()
#
# # 绘制多条曲线
# x = np.linspace(-np.pi * 2, np.pi * 2, 100)  # 定义域为: -2pi 到 2pi
# plt.figure(1, dpi=50)  # 创建图表       dpi:精度(绘画图形的详细程度)精度越高,图片产生的体积越大,画的图越清晰
# for i in range(1, 5):  # 画四条线
#     plt.plot(x, np.sin(x / i))
#
# plt.show()
#
# # 绘制直方图
# plt.figure(1, dpi=50)  # 创建图表1, dpi代表图片精细度, dpi越大文件越大, 杂志要300以上
# data = [1, 1, 1, 2, 2, 2, 3, 3, 4, 5, 5, 6, 4]
# plt.hist(data)  # 只要传入数据,直方图就会统计数据出现的次数
#
# plt.show()
#
# # 绘制散点图
# x = np.arange(1, 10)
# y = x
# fig = plt.figure()  # 创建图表
# plt.scatter(x, y, c='r', marker='o')  # c = 'r' 表示散点的颜色为红色,marker 表示指定散点的形状为圆形
# plt.show()

# pandas 和 matplotlib 结合
# pandas读取数据——matplotlib绘图
import pandas as pd
#
# iris = pd.read_csv("./iris_training.csv")
# print(iris.head())  # 显示iris前五行信息
#
# # 基于前两列绘制散点图
# iris.plot(kind='scatter', x='120', y='4')  # 散点图 x轴 y轴
#
# # 没啥用,只是让pandas的plot()方法在pyCharm上显示
# plt.show()

# 封装matplotlib库的库
import seaborn as sns
import warnings  # 忽略警告

warnings.filterwarnings("ignore")  # 当产生warnings时,进行ignore

iris = pd.read_csv("./iris_training.csv")
# 设置样式
sns.set(style="white", color_codes=True)
# 设置绘制格式为散点图
# sns.jointplot(x="120", y="4", data=iris, size=5)
# distplot绘制曲线
# sns.distplot(iris['120'])  # 绘制120对应的散点图

# 没啥用,只是让pandas的plot()方法在pyCharm上显示
# plt.show()

# 基于不同分类,对点进行不同颜色的划分
# FacetGrid 一般绘图函数
# hue 彩色显示分类0/1/2
# plt.scatter 绘制散点图
# add_legend() 显示分类的描述信息
# sns.FacetGrid(iris, hue="virginica", size=5).map(plt.scatter, "120", "4").add_legend()  # hue 基于virginica不同取值,对散点不同颜色绘制

# 显示第3、4列相应的信息
sns.FacetGrid(iris, hue="virginica", size=5).map(plt.scatter, "setosa", "versicolor").add_legend()

# 没啥用,只是让pandas的plot()方法在pyCharm上显示
plt.show()

结果:

在这里插入图片描述

机器学习分类的原理

工作原理:
特征值与对应的分类结果数据输入到机器学习算法中——得到模型——测试模型——输入新值进行预测

Tensorflow的安装

根据特征值分类的模型和代码

第十五章 爬虫

网页数据的采集与urllib库

在这里插入图片描述代码:

# 获取网页
from urllib import request

url = 'http://www.baidu.com'  # http协议
# 解析url
response = request.urlopen(url, timeout=1)  # timeout 设置超时时间(超过1s没打开就放弃打开网页)
print(response.read().decode('utf-8'))  # 直接读会读出乱码,需要解析需要编码的格式为utf-8

网页常见的两种请求方式get和post

代码:

# 请求网页两种方式
from urllib import parse  # parse用来处理post数据
from urllib import request

# GET方式
# 输入网址时,后面跟着要传给网页的参数
# 把要传给网页服务器的信息,写在url地址内
# httpbin.org/get?a=123&bb=456 告诉服务器要给它传给a和b两个值     之后服务器会显示出来
# 好处:往服务器传递数据时很简单;坏处:传输数据大小的限制

response = request.urlopen('http://httpbin.org/get', timeout=1)  # 后面没有data参数的为get方式
print(response.read())

# POST方式
# 提交用户名,密码时,用post提交   在网页中输入完用户名和密码没有在url地址栏出现

data = bytes(parse.urlencode({'word': 'hellp'}), encoding='utf8')  # 用data封装数据
response2 = request.urlopen('http://httpbin.org/post', data=data)  # data=data 指定要传输的数据
print(response2.read().decode('utf-8'))

import urllib
import socket  # 套接字库(网络超时一般发生于此)

# 超时情况
try:
    response3 = request.urlopen('http://httpbin.org/get', timeout=0.1)
except urllib.error.URLError as e:
    if isinstance(e.reason, socket.timeout): # 判断error的错误是否是超时引起的
        print('TIME OUT')

结果:

b'{\n  "args": {}, \n  "headers": {\n    "Accept-Encoding": "identity", \n    "Host": "httpbin.org", \n    "User-Agent": "Python-urllib/3.8", \n    "X-Amzn-Trace-Id": "Root=1-601f3179-477c6caf31b7d3e6394fe965"\n  }, \n  "origin": "1.50.125.140", \n  "url": "http://httpbin.org/get"\n}\n'
{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {
    "word": "hellp"
  }, 
  "headers": {
    "Accept-Encoding": "identity", 
    "Content-Length": "10", 
    "Content-Type": "application/x-www-form-urlencoded", 
    "Host": "httpbin.org", 
    "User-Agent": "Python-urllib/3.8", 
    "X-Amzn-Trace-Id": "Root=1-601f317a-116916d86dd759e02cda01f4"
  }, 
  "json": null, 
  "origin": "1.50.125.140", 
  "url": "http://httpbin.org/post"
}

TIME OUT

HTTP头部信息的模拟

# url伪装成浏览器去请求网页信息
from urllib import request, parse

url = 'http://httpbin.org/post'

headers = {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
    "Accept-Encoding": "gzip, deflate",
    "Accept-Language": "zh-CN,zh;q=0.9",
    "Cache-Control": "max-age=259200",
    "Host": "httpbin.org",
    "Upgrade-Insecure-Requests": "1",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36",
    "X-Amzn-Trace-Id": "Root=1-601f3d71-47afea5509bb17d15ab795ec"
}

dict = {
    'name': 'value'
}

data = bytes(parse.urlencode(dict), encoding='utf8')
req = request.Request(url=url, data=data, headers=headers, method='POST')
response = request.urlopen(req)
print(response.read().decode('utf-8'))

{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {
    "name": "value"
  }, 
  "headers": {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", 
    "Accept-Encoding": "gzip, deflate", 
    "Accept-Language": "zh-CN,zh;q=0.9", 
    "Cache-Control": "max-age=259200", 
    "Content-Length": "10", 
    "Content-Type": "application/x-www-form-urlencoded", 
    "Host": "httpbin.org", 
    "Upgrade-Insecure-Requests": "1", 
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36", 
    "X-Amzn-Trace-Id": "Self=1-601f3dee-7861d78308a6c5be459b26a8;Root=1-601f3d71-47afea5509bb17d15ab795ec"
  }, 
  "json": null, 
  "origin": "1.50.125.140", 
  "url": "http://httpbin.org/post"
}

requests库的基本使用

# get请求
import requests

url = 'http://httpbin.org/get'
data = {'key': 'value', 'abc': 'xyz'} # 传递给服务器的数据
# .get是使用get方式请求url,字典类型的data不用进行额外处理
response = requests.get(url, data)
print(response.text)

# post请求
url = 'http://httpbin.org/post'
data = {'key': 'value', 'abc': 'xyz'}
# .post表示为post方法
response = requests.post(url, data)
# 返回类型为json格式
print(response.json())

结合正则表达式爬取图片链接

import requests
import re

content = requests.get('http://www.cnu.cc/discoveryPage/hot-人像').text

print(content)

# <div class="grid-item work-thumbnail">
# <a href="(http://www.cnu.cc/works/244938)" class = "thumbnail" target="_blank">
# <div class="title">( Fashion kids | 复古童年 )</div>
# <div class="author">LynnWei </div>

# <a href="(.*?)" .*?title">( .*? )</div>

pattern = re.compile(r'<a href="(.*?)".*?title">(.*?)</div>', re.S)
results = re.findall(pattern, content)
print(results)  # 显示的是 列表中的元组 形式

# 把列表中每个元素取出来
for result in results:
    url, name = result
    print(url, re.sub('\s', '', name))  # \s匹配空白字符   \n等特殊符号全能被\s匹配上,进而替换成空值''

Beautiful Soup的安装和使用

# 无需编写正则,也可以匹配html语言
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>
"""

from bs4 import BeautifulSoup

# 将网页的内容导入进去
soup = BeautifulSoup(html_doc, 'lxml')  # 用lxml格式解析html

# 处理为标准的html格式
print(soup.prettify())

# 找到title标签
print(soup.title)

# title标签里的内容
print(soup.title.string)

# 找到p标签
print(soup.p)

# 找到p标签class的名字
print(soup.p['class'])

# 找到第一个a标签
print(soup.a)

# 找到所有的a标签
print(soup.find_all('a'))

# 找到id为link3的标签
print(soup.find(id="link3"))

# 找到所有<a>标签的链接
for link in soup.find_all('a'):
    print(link.get('href'))

# 找到文档中所有的文本内容
print(soup.get_text())

使用爬虫爬取新闻网站

# requests 抓取文字  beautiful soup 进行处理
from bs4 import BeautifulSoup
import requests

# 告诉网站我们是一个合法的浏览器
headers = {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
    "Accept-Language": "zh-CN,zh;q=0.8",
    "Connection": "close",
    "Cookie": "_gauges_unique_hour=1; _gauges_unique_day=1; _gauges_unique_month=1; _gauges_unique_year=1; _gauges_unique=1",
    "Referer": "http://www.infoq.com",
    "Upgrade-Insecure-Requests": "1",
    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 LBBROWSER"
}

url = 'https://www.infoq.com/news/'


# 取得网页完整内容


def craw(url):
    response = requests.get(url, headers=headers)
    print(response.text)


# craw(url)

# 取得新闻标题


def craw2(url):
    response = requests.get(url, headers=headers)

    soup = BeautifulSoup(response.text, 'lxml')

    for title_href in soup.find_all('div', class_='news_type_block'):
        print([title.get('title')
               for title in title_href.find_all('a') if title.get('title')])


craw2(url)

# 翻页
for i in range(15, 46, 15):
    url = 'http://www.infoq.com/cn/news/' + str(i)
    # print(url)
    craw2(url)

使用爬虫爬取图片链接并下载图片

# 通过requests实现图片的批量下载
# 获取图片的链接地址
from bs4 import BeautifulSoup
import requests
import os
import shutil

headers = {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
    "Accept-Language": "zh-CN,zh;q=0.8",
    "Connection": "close",
    "Cookie": "_gauges_unique_hour=1; _gauges_unique_day=1; _gauges_unique_month=1; _gauges_unique_year=1; _gauges_unique=1",
    "Referer": "http://www.infoq.com",
    "Upgrade-Insecure-Requests": "1",
    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 LBBROWSER"
}

url = 'http://www.infoq.com/presentations'


# 下载图片
# Requests 库封装复杂的接口,提供更人性化的 HTTP 客户端,但不直接提供下载文件的函数。
# 需要通过为请求设置特殊参数 stream 来实现。当 stream 设为 True 时,
# 上述请求只下载HTTP响应头,并保持连接处于打开状态,
# 直到访问 Response.content 属性时才开始下载响应主体内容


def download_jpg(image_url, image_localpath):
    response = requests.get(image_url, stream=True)
    if response.status_code == 200:
        with open(image_localpath, 'wb') as f:
            response.raw.deconde_content = True
            shutil.copyfileobj(response.raw, f)


# 取得演讲图片
def craw3(url):
    response = requests.get(url, headers=headers)
    soup = BeautifulSoup(response.text, 'lxml')
    for pic_href in soup.find_all('div', class_='items__content'):
        for pic in pic_href.find_all('img'):
            imgurl = pic.get('src')
            dir = os.path.abspath('.')
            filename = os.path.basename(imgurl)
            imgpath = os.path.join(dir, filename)
            print('开始下载 %s' % imgurl)
            download_jpg(imgurl, imgpath)


# craw3(url)

# 翻页
j = 0
for i in range(12, 37, 12):
    url = 'http://www.infoq.com/presentations' + str(i)
    j += 1
    print('第 %d 页' % j)
    craw3(url)
这篇关于《零基础学Python》——极客时间——学习笔记的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!