Python教程

1 Python基本语法

R语言 - 包更多,功能拓展更丰富编程更复杂,容易出错

Python - 简洁、遍历、不易错性,是火爆市场的不二法门

学习Python编程的利器:
Python官方文档:https://www.python.org/doc/

iPython:https://www.ipython.org/

jupyter notebook:http://jupyter-notebook.readthedocs.io/cn/latest/

Pycharm:https://www.jetbrains.com/pycharm/

Pip:https://pip.pypa.io/en/stable/installing/

基本数据类型:

  • 整数(int)
  • 浮点数(float)
  • 字符串(str)
  • 布尔值(bool)

具体效果如图:

image-20220318200613202

注意:truefalse不是bool类型,TrueFalse为bool类型

可以通过以下命令将字符进行转换

1
int('8')

输出结果为数字类型的8。

同理,如图:

image-20220318201638704

示例:

1
2
3
4
# 网络带宽计算
bandwidth = 100
ratio = 8
print(bandwidth / ratio)

==注意==:Python对于单引号和双引号没有区分,如果想用引号的嵌套,需要用双引号。

对于不懂的函数可以通过help(语法)来进行学习。

为了写出的代码非常美观,应当尽量满足PEP8规范:https://peps.python.org/pep-0008/

2 序列

2.1 序列的概念

序列:指的是它的成员都是有序排列并且可以i通过下表偏移量访问到它的一个或几个成员

字符串列表元组三种类型都属于序列

  • 字符串:“abcd”
  • 列表:[0,"abcd"]
  • 元组:("abc","def")

2.2 字符串的定义和使用

示例1:

1
2
3
4
5
# 记录生肖,根据年份判断生肖
chinese_zodiac = '鼠牛虎兔龙蛇马羊猴鸡狗猪'
print(chinese_zodiac[0:4]) # 访问的下标是0-3,输出的是 鼠牛虎兔
print(chinese_zodiac[-1]) # 输出的是 猪
print(chinese_zodiac[-3]) # 输出的是 鸡

示例2:

1
2
3
4
5
# 记录生肖,根据年份判断生肖
chinese_zodiac = '猴鸡狗猪鼠牛虎兔龙蛇马羊'
year = 2022
print(year % 12) # 输出 6
print(chinese_zodiac[year % 12]) # 输出 虎

字符串的常用操作

  1. 成员关系操作符 in not in 示例:对象 [not] in 序列
  2. 连接操作符 + 示例:序列 + 序列
  3. 重复操作符 * 示例:序列 * 序列
  4. 切片操作符 [:] 示例:序列[0:整数]

示例:

1
2
3
4
5
6
7
8
9
10
11
12
# 记录生肖,根据年份判断生肖
chinese_zodiac = '猴鸡狗猪鼠牛虎兔龙蛇马羊'

# 成员关系操作符
print('狗' not in chinese_zodiac) # 输出为 False
# 链接操作符
print(chinese_zodiac + chinese_zodiac) # 输出为 猴鸡狗猪鼠牛虎兔龙蛇马羊猴鸡狗猪鼠牛虎兔龙蛇马羊
print(chinese_zodiac + 'abcd') # 输出为 猴鸡狗猪鼠牛虎兔龙蛇马羊abcd
# 重复操作符
print(chinese_zodiac * 3) # 输出为 猴鸡狗猪鼠牛虎兔龙蛇马羊猴鸡狗猪鼠牛虎兔龙蛇马羊猴鸡狗猪鼠牛虎兔龙蛇马羊
# 切片操作符
print(chinese_zodiac[0:2]) # 输出为 猴鸡

==注意==:列表和元组的区别,列表中的数据可以变更,元组中的数据不能变更。

2.2 元组的定义和常用操作

示例:在Python的shell中输入以下代码:

1
2
3
4
5
6
7
8
9
a=(1,3,5,7)
b=4
filter(lambda x: x < b , a) #输出为 <filter object at 0x000002715049DB40>
list (filter(lambda x: x < b , a)) #输出为 [1, 3]
len(list (filter(lambda x: x < b , a))) #输出为 2
b=6
len(list (filter(lambda x: x < b , a))) #输出为 3
b=8
len(list (filter(lambda x: x < b , a))) #输出为 4

效果如图:

image-20220318221706992

示例:

1
2
3
4
5
6
7
8
zodiac_name = ('魔羯座', '水瓶座', '双鱼座', '白羊座', '金牛座', '双子座',
'巨蟹座', '狮子座', '处女座', '天秤座', '天蝎座', '射手座')
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))
(month, day) = (2, 15)
zodiac_day = filter(lambda x: x <= (month, day), zodiac_days)
print(zodiac_day) # 输出 <filter object at 0x000001B54FF3BF10>
print(list(zodiac_day))# 输出 [(1, 20)]

2.3 列表的定义和常用操作

示例:

1
2
3
4
5
a_list=['abc','xyz']
a_list.append('X')
print(a_list) #输出为 ['abc', 'xyz', 'X']
a_list.remove('xyz')
print(a_list) #输出为 ['abc', 'X']

3 条件与循环

3.1 条件语句

条件语句:if

使用方法:

1
2
if 表达式: 
代码块

1
2
3
4
5
6
if 表达式: 
代码块
elif 表达式:
代码块
else:
代码块

示例1:

1
2
3
x = 'abc'
if x == 'abc':
print('x的值和abc相等') # 输出 x的值和abc相等

示例2:

1
2
3
4
5
x = 'abcd'
if x == 'abc':
print('x的值和abc相等')
else:
print('x的值和abc不相等') # 输出 x的值和abc不相等

示例3:

1
2
3
4
5
6
7
x = 5
if x < 5:
print('x<5>')
elif x == 5:
print('x=5') # 输出 x=5
else:
print('x>5')

示例4:

1
2
3
4
chinese_zodiac = '猴鸡狗猪鼠牛虎兔龙蛇马羊'
year = int(input('请用户输入出生年份'))
if chinese_zodiac[year % 12] == '狗':
print('狗年运势') # 输入:2018 输出: 狗年运势

3.2 循环语句

3.2.1 for语句

for语句使用方法:

1
2
for 迭代变量 in 可迭代对象:
代码块

示例:

1
2
3
4
5
6
7
8
9
chinese_zodiac = '猴鸡狗猪鼠牛虎兔龙蛇马羊'
for cz in chinese_zodiac: #不需要定义变量cz,默认从第一个字符开始
print(cz) # 输出 猴鸡狗猪鼠牛虎兔龙蛇马羊
for i in range(13):
print(i) # 输出 0 1 2 3 4 5 6 7 8 9 10 11 12
for j in range(1, 13):
print(j) # 输出 1 2 3 4 5 6 7 8 9 10 11 12
for year in range(2000, 2019):
print('%s 年的生肖是 %s' % (year, chinese_zodiac[year % 12])) # 输出 2000年的生肖是龙 2001年的生肖是蛇 ...

示例2:

1
2
3
4
5
6
7
8
9
10
11
12
zodiac_name = ('魔羯座', '水瓶座', '双鱼座', '白羊座', '金牛座', '双子座', '巨蟹座', '狮子座', '处女座', '天秤座', '天蝎座', '射手座')
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))
int_month = int(input('请输入月份:'))
int_day = int(input('请输入日期:'))
for zd_num in range(len(zodiac_days)): # len是计算列表的长度 range是取值范围
if zodiac_days[zd_num] >= (int_month, int_day):
print(zodiac_name[zd_num])
break
elif int_day == 12 and int_day > 23:
print(zodiac_name[0])
break

输出结果:

image-20220319093114795

3.2.2 while语句

while语句使用方法:

1
2
while 表达式: 
代码块

示例:

1
2
3
4
5
6
7
8
9
number = 8
while True:
print(number)
number = number + 1
if number == 12:
break
if number > 10:
print('a')
continue

运行结果为: 8 9 10 a 11

示例2:

1
2
3
4
5
6
7
8
9
10
11
zodiac_name = ('魔羯座', '水瓶座', '双鱼座', '白羊座', '金牛座', '双子座', '巨蟹座', '狮子座', '处女座', '天秤座', '天蝎座', '射手座')
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))
int_month = int(input('请输入月份:'))
int_day = int(input('请输入日期:'))
n = 0
while zodiac_days[n] < (int_month, int_day):
if int_month == 12 and int_day > 23:
break
n += 1
print(zodiac_name[n])

运行结果:

image-20220319094458102

4 映射与字典

4.1 字典的定义和常用操作

映射的类型:字典

字典包含哈希值和指向的对象。

使用方法:{"哈希值":"对象"} 例如:{'length':180, 'width':80}

示例:

1
2
3
4
5
dict1 = {}
print(type(dict1))
dict2 = {'x': 1, 'y': 2}
dict2['z'] = 3
print(dict2)

运行结果:

image-20220319101207737

示例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
chinese_zodiac = '鼠牛虎兔龙蛇马羊猴鸡狗猪'
zodiac_name = ('魔羯座', '水瓶座', '双鱼座', '白羊座', '金牛座', '双子座',
'巨蟹座', '狮子座', '处女座', '天秤座', '天蝎座', '射手座')
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 = {}
for i in chinese_zodiac:
cz_num[i] = 0
z_num = {}
for i in zodiac_name:
z_num[i] = 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(zodiac_name[n])
print('%s 年的生肖是 %s' % (year, chinese_zodiac[(year + 8) % 12]))
cz_num[chinese_zodiac[(year + 8) % 12]] += 1
z_num[zodiac_name[(year + 8) % 12]] += 1

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

for each_key in z_num.keys():
print('星座 %s 有 %d 个' % (each_key, z_num[each_key])) # 字符串输出用%s,整数输出用%d

4.2 列表推导式与字典推导式

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 从 1 到 10 的所有偶数的平方
# 列表推导式
# 方法一:传统方法
alist = []
for i in range(1, 11):
if ((i % 2) == 0):
alist.append(i*i)
print(alist)
# 方法二:列表推导式
blist = [i*i for i in range(1, 11) if(i % 2) == 0]
print(blist)

# 字典推导式
zodiac_name = ('魔羯座', '水瓶座', '双鱼座', '白羊座', '金牛座', '双子座',
'巨蟹座', '狮子座', '处女座', '天秤座', '天蝎座', '射手座')
z_num = {}
for i in zodiac_name:
z_num[i] = 0
print(z_num)

z_num = {i: 0 for i in zodiac_name}
print(z_num)

5 文件和输入输出

使用Python对文件进行基本的读写操作:

  • 打开文件 open()
  • 输入 read()
  • 输入一行 readline()
  • 文件内移动 seek()
  • 输出 write()
  • 关闭文件 close()

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 将小说的主要人物记录在文件中
file1 = open('name.txt', 'w') # 如果没有标注打开的模式,默认以只读的方式打开 w是写入
file1.write('诸葛亮')
file1.close()

file2 = open('name.txt') # 以只读的方式打开
print(file2.read())
file2.close()

file3 = open('name.txt', 'a') # 如果直接写,会将原有的内容覆盖掉,用 a 用来增加内容
file3.write('刘备')
file3.close()

file4 = open('name.txt')
print(file4.readline())

file5 = open('name.txt')
for line in file5.readlines():
print(line)
print('**********')

运行输出:

image-20220319111819333

同时会产生一个name.txt文件,文件内容为:

1
诸葛亮刘备

示例2:读取多行

1
2
3
4
5
6
7
8
file4 = open('name.txt')
print(file4.readline()) #读取第一行
file4.close()

file5 = open('name.txt')
for line in file5.readlines():
print(line) # line已经代表每一行的值
file5.close()

运行结果:

image-20220319113014580

示例3:

1
2
3
4
5
6
7
8
9
10
11
12
13
file6 = open('name.txt')
print('当前文件指针的位置 %s ' % file6.tell()) # 告诉文件光标在什么位置
print('当前读取了一个字符 %s ' % file6.read(4)) # 告诉文件光标在什么位置
print('当前指针的位置 %s ' % file6.tell()) # 告诉文件光标在什么位置
# seek()中如果有两个参数,第一个参数代表偏移的位置,第二个参数 0 表示从文件开头偏移 1 表示从当前位置偏移 2 表示从文件结尾
# file6.seek(0) #表示光标回到文件开头
print(file6.seek(6, 0))
print('当前文件指针的位置 %s ' % file6.tell()) # 告诉文件光标在什么位置
print('我们进行了seek操作') # seek中可以填写两个参数,第一个为偏移位置,当前的位置 file6.seek(0)为回到指针0
print('当前文件指针的位置 %s ' % file6.tell()) # 告诉文件光标在什么位置
print('当前读取了一个字符 %s ' % file6.read(1)) # 告诉文件光标在什么位置
print('当前指针的位置 %s ' % file6.tell()) # 告诉文件光标在什么位置
file6.close()

运行结果:

image-20220319115037577

6 错误和异常

==错误 ≠ 异常==

异常是在出现错误时采用正常控制流以外的动作

异常处理的一般流程是:检测到错误,引发异常;对异常进行捕获的操作

使用方法:

1
2
3
4
5
6
try:
<监控异常>
except Exception[, reason]:
<异常处理代码>
finally:
<无论异常是否发生都执行>

示例1:

1
2
3
4
try:
year = int(input('input year:'))
except ValueError:
print('年份要输入数字:')

运行结果:

image-20220320095206545

可以通过组成元组来进行多个错误捕获:except (ValueError, AttributeError, KeyError, ZeroDivisionError)

示例2:

1
2
3
4
try:
print(1 / 0)
except (ValueError, AttributeError, KeyError, ZeroDivisionError) as e:
print('这里对异常捕获 %s' % e)

这里将错误提示信息重新命名为变量,并进行打印,常用于调试时的错误信息提示。

运行结果:

image-20220320101402211

示例3:

1
2
3
4
try:
print(1 / 'a')
except Exception as a:
print('%s' % a)

运行结果:

image-20220320101326850

示例4:可以通过raise来自定义错误类型

1
2
3
4
try:
raise NameError('helloError') # 可以自己定义错误信息
except NameError:
print('my custom error')

示例5:

1
2
3
4
5
6
try:
aaa = open('name1.txt') # 可以自己定义错误信息
except Exception as e:
print(e)
finally:
aaa.close()

7 函数

7.1 函数的定义和常用操作

函数:函数是对程序逻辑进行结构化的一种编程方法。

函数的定义:

1
2
3
def 函数名称():
代码
return 需要返回的内容

函数的调用:

1
函数名称()

示例1:

原始未利用自定义函数的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 读取人物
f = open('name.txt')
data = f.read()
print(data.split('|'))

# 读取兵器的名称
f2 = open('weapon.txt', encoding='utf-8')
# data2 = f2.read()
i = 1
for line in f2.readlines():
if i % 2 == 1:
print(line.strip('\n')) # 通过strip('\n')将文件末尾的换行符进行删除
i += 1

f3 = open('sanguo.txt', encoding='utf-8')
print(f3.read().replace('\n', '')) # 读取内容,并将文本中的换行替换成空格

可以利用函数进行实现:

1
2
3
4
5
def func(filename):
print(open(filename).read())

print('test func')
func('name.txt')

示例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import re

def find_item(hero):
with open('sanguo.txt', encoding='utf-8') as f:
data = f.read().replace('\n', '')
name_num = re.findall(hero, data) # 这里的findall是出现一次输出一次
print('主角 %s 出现了 %s 次' % (hero, len(name_num)))
return name_num

# 读取人物的信息
name_dict = {}
with open('name.txt') as f:
for line in f:
names = line.split('|')
for n in names:
# print(n)
name_num = find_item(n)
name_dict[n] = name_num

运行结果:

image-20220320112533528

7.2 函数的可变长操作

在函数中,需要按照顺序进行参数传入,如果想跳跃使用,则通过关键字参数来进行调用,示例如图:

image-20220320113619401

示例1:

1
2
3
4
5
6
7
def func(a, b, c):
print('a = %s' % a)
print('b = %s' % b)
print('c = %s' % c)


func(1, c=3, b=2)

运行结果:

image-20220320114913143

示例2:

1
2
3
4
5
6
7
#  取参数的个数
def howlong(first, *other): # 通过加*的方式变为可变长参数,未加*的参数必须要进行填写
print(1 + len(other))


howlong(10, 20, 30)
howlong(2)

运行结果:

image-20220320115042393

7.3 函数的变量作用域

当函数外部的变量赋值后,在函数内部使用相同名称的变量时,会默认使用函数外部的变量;如果在函数内部对变量进行重新赋值,则会新建一个函数内部的变量,该变量的名称和函数外部定义的变量名称相同。

示例1:

1
2
3
4
5
6
var1 = 123
def func():
print(var1)


func()

运行结果:

image-20220320125032063

示例2:

1
2
3
4
5
6
7
8
9
var1 = 123

def func():
var1 = 456
print(var1)


func()
print(var1)

运行结果:

image-20220320125155667

示例3:

1
2
3
4
5
6
7
8
9
10
11
12
var1 = 123

def func():
# global var2 = 456 # 该行语法错误
global var2
var2 = 456
print(var2)


func()
print(var1)
print(var2)

运行结果:

image-20220320125545198

7.4 函数的迭代器和生成器

7.4.1 迭代器

示例:

1
2
3
4
5
6
list1 = (1, 2, 3)
it = iter(list1)
print(next(it))
print(next(it))
print(next(it))
print(next(it)) #这一行代码错误,已经迭代结束了

运行结果:

image-20220320160330240

7.4.2 生成器

示例:

1
2
3
4
5
6
7
8
9
10
11
def foo():
print("starting...")
while True:
res = yield 4
print("res:", res)

g = foo()
print("*" * 20)
print(next(g))
print("*" * 20)
print(next(g))

运行结果:

image-20220320164159222

分析:
1.程序开始执行以后,因为foo函数中有yield关键字,所以foo函数并不会真的执行,而是先得到一个生成器g(相当于一个对象)
2.直到调用next方法,foo函数正式开始执行,先执行foo函数中的print方法,然后进入while循环
3.程序遇到yield关键字,然后把yield想想成return,return了一个4之后,程序停止,并没有执行赋值给res操作,此时next(g)语句执行完成,所以输出的前两行(第一个是while上面的print的结果,第二个是return出的结果)是执行print(next(g))的结果,
4.程序执行print("*"20),输出20个
5.又开始执行下面的print(next(g)),这个时候和上面那个差不多,不过不同的是,这个时候是从刚才那个next程序停止的地方开始执行的,也就是要执行res的赋值操作,这时候要注意,这个时候赋值操作的右边是没有值的(因为刚才那个是return出去了,并没有给赋值操作的左边传参数),所以这个时候res赋值是None,所以接着下面的输出就是res:None
6.程序会继续在while里执行,又一次碰到yield,这个时候同样return 出4,然后程序停止,print函数输出的4就是这次return出的4。
到这里你可能就明白yield和return的关系和区别了,带yield的函数是一个生成器,而不是一个函数了,这个生成器有一个函数就是next函数,next就相当于“下一步”生成哪个数,这一次的next开始的地方是接着上一次的next停止的地方执行的,所以调用next的时候,生成器并不会从foo函数的开始执行,只是接着上一步停止的地方开始,然后遇到yield后,return出要生成的数,此步就结束。

示例2:

1
2
3
4
5
6
7
8
9
def frange(star, stop, step):
x = star
while x < stop:
yield x
x += step


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

运行结果:

image-20220320191101081

7.5 lambda表达式

示例1:将lambda函数赋值给一个变量,通过这个变量间接调用该lambda函数。

通过传统的方法定义函数:

1
2
3
def sum(x,y):
return x+y
print(sum(5,9))

通过lambda的方法定义函数:

1
2
add = lambda x, y: x + y
print(add(5, 9))

示例2:将lambda函数作为参数传递给其他函数。部分Python内置函数接收函数作为参数。

通过传统方式:

1
2
3
4
5
def odd(x):
return x%2
temp = range(10)
show = filter(odd,temp)
print(list(show)) #[1, 3, 5, 7, 9]

通过lambda函数实现:

1
print(list(filter(lambda x: x%2,range(10))))    #[1, 3, 5, 7, 9]

此时lambda函数用于指定过滤列表元素的条件。

示例3:将lambda函数作为其他函数的返回值,返回给调用者。

函数的返回值也可以是函数。例如return lambda x, y: x+y返回一个加法函数。这时,lambda函数实际上是定义在某个函数内部的函数,称之为嵌套函数,或者内部函数。对应的,将包含嵌套函数的函数称之为外部函数。内部函数能够访问外部函数的局部变量,这个特性是闭包(Closure)编程的基础。

示例4:将lambda函数赋值给其他函数,从而将其他函数用该lambda函数替换。

例如:为了把标准库time中的函数sleep的功能屏蔽(Mock),我们可以在程序初始化时调用:time.sleep=lambda x:None。这样,在后续代码中调用time库的sleep函数将不会执行原有的功能。例如,执行time.sleep(3)时,程序不会休眠3秒钟,而是什么都不做

示例5:将if...else语句缩减为单一的条件表达式,

语法expression1 if A else expression2

如果ATrue,条件表达式的结果为expression1,否则为expression2

1
2
3
4
5
6
7
def s(x):
if x==1:
return "yes"
else:
return "no"
print(s(0))
print(s(1))

使用lambda函数:

1
2
3
s = lambda x:"yes" if x==1 else "no"
print(s(0))
print(s(1))

7.6 Python内建函数

7.6.1filter函数

filter函数:

1
2
a = (1, 2, 3, 4, 5, 6, 7)
print(list(filter(lambda x: x > 2, a))) # 需要将filter强制转换成列表类型,否则系统不会执行

运行结果:

image-20220320213250479

7.6.2 map函数

map函数:

1
2
a = [1, 2, 3]
print(list(map(lambda x: x + 1, a)))

运行结果:

image-20220320213331709

7.6.3 reduce函数

reduce函数:

reduce函数不能直接使用,在终端中通过from functools import reduce命令导入相应的函数包,然后才能使用reduce函数。

1
2
3
4
from functools import reduce

reduce(lambda x, y: x + y, [2, 3, 4], 1) # 将数值1通过lambda函数分别对列表中的元素依次进行运算
# ((1+2)+3)+4

运行结果:

image-20220320214536358

7.6.4 zip函数

zip函数:zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。

示例1:

1
2
3
4
# zip((1, 2, 3), (4, 5, 6))
print((1, 2, 3), (4, 5, 6))
for i in zip((1, 2, 3), (4, 5, 6)):
print(i)

运行结果:

image-20220321100237335

示例2:

1
2
3
dicta = {'a': 'aaa', 'b': 'bbb'}
dictb = zip(dicta.values(), dicta.keys())
print(dict(dictb))

运行结果:

image-20220321100838416

7.7 闭包

闭包概念:在一个内部函数中,对外部作用域的变量进行引用,(并且一般外部函数的返回值为内部函数),那么内部函数就被认为是闭包。

示例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def sum(a):  # 内部函数
def add(b): # 内部函数
print(a)
print(b)
return a + b # 外部函数的变量 a 被内部函数引用称为闭包

return add


# add 函数名称或函数的引用
# add() 函数的调用
# num1 = func()

num2 = sum(2) # 该行代码返回的是一个函数
print(num2)
print(num2(5))
# print(type(num1))
# print(type(num2))

运行结果:

image-20220321110446033

示例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def counter(a):
cnt = [a] # 列表

def add_one():
cnt[0] += 1
return cnt[0]

return add_one


num5 = counter(5)
print(num5())
print(num5())
print(num5())
print(num5())

num9 = counter(9)
print(num9())
print(num9())
print(num9())

运行结果:

image-20220321113526662

示例3:

1
2
3
4
5
6
7
8
9
10
11
# 计算公式 a * x + b = y
def a_line(a, b):
def arg_y(x):
return a * x + b
return arg_y


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

如果通过lambda来实现闭包,代码如下:

1
2
3
4
5
6
7
8
9
# 计算公式 a * x + b = y
def a_line(a, b):
return lambda x: a * x + b


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

运行结果:

image-20220321123815152

7.8 装饰器

装饰器的概念:装饰器(Decorators)是 Python 的一个重要部分。简单地说:他们是修改其他函数的功能的函数。他们有助于让我们的代码更简短,也更Pythonic(Python范儿)。

闭包和装饰器的不同点:闭包传入的是变量,内部引用的是变量;装饰器传入的是函数,内部引用的也是函数。

示例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import time

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


@timer # 装饰函数
def i_can_sleep(): # 被装饰函数
time.sleep(3) # 将暂停运行 3 秒这个函数传递给 timer ,对应timer中的函数为 func

i_can_sleep() # 该行命令等同于 timer(i_can_sleep()) 或 a = timer(i_can_sleep())

运行过程:首先运行到i_can_sleep()时,会自动寻找i_can_sleep()这个函数,发现这个函数被装饰,会跳转到timer这个装饰函数,将被装饰函数i_can_sleep()作为func传入,并运行wrapper()函数。

运行结果:

image-20220321130135760

示例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def new_tips(argv):
def tips(func):
def nei(a, b):
print('start %s %s' % (argv, func.__name__)) # 通过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)


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

运行结果:

image-20220321131658615

可以通过@装饰器来进行重复进行调用。

7.9 上下文管理器

通过with来进行上下文管理:

传统方式:

1
2
3
4
5
6
fd = open('name.txt')
try:
for line in fd:
print(line)
finally:
fd.close()

通过with来进行上下文管理:

1
2
3
with open('name.txt') as f:
for line in f:
print(line) # 当运行出现异常的时候,with会自动调用finally来关闭文件

8 模块

模块是在代码量变得相当大之后,为了将需要重复使用的有组织的代码段放在一起,这部分代码可以附加到现有程序中,附加的过程叫做导入(import)。

导入模块的一般写法:

  • import 模块名称
  • from 模块名称 import 方法名

示例:

1
2
3
4
5
6
7
8
import os  # 导入 os 模块

import time # 导入 time 模块

import matplotlib as m # 可以将 matplotlib 进行重命名为 m

from time import sleep # 导入 time 模块中的 sleep 函数
sleep() # 使用sleep函数,不推荐使用,可能出现自己定义的函数名称和sleep重名

新建一个mymod.py文件,并写入如下代码:

1
2
def print_me():
print('me')

新建一个mod_test.py文件,并写入如下代码:

1
2
import mymod
mymod.print_me()

运行结果:

image-20220321154631823

9 面向对象编程

9.1 类与实例

示例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Player():  # 定义一个类  类的名称第一个字母大写
def __init__(self, name, hp, occu):
self.__name = name # self指的是实例化本身,即user1和user2,通过增加下划线,对类进行封装,该类的属性可以不被访问到
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', 100, 'master')
print(1)
user1.print_role()
user2.print_role()

运行结果:

image-20220321163604416

示例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Player():  # 定义一个类  类的名称第一个字母大写
def __init__(self, name, hp, occu): # 类中第一个参数一定是self
self.__name = name # self指的是user1和user2,通过增加下划线,对类进行封装,该类的属性可以不被访问到
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
self.__name = newname

class New():
# 下面通过单引号'xxx'或者"""xxx"""来对这个类进行说明,并不会报错
'定义怪物类'
pass #如果不确定这个类中写什么,可以暂时写一个pass,编译器不会报错

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

user1.updateName('wilson')
user1.print_role()
user1.__name = ('aaa') #无法更改类中属性的值,因为已经被封装,只有通过类本身的函数(方法)来更改
user1.print_role()

9.2 类的继承

示例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class Monster():
def __init__(self, hp=90):
self.hp = hp # 变量被称为属性

def run(self):
print('移动到某个位置') # 函数被称为方法

def whoami(self):
print('我是怪物父类')


class Animals(Monster): # 在括号中写继承父类的名字 #Animals作为Monster的子类,使用Animals的时候就能够调用Monster的hp和run
"""普通的怪物"""
def __init__(self, hp=10):
super().__init__(hp) # 子类hp属性和父类hp属性属于重复定义,父类中初始化了某些属性,子类不用重复初始化该子类


class Boss(Monster):
"""Boss类怪物"""
def __init__(self, hp=1000):
self.hp = hp

def whoami(self):
print('我是怪物我怕谁haha')


a1 = Monster(100) # 会直接赋值替换原来__init__初始化的值
print('a1:')
print(a1.hp)
print(a1.run())
a2 = Animals(1) # a2
print('a2:')
print(a2.hp)
print(a2.run()) # 此时可以看出a2可以继承父类方法
print(a2.whoami()) # 此时可以看出a2可以继承父类方法

print('a3:')
a3 = Boss(800)
print(a3.hp)
a3.whoami() # 子类的继承中如果有重名的方法,会替换父类中的方法

print('a1的类型 %s ' % type(a1))
print('a2的类型 %s ' % type(a2))
print('a3的类型 %s ' % type(a3))

print(isinstance(a2, Monster)) # isinstance可以用来判断a2是否为Monster的子类

运行结果:

image-20220322093031444

示例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Testwith():
def __enter__(self): # 类初始化的时候会调用这一行
print('run')

def __exit__(self, exc_type, exc_val, exc_tb): # 类结束的时候会调用这一行
if exc_tb is None: # 没有异常,则exc_tb值为空
print('正常结束')
else:
print('Has error %s ' % exc_tb)


with Testwith():
print('Test is running')
raise NameError('testNameError') # 用raise抛出异常

运行结果:

image-20220322094948501

10 多线程编程

示例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import threading
import time
from threading import current_thread

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

print('运行开始')
for i in range(1, 6):
t1 = threading.Thread(target=myThread, args=(i, i + 1))
t1.start() # 加上start方法之后多线程才能运行起来
print('运行结束')
print(current_thread().name, 'end')

运行分析:主线程运行结束才会运行

运行结果1:

image-20220322110411275

运行结果2:

image-20220322110202697

如果运行的多线程中某些线程先结束,希望该线程等待其他线程全部结束后再继续运行,则通过join的方法来实现。

示例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import threading
from threading import current_thread

class Mythread(threading.Thread): # 使用Thread方法的名称,不是引用
def run(self):
print(current_thread().name, 'start')
print('run')
print(current_thread().name, 'stop')

t1 = Mythread()
t1.start()
t1.join() #为了使Thread先结束,主线程后结束,采用join的方法

print(current_thread().name, 'end')

运行结果:

image-20220322111716144

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

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
from threading import Thread, current_thread
import time
import random
from queue import Queue

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


class ProducerThread(Thread):
def run(self):
name = current_thread().name
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().name
global queue
while True:
num = queue.get() # 根据加入的数据的顺序进行读取
queue.task_done() # 没有用join等待,因为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()
p2 = ProducerThread(name='p2')
p2.start()
p3 = ProducerThread(name='p3')
p3.start()

c1 = ConsumerThread(name='c1')
c1.start()
c2 = ConsumerThread(name='c2')
c2.start()
c3 = ConsumerThread(name='c3')
c3.start()
c4 = ConsumerThread(name='c4')
c4.start()

运行分析:如果生产者多余消费者,当队列中存放的数据满了之后,则生产者将不再生产数据,只要当消耗着消耗部分后,队列中有多余位置,才会产生数据。

11 标准库

Python官方文档对应地址:https://docs.python.org/3/library/index.html

Python常用的标准库:

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

11.1 正则表达式库 - re

11.1.1 正则表达式元字符

示例1:匹配相同字符

1
2
3
4
5
import re

p = re.compile('a')
print(p.match('a'))
print(p.match('b'))

运行结果:

image-20220322215847856

示例2:.可以匹配所有任意的单个字符

1
2
3
4
5
import re

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

运行结果:

image-20220322212152620

示例3:^以什么作为开头,从开头进行搜索

示例4:$以什么作为结尾,从后面往前面进行匹配,比如以d = re.compile('jpg$')表示以jpg作为结尾,来进行检索。

示例5:*表示匹配前面的字符出现0次到多次

1
2
3
4
5
import re

b = re.compile('ca*t')
print(b.match('cat'))
print(b.match('caat'))

运行结果:

image-20220322220015635

示例6:?代表字符出现0次或1次

1
2
3
4
5
6
import re

b = re.compile('c?t')
print(b.match('ct'))
print(b.match('cat'))
print(b.match('caaat'))

运行结果:

image-20220322221537819

示例7:{内容}表示前面字符出现指定次数

1
2
3
4
5
6
7
8
import re

b = re.compile('ca{4,6}t')
print(b.match('ct'))
print(b.match('cat'))
print(b.match('caaaat'))
print(b.match('caaaaat'))
print(b.match('caaaaaaat'))

运行结果:

image-20220323100133927

示例8:[内容]表示匹配方括号中的任意一个字符

1
2
3
4
5
6
7
8
import re

b = re.compile('ca[abcd]t')
print(b.match('ct'))
print(b.match('cat'))
print(b.match('caabcdt'))
print(b.match('cact'))
print(b.match('cabt'))

运行结果:

image-20220323100227459

示例9:\d用来匹配多个数字字符[0-9](多个[0-9]也可以用[0-9]+表示)

示例10:\D用来匹配非数字字符

示例11:\s表示匹配的是字符串

示例12:.*?表示不匹配贪婪模式,例如下面的内容

1
2
<img   /img>
<img /img>

如果使用.*?不匹配贪婪模式,则只会匹配第一行,不会匹配所有的行。

11.1.2 正则表达式分组功能

示例1:

1
2
3
4
5
6
7
8
9
10
11
12
import re

b = re.compile('ca...t')
print(b.match('cat'))
print(b.match('caabct'))
print(b.match('cact'))

print('**********')
c = re.compile('ca.{2}t')
print(c.match('cat'))
print(c.match('cact'))
print(c.match('cacbt'))

运行结果:

image-20220323105849066

11.1.3 正则表达式中match和search的区别

示例1:

1
2
3
4
5
6
7
8
9
10
11
import re

b = re.compile(r'(\d+)-(\d+)-(\d+)') # 在前面加上r代表后面的内容不进行转义
print(b.match('2022-05-30'))
print(b.match('2022-05-30').group(1))
print(b.match('2022-05-30').group(2))
print(b.match('2022-05-30').groups())
(year, month, day) = b.match('2022-05-30').groups()
print('year = %s' % year)
print('month = %s' % month)
print('day = %s' % day)

运行结果:

image-20220323113655477

示例2:

1
2
3
4
5
6
7
8
9
10
11
12
import re

b = re.compile(r'(\d+)-(\d+)-(\d+)') # 在前面加上r代表后面的内容不进行转义
print(b.search('aa2022-05-30bbb'))
print(b.search('aa2022-05-30bbb').group()) # search用来搜索指定字符串
print(b.search('aa2022-05-30bbb').group(1))
print(b.search('aa2022-05-30bbb').group(2))
print(b.search('aa2022-05-30bbb').groups())
(year, month, day) = b.search('aa2022-05-30bbb').groups()
print('year = %s' % year)
print('month = %s' % month)
print('day = %s' % day)

运行结果:

image-20220323114845268

11.1.4 正则表达式替换函数sub()

示例1:

1
2
3
4
5
6
7
8
9
import re

phone = '123-456-798 # 这是电话号码'
# 用r表示后面的字符不进行转义,#表示匹配#号,#.*表示匹配#后面所有内容,*是多个的意思,$表示一直到结尾
# sub('原来需要替换的内容','需要替换的新内容',字符串名字)
p2 = re.sub(r'#.*$', '', phone)
print(p2)
p3 = re.sub(r'\D', '', p2) # \D 表示选择非数字的部分
print(p3)

运行结果:

image-20220323121112440

11.2 日期与时间函数库

time模块多数是用来查看日期和时间

示例1:

1
2
3
4
5
6
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'))

运行结果:

image-20220323150706546

datetime多用于时间的修改

示例2:

1
2
3
4
5
6
7
8
9
10
import datetime
print(datetime.datetime.now())
# 如果想获取十分钟以后的时间,可以通过类似加减法的方式来进行计算
newtime = datetime.timedelta(minutes=10) # timedelta为偏移时间
print(datetime.datetime.now() + newtime)

one_day = datetime.datetime(2000, 5, 27)
print(one_day)
new_date = datetime.timedelta(days=10)
print(one_day + new_date)

运行结果:

image-20220323151549821

11.3 数学相关库

数学相关的库为:Numeric and Mathmatical Modules

示例:

1
2
3
4
import random

print(random.randint(1, 5)) # 产生1到5的整数(包括1和5)
print(random.choice(['aa', 'bb', 'cc']))

运行结果:

image-20220323152430186

11.4 对文件和文件夹操作库

在Linux的终端中,常用操作命令:

1
2
3
4
5
6
7
8
pwd     #返回当前的地址
cd .. # 访问上一级目录
cd /tmp #访问根目录下的tmp文件夹,这个进入方式为绝对路径
cd ./tmp #访问当前目录的下一级目录,即进入tmp文件夹,这个进入方式为相对路径
mkdir /tmp/a #建立文件夹
mkdir -p /tmp/a #如果不存在相应的文件,通过
rmdir g #如果当前终端在g文件夹的上一级目录中,可以通过此命令来删除g文件夹
rm -rf /tmp/a #如果某个目录中存在子目录,可以通过此命令将a文件夹和a文件夹下的所有文件进行删除

11.4.1 文件夹操作库-os.path

通过文件夹操作库对文件和文件夹进行操作

示例:

1
2
3
4
5
6
7
8
9
10
import os
from os import path

print(os.path.abspath('.')) # 通过 . 来获取绝对路径
print(os.path.abspath('..')) # 通过 .. 来获取上一级的绝对路径
print(os.path.exists('/users')) # 判断根目录下的users文件夹是否存在,如果存在返回True,不存在返回False
print(os.path.isfile('/Code/Code_py')) # 判断Code_py是否为文件
print(os.path.isdir('/Code/Code_py')) # 判断Code_py是否为文件

print(os.path.join('/tmp/a/', 'b/c')) # 将两个路径进行拼接

运行结果:

image-20220323162927586

11.4.2 文件夹操作库-pathlib.Path

示例:

1
2
3
4
5
6
7
8
9
from pathlib import Path
p = Path('/Code/Code_py')
print(p.resolve()) # 通过此方法可以得到相对路径的绝对路径
print(p.is_dir())

q = Path('/tmp/a')
# parents设为True,当q对应的目录不存在,则创建目录
# parents设为False,当q对应的目录不存在,则不创建目录
Path.mkdir(q,parents=True)

运行结果:

image-20220323165930706

可以看到该文件夹已经创建

image-20220323165426767

12 机器学习

12.1 numpy库

numpy库:用于高性能科学计算和数据分析,是常用的高级数据分析库的基础包,用numpy库的运行效率比python自身的运行效率更高。

需要在终端中通过pip3 install numpy命令来安装numpy库,运行效果:

image-20220325102818737

示例1:

1
2
3
4
5
6
7
8
9
10
11
12
import numpy as np

arr1 = np.array([2, 3, 4])
print(arr1)
print(arr1.dtype)

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

#可以有多种数据类型:int8 int16 int32 int64等 numpy可以根据输入的数据类型自动进行转换
print(arr1 + arr2)

运行结果:

image-20220325104808949

示例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import numpy as np

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

print(arr2 * 10)
data = ((1, 2, 3), (4, 5, 6))
print(data)
arr3 = np.array((data)) # 将data转为二维矩阵
print(arr3)
print(arr3.dtype)

print('np:zeros, ones和empty:')
print(np.zeros(10))
print(np.zeros((3, 5)))
print(np.ones((4,6)))
print(np.empty((2,3,2)))

运行结果:

image-20220325115100759

示例3:

1
2
3
4
5
6
7
8
9
10
11
import numpy as np

arr4 = np.arange(10)
print(arr4[5:8])
arr4[5:8] = 10
print(arr4)
arr_slice = arr4[5:8].copy() # 对原有数据进行切片(部分赋值)给arr_slice
print(arr_slice)
arr_slice[:] = 15
print(arr_slice)
print(arr4)

运行结果:

image-20220325120711789

12.2 pandas库

pandas是用来数据预处理、数据清洗非常重要的库。

需要在终端中通过pip3 install pandas命令来安装pandas库,运行效果:

image-20220325121921191

Series可以看作一维的字典,dataframe可以看作二维的字典。

12.2.1 Series数据结构

示例1:

1
2
3
4
5
6
7
8
9
10
from pandas import Series, DataFrame
import pandas as pd

# pandas会将你的数据自动进行数据排列或者按照自定义的方式进行排列显示,避免数据没有对齐,处理数据出现失误
# pandas可以很灵活处理缺失的数据,也可以填充想要的值

obj = Series([4, 5, 6, -7])
print(obj)
print(obj.index)
print(obj.values)

运行结果:

image-20220325202537583

示例2:

1
2
3
4
5
6
7
8
9
from pandas import Series, DataFrame
import pandas as pd

obj2 = Series([4, 7, -5, 3], index=['d', 'b', 'c', 'a'])
print(obj2)

obj2['c'] = 6
print(obj2)
print('a' in obj2)

运行结果:

image-20220325202849669

示例3:

1
2
3
4
5
6
7
8
9
10
11
12
13
from pandas import Series, DataFrame
import pandas as pd

sdata = {
'beijing': 35000,
'shanghai': 71000,
'guangzhou': 16000,
'shenzhen': 5000}
obj3 = Series(sdata)
print(obj3)

obj3.index = ['bj', 'gz', 'sh', 'sz']
print(obj3)

运行结果:

image-20220325203508667

12.2.2 Dataframe数据结构

示例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pandas import Series, DataFrame
import pandas as pd

data = {
'city': [
'shanghai', 'shanghai', 'shanghai', 'beijing', 'beijing'], 'year': [
2016, 2017, 2018, 2017, 2018], 'pop': [
1.5, 1.7, 3.6, 2.4, 2.9]}
frame = DataFrame(data)
print(frame)
frame2 = DataFrame(data, columns=['year', 'city', 'pop'])
print(frame2)
print(frame2['city'])
print('***************')
print('year:')
print(frame2.year)

运行结果:

image-20220325205253855

示例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pandas import Series, DataFrame
import pandas as pd

data = {
'city': [
'shanghai', 'shanghai', 'shanghai', 'beijing', 'beijing'], 'year': [
2016, 2017, 2018, 2017, 2018], 'pop': [
1.5, 1.7, 3.6, 2.4, 2.9]}
frame = DataFrame(data)
frame2 = DataFrame(data, columns=['year', 'city', 'pop'])

frame2['new'] = 100
print(frame2) # 增加一个新的列
frame2['cap'] = frame2.city == 'beijing'
print(frame2)

运行结果:

image-20220325205810945

示例3:

1
2
3
4
5
6
7
8
from pandas import Series, DataFrame
import pandas as pd

pop = {'beijing': {2008: 1.5, 2009: 2.0},
'shanghai': {2008: 2.0, 2009: 3.6}}
frame3 = DataFrame(pop)
print(frame3)
print(frame3.T)

运行结果:

image-20220325210309868

示例4:

1
2
3
4
5
6
7
8
9
from pandas import Series, DataFrame
import pandas as pd

obj4 = Series([4.5, 7.2, -5.3, 3.6], index=['b', 'c', 'd', 'a'])
obj5 = obj4.reindex(['a', 'b', 'c', 'd', 'e'], fill_value=0)
print(obj5)

obj6 = Series(['blue', 'purple', 'yellow'], index=[0, 2, 4])
print(obj6.reindex(range(6), method='ffill')) #如果用后面的值进行填充,用 bfill

运行结果:

image-20220325211625055

示例5:

1
2
3
4
5
6
7
from pandas import Series, DataFrame
import pandas as pd

from numpy import nan as NA
data = Series([1, NA, 2])
print(data)
print(data.dropna()) # 删除NA对应的索引

运行结果:

image-20220325213552479

示例6:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pandas import Series, DataFrame
import pandas as pd
from numpy import nan as NA

data2 = DataFrame([[1., 6.5, 3], [1., NA, NA], [NA, NA, NA]])
print('下面展示的是删除一整行全为NAN的这一行')
print(data2.dropna(how='all'))

data2[4] = NA
print('下面展示的是删除一整行全为NAN的这一列:')
print(data2)
print(data2.dropna(axis=1, how='all'))
data2.fillna(0)
print(('******'))
print(data2)
data2.fillna(0, inplace=True)
print(data2.fillna(0, inplace=True))
print(data2)

运行结果:

image-20220325213724732

12.2.3 层次化索引

pandas支持多层次索引

示例1:

1
2
3
4
5
6
7
8
9
10
from pandas import Series, DataFrame
import numpy as np

data3 = Series(np.random.random(10), index=[
['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'd', 'd'], [1, 2, 3, 1, 2, 3, 1, 2, 2, 3]])
print(data3)
print('输出单个索引:')
print(data3['b'])
print('输出多个索引:')
print(data3['b':'d'])

运行结果:

image-20220325224129406

示例2:

1
2
3
4
5
6
7
8
9
from pandas import Series, DataFrame
import numpy as np

data3 = Series(np.random.random(10), index=[
['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'd', 'd'], [1, 2, 3, 1, 2, 3, 1, 2, 2, 3]])
print('将Series一维数据转换成DataFrame二维数据:')
print(data3.unstack())
print('DataFrame二维数据转换成将Series一维数据:')
print(data3.unstack().stack())

运行结果:

image-20220325224458466

12.3 matplotlib库

matplotlib库主要用于绘图。

需要在终端中通过pip3 install matplotlib命令来安装matplotlib库。

示例:

1
2
3
4
import matplotlib .pyplot as plt
# 绘制菜单的曲线
plt.plot([1,3,5],[4,8,10])
plt.show()

运行结果:

image-20220325225815865

示例2:

1
2
3
4
5
6
7
import matplotlib .pyplot as plt
import numpy as np

x = np.linspace(-np.pi, np.pi, 100) # x轴的定义域为-3.14 到3.14,中间间隔100个元素
plt.plot(x, np.sin(x))
# 显示所画的图
plt.show()

运行结果:

image-20220325230248280

示例3:

1
2
3
4
5
6
7
8
9
import matplotlib .pyplot as plt
import numpy as np

x = np.linspace(-np.pi, np.pi, 100) # x轴的定义域为-3.14 到3.14,中间间隔100个元素
plt.figure(1, dpi=50) # 创建图表1
for i in range(1, 5):
plt.plot(x, np.sin(x / i))
# 显示所画的图
plt.show()

运行结果:

image-20220325230813588

示例4:

1
2
3
4
5
6
import matplotlib .pyplot as plt

plt.figure(1, dpi=50) # 创建图表1,dpi代表图片精细度,dpi越大文件越大,杂志要dpi300以上
data = [1, 1, 1, 2, 2, 2, 3, 3, 4, 5, 5, 6, 4]
plt.hist(data) # 只要传入数据,直方图就会统计数据出现的次数
plt.show()

运行结果:

image-20220325231558628

示例4:

1
2
3
4
5
6
7
8
import matplotlib .pyplot as plt
import numpy as np

x = np.arange(1,10)
y = x
fig = plt.figure()
plt.scatter(x,y,c = 'r',marker='o') # c = 'r'表示散点的颜色为红色,marker表示指定散点形状为圆形
plt.show()

运行结果:

image-20220325232159772

12.4 seaborn库

需要在终端中通过pip3 install seaborn命令来安装seaborn库。

12.5 tensorflow库

需要在终端中通过pip3 install tensorflow命令来安装tensorflow库。

13 爬虫

常用的网络库包括:

  • urllib库:数据收集和下载的库
  • requests库:数据收集和下载的库
  • BeautifulSoup库:格式处理
  • http协议常用库
  • http协议常用库
  • xml格式处理库

httpbin.org是测试http协议的网站,可以通过它测试http功能。

示例1:

1
2
3
4
5
from urllib import request

url = 'http://www.baidu.com'
response = request.urlopen(url, timeout=1)
print(response.read().decode('utf-8')) # 将读取的网页通过utf-8进行读取,utf-8是汉字编码的一种方式

运行结果:

image-20220326082959576

示例2:

可以通过输入httpbin.org/get?a=123&b=456来告诉服务器a的值为123,b的值为456。

image-20220326084109093

通过上面的get来往服务器传递数据,有传输数据大小的限制。还有另一种向服务器传递数据的限制,向服务器提供密码的时候会用post来进行提交。

示例3:

1
2
3
4
5
6
7
8
9
10
11
12
13
from urllib import parse
from urllib import request

data = bytes(parse.urlencode({'word': 'hello'}), encoding='utf-8') # 对数据进行封装
print(data)

print('***********************')
response = request.urlopen('http://httpbin.org/post', data=data) # 通过urlopen打开网页,同时指定传输的数据
print(response.read().decode('utf-8'))

print('***********************')
response2 = request.urlopen('http://httpbin.org/get', timeout=1) # 强烈建议写timeout,否则会出现卡死的情况
print(response2.read())

运行结果:

image-20220326091811914

示例4:

1
2
3
4
5
6
7
8
9
10
11
from urllib import parse
from urllib import request

import socket
import urllib

try:
response3 = request.urlopen('http://httpbin.org/get', timeout=0.1) # 强烈建议写timeout,否则会出现卡死的情况
except urllib.error.URLError as e:
if isinstance(e.reason, socket.timeout):
print('TIME OUT')

运行结果:

image-20220326093115888

示例5:用headers来伪装头部

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
"Host": "httpbin.org",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:98.0) Gecko/20100101 Firefox/98.0",
"X-Amzn-Trace-Id": "Root=1-623e6011-127adb2c4d8dfd857e37a791"
}
dict = {
'name':'value'
}

data = bytes(parse.urlencode(dict), encoding='utf-8') # 对字典重新编码,即将其变为网页的字节形式进行封装
req = request.Request(url=url,data=data,headers=headers,method='POST')
response = request.urlopen(req)
print(response.read().decode('utf-8'))

运行结果:

image-20220326095411505

需要在终端中通过pip3 install requests命令来安装requests库。

示例6:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 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())

运行结果:

image-20220326100647336

示例7:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import requests
import re

content = requests.get('http://www.cnu.cc/discoveryPage/hot-111').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"> Lynride < / 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))

运行结果:部分运行结果如下

image-20220326104506764

需要在终端中通过pip3 install bs4命令来安装BeautifulSoup库。

示例8:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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, 'lxml') # 选用html解析器
# print(soup)
print(soup.prettify()) # 当格式比较混乱的时候,通过此方法可以对其格式化处理
print('*********title:')
print(soup.title)
print(soup.title.string)
print(soup.title.parent.name)
print('*********head:')
print(soup.head)
print('*********body:')
print(soup.body)
print('*********p:')
print(soup.p) # 找到p标签
print(soup.p['class'])
print('*********a:')
print(soup.a) # 找到第一个a标签
print(soup.a['class'])
print('*********all p:')
print(soup.find_all('p'))
print('*********all a:')
print(soup.find_all('a'))
print('*********link3:')
print(soup.find(id="link3"))

print('*********href:')
for link in soup.find_all('a'):
print(link.get('href'))
print('get_text:')
print(soup.get_text())

运行结果:

image-20220326111938282

image-20220326112022076