函数


函数参数
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
## 函数  是一个容器,里面包含了代码执行语句,还有一系列的变量数据
函数的参数是在定义函数时括号中的内容
形参是一个待赋值的变量
实参是函数实际调用时传递进去的值
形参是被实参所赋值
实参在传递的时候要和形参一一对应
缺省参数:
在函数定义时,指明一个形参的默认值,就可以不给这个具有默认值得参数传递参数了
给一个具有默认参数的形参传递一个实参,那么会覆盖原有的默认值
缺省参数的定义顺序一点是从右向左,从后向前
#缺省参数可以让形参具有默认值
#缺省参数的定义一定是从右向左
#缺省参数后面要么是缺省,要么就没参数了
不定长参数:
元组不定长*arg
def func(*args):
print(args)
func([1,2,3],'abc','中国')
字典不定长:
def func(**kwargs):
print(kwargs) #*args 用来接收不定长参数保存成元组
func(a={'name':'小明','sex':'man'},b=2,c=3)
形参:a,b,c
实参:就是后面的数据
不定长参数可以接收空值
def func(i,j,*args,**kwargs):
#**kwargs 用来接收不定长参数保存成字典,而且在函数调用时,
#一定要注意使用命名传参的方式
print(i,j,args,kwargs)
func(1,2)
传递的时候首先传递单纯变量作为元组不定长,键值对不定长必须在后
命名参数
def func(a,b,c,d,e,f):
pass
func(b=1,a=2,d=3,f=4,e=3,c=5)
#命名传参可以打乱顺序
返回值
- 函数内部的一些操作,不能影响外界的事务
- return 语句 在函数执行完成之后返回一个结果
- return 会终止函数运行
- 函数调用完成之后会返回结果
- 默认的函数如果没有返回值,那么返回None
- 函数返回值可以任意多个
- 只要是合理的数据,**模块**,对象,函数名均可以返回
函数作用域
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
a = 1 #全局就是全局
def func():
a = 2 #局部就是局部
#修改全局a变为2 错误
#在局部空间创建一个新的同名a 正确
print("内:",a)

global 把一个局部变量声明成全局的

a = 1 #全局就是全局
def func():
global a #升级局部变量成为全局的
a = 2 #局部就是局部
#修改全局a变为2 正确
#在局部空间创建一个新的同名a 错误的
print("内:",a)

#局部作用域:函数内空间
#全局作用域:整个脚本空间

- 形参都是局部的
- 不可变数据对象,在函数内外的值,用到了引用计数
- 全局变量可以被局部作用域使用
- 但是局部变量不可以被全局作用域所使用,除非你用global语句升级,声明为全局变量
- 全局可变对象,在函数内部使用的时,其实是一个共享状态
- 是因为列表的指针域 是一个 也会存在引用计数的情况
- 解决办法就是在函数内部使用深浅拷贝
#内外其实现在共同使用同一个列表
#内外互相影响,用的就是同一个列表
#这样的数据可以在函数之间进行通信
可变数据在传递参数时
- 在函数内部直接通过形参修改,也会影响原有数据
- 可变对象在传递参数时,只是一个引用
不可变数据在传递参数时
- 在函数内部直接通过形参修改,不会影响原有数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
+= 或者 = 号赋值都会使一个不可变数据类型在函数的局部作用域下成为一个局部变量

a = 1
def func():
a = a + 1
func()

# 整个作用域下的a都是来自于同一个作用域的
#你不能说 第一个a是局部的、第二个a是全局的
#这样的话,一个a在一个内存空间下可以表示两个值了,这就二义性了
# 现在的a 就是一个局部变量了
# 局部变量a 需要 局部变量a + 1
# 这个代码会报错
# local variable 'a' referenced before assignment
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
mylist = [1,2,3,4,5,6]
def func():
mylist[0] = 'a'
print('内:',mylist)
#内外其实现在共同使用同一个列表
#内外互相影响,用的就是同一个列表
#这样的数据可以在函数之间进行通信
func()
print('外:',mylist)

#==================

mylist = [1,2,3,4,5,6] #全局变量
def func():
new_list = mylist.copy() #浅拷贝之后,互不影响
new_list[0] = 'a' #局部变量
print('内:',new_list)
func()
print('外:',mylist)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
mydict = {
'name':'Small White',
'money':500
} #字典是一个可变的

def func(key,value):
mydict[key] += value
move_dict = {
'中彩': [func,20],
'生病': [func,-20],
#字典的value要给定一个实际的值
}
move = '中彩'
move_dict[move][0]('money',move_dict[move][1])
#move_dict[move][0] 取到函数
#move_dict[move][1] 取到应该修改的值
print(mydict)
匿名函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- lambda 表达式
- 除了def语句,我们还可以通过lambda语句来创建函数
- lambda创建的函数 因为默认不具有名字,他需要我们来指定一个变量名来保存
- 表达式的结果,将作为返回值自动返回
- 轻量级的函数 一般使用lambda来实现
a = lambda x: x*2
a(2)
#lamdba 参数 : 表达式

mylist = [lambda x,y:x**y,lambda x,y:x**(y+1),lambda x,y:x**(y+2)] #跳转表
for var in range(5): #取出来0-4的数据
for func in mylist:
res = func(var,2)
print(res)
print('-------------')
1
2
3
4
5
6
7
8
9
#计算器
oper_func_dict = {
'+':lambda x,y : x + y if x > 0 else x - y,
'-':lambda x,y : x-y,
'*':lambda x,y : x*y,
'/':lambda x,y : x/y,
}
res = oper_func_dict['+'](x=0,y=1)
print(res)
三元表达式
1
2
x + 1 if x > 0 else x - 1
#当条件满足时(x > 0) 执行表达式左边的,反之执行表达式右边的
跳转表:包含函数的字典或者列表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

mylist = [lambda x,y:x**y,lambda x,y:x**(y+1),lambda x,y:x**(y+2)]
#列表中的每一数据都是一个函数
#求出0-4数据的每一个2,3,4次方的结果
for var in range(5): #取出来0-4的数据
for func in mylist:
#func = lambda x:x**2
#func = lambda x:x**3
#func = lambda x:x**4
res = func(var,2)
print(res)
#外层for循环取出每一个值
#传递到内存循环中执行三次,分别求出2,3,4的方结果
print('-------------')
#跳转表:包含函数的字典或者列表
作业:模拟人生
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
move_dict = {
'w': lambda y: y + 1,
's': lambda y: y - 1,
'a': lambda x: x - 1,
'd': lambda x: x + 1,
}
x = 0
y = 0
while True:
move = input('你要怎么移动:')
if 'w' == move or 's' == move:
y = move_dict[move](y.
if 'a' == move or 'd' == move:
x = move_dict[move](x)
print('你当前的位置:%s:%s' % (x,y))
递归
1
2
3
4
5
6
7
- 当函数自身包含了对自身的调用,那么就是递归
- 递归有最大上限次数:1000次左右
- 递归每一次都在开启一个新的函数空间
- 递归会非常占用内存
- 递归一定要确定终止条件
普通循环 for while 一般适用于解决线性循环
递归的优势在与解决非线性的
递归求和作业练习:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
mylist = [1,2,[3],5,[6,[7,8,9]],1,2] #-> 44
#试一下用循环求和,
#如果列表变化,那么代码可以兼容,可以直接复用,不能改变
mysum = 0
def get_sum(iter):#接收一个等待求和的多层序列
#iter 中 无非两种数据类型: list int
global mysum
for var in iter:
if type(var) == int: #当前取出来的数据是int
#if type(var) == type([])
mysum += var
else:
get_sum(var) #遇到的又是一个列表,那么我们继续遍历
#for循环结束的时候,递归结束
get_sum(mylist)
print(mysum)

递归统计每一个出现的字符出现的次数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
mylist = ['asdazxc','adxzc',['12390145fcsdjfhzkjxcmnasd','123987189asjkdsajkb'],'asdqwewqerq',['asd890q8390'],'asdhquiweqysa','asdhjkzhxjkckjasdh']
#把一样的提出来
#统计每一个出现的字符出现的次数
#for循环实现
dict_num = {}
#key:对应的字符
#value:出现的次数
def get_num(seq):
#字典是可变数据类型,所以直接可以在函数作用域内进行修改
for var in seq: #遍历整个列表数据
if type(var) == list:
#如果取出来的还是一个列表,那么就继续递归
get_num(var)
else: #如果碰到的是一个字符串
for i in var: #遍历字符串,记录次数
if i in dict_num:
# 如果获取到的字符,已经存在了字典中,那么他的次数+1
dict_num[i] = dict_num[i] + 1
else:
# 如果获取到的字符没出现过,那么就创建默认值1就行
dict_num[i] = 1
get_num(mylist)
for key in dict_num:
print(key,':',dict_num[key])
回文判断
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
#问题:使用递归 判断一个字符串是否是回文:

mystr = input("请输入一个你觉得是回文的字符串我来帮你判断:")
if mystr == mystr[::-1]:
print('这就是回文')
else:
print('这不是回文')

def p_h(obj):
if len(obj) < 2: #'a'
return True #返回 结束
elif obj[0] != obj[-1]:
#如果判断对应索引位置的值不一样,那么就返回False
return False
# 现在我判断完了0和-1位置,是不是就可以不要他们了
return p_h(obj[1:-1])
print(p_h(mystr))

#奇数一定有1,偶数一定没有
def p_h_2(obj):
#7 - 1 / 2 = 3
#7 / 2 - 1 / 2
#结果少了小数点后的
index = len(obj) // 2 #取出中间索引位置
#取出下一半字符串
b = obj[index:] if not (len(obj) & 1) else obj[index+1:]
#判断是否是奇或 偶数位
#三元表达式 当 if条件成立,那么返回左边的,反之返回右边的
return True if obj[:index] == b[::-1] else False
print(p_h_2(mystr))
1
2
3
4
5
6
7
8
9
10
11
#回文判断
def p_h_2(obj):
#7 - 1 / 2 = 3
#7 / 2 - 1 / 2 #结果少了小数点后的
index = len(obj) // 2 #取出中间索引位置
#取出下一半字符串
b = obj[index:] if not (len(obj) & 1) else obj[index+1:]
#判断是否是奇或 偶数位
#三元表达式 当 if条件成立,那么返回左边的,反之返回右边的
return True if obj[:index] == b[::-1] else False
print(p_h_2(mystr))
1
2
3
4
5
6
7
8
9
10
#递归回文判断
def p_h(obj):
if len(obj) < 2: #'a'
return True #返回 结束
elif obj[0] != obj[-1]:
#如果判断对应索引位置的值不一样,那么就返回False
return False
# 现在我判断完了0和-1位置,是不是就可以不要他们了
return p_h(obj[1:-1])
print(p_h(mystr))
os模块
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
- os模块支持以下平台,他会根据平台来对应处理你调用的函数
- posix:类Unix操作 安卓 Centos ubuntu Debian
- nt:Win
- mac:MacOS
- 428号早上8点多的时候我的mac丢了
- dos:DOS
- dos必须关机 开机的阶段才能看到
- U盘安装dos操作系统
- os.name
输出当前os模块在哪个平台下
- os.getcwd() -> str
- 获取当前的程序工作目录
- 工作目录:是我们程序在运行期间的时候,如果你需要和当前运行环境(操作系统)进行交互,相对路径互相参照,工作目录可以在程序运行期间修改
- 运行目录:维护当前程序是从哪个路径下被执行的
- os.listdir(path=os.getcwd()) -> list
- 返回指定path目录下的所有文件及文件夹的列表
- 当你不传递一个路径的时候,默认的会返回当前的工作目录下的内容
- 该函数返回的结果,不会明确什么是文件,什么是文件夹
- 返回的结果是一个字符串列表,并且每一个路径都是相对路径的
- 该函数也会将隐藏文件展示
- os.remove(file_path) #rm
- 删除file_path所指定的一个文件
- 如果成功返回None,失败了直接报错
- 删除的时候一定要指明文件的后缀
IsADirectoryError: [Errno 21] Is a directory: 'test'
删除了一个文件夹
FileNotFoundError: [Errno 2] No such file or directory: 'tesasdjklajdkt'
删除了一个不存在的文件
- os.rmdir(dir_path) # rm -rf
- 删除dir_path指定的一个文件夹(目录)
- 如果成功返回None,失败了直接报错
- 无法递归删除文件夹,如果文件夹不为空,那么删除不了
- os.makedirs('a/b/c')
- 递归创建目录
- 可以嵌套创建目录
- 成功返回None,失败则报错
- os.mkdir('a')
- 创建目录
- 不能在linux下创建一个和文件名重名的文件夹
- 虽然类型不同,但是名字也不能是相同的
- 成功返回None,失败则报错
- os.chdir()
- 在程序运行期间可以通过该函数来改变工作目录
- os.listdir() 这个函数可以不传递参数执行,返回当前工作目录下的所有文件及文件夹的列表

os模块下还有一个子模块叫os.path

os.path可以处理和路径及文件类型有关的问题

- os.path.isfile(path) -> Bool
- 判断路径是否是一个真正的文件
- os.path.isdir(path) -> Bool
- 判断路径是否是一个真正的目录
- os.path.join('path','sub_path')
- 拼接path和sub_path
- 可以构成绝对路径
- 路径中重复的部分不会被去掉
>>> os.path.join('home','home/CODE')
'home/home/CODE'
- os.path.exists(path)
- 判断路径是否存在
- 如果存在返回True,反之返回False
- os.path.getsize(path)
- 返回路径对应的文件大小
- 返回的文件大小单位为Byte
os语音控制你的电脑
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
'''
pip install PyAudio 是可以控制你的音频设备 录音还有播放
pip install pyttsx3 是可以让你的电脑播放音频
pip install requests 可以访问百度语音接口
然后安装好pywin32软件即可
'''
'''
1.你先向电脑传输音频
2.解析音频 转换成字符串
requests
百度云接口
3.说话后的字符串再分析
4.os.system(处理分析后的字符串)
'''
import pyttsx3 #播放
import pyaudio #录音
import time #获取时间
import json #用来分析json字符串
import requests #访问链接
from urllib.request import urlopen,Request #访问连接
import base64 #b64编码
import os
def talk(data):
eg = pyttsx3.init()
eg.say(data)
eg.runAndWait()

#向电脑说话
def get_audio():
pa = pyaudio.PyAudio() #初始化音频设备
audio_equip = pa.open(
format=pyaudio.paInt16,#存储位深
channels=1,#声道
rate=16000,#采样率
input=True,#输入
frames_per_buffer=1024,#获取的数据大小
)
times = 0
data = []
print('[+] 请说话...')
start = time.time()
while times < 45: #控制到了说话时间为3秒
audio_data = audio_equip.read(1024) #从设备中读取音频
data.append(audio_data) #吧每一次read读取到的音频 追加到我的data列表中
times += 1
end = time.time()
print('[+] 你说话耗时:%.2f' % (end-start))

audio_equip.close() #关闭设备
res = b''.join(data) #把列表中的所有数据拼接成整体
return res


def get_token():
url = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=%s&client_secret=%s'
client_id = 'npFlwGurf1tMvMS8myW6W9AA'
client_secret = 'TZcTamTfVlYWilclkLbatZe18e8xYzIY'
host = url % (client_id,client_secret)
res = urlopen(host).read().decode() #urlopen函数打开链接提交参数,获取Toekn
#但是这里获取到的是一个json的并且是编码过后的数据
token = json.loads(res)['access_token']
return token

#百度音频解析
def bd_analysis():
token = get_token()
audio_data = get_audio()
audio_data_len = len(audio_data)
audio_data = base64.b64encode(audio_data).decode()

#百度云在接收音频的时候,需要传递两个值
#第一个是音频的实际数据,用base64编码
#第二个是音频的长度, 一定是未编码之前的
data = {
'format':'wav',
'rate':16000,
'channel':1,
'cuid': '1804shuaideyipi',
'dev_pid':1536,
'token':token,
'speech':audio_data,
'len':audio_data_len,
}

data = json.dumps(data).encode() #处理成json格式并且编码
host = 'http://vop.baidu.com/server_api' #把所有的东西都给到百度

headers = {
'Content-Type':'application/json', #指明你提交的数据类型
}

req = Request(url=host,headers=headers,data=data)
try:
res = json.loads(urlopen(req).read().decode())['result'][0].replace(',','')
except :
res = '语音质量有问题,请重新喊话!'
talk('语音质量有问题,请重新喊话!')
else:
print('[+] 你说话的内容:',res)
return res


while True:
if 'yes' in bd_analysis():
talk('请告诉我,我要做什么!')
res = bd_analysis()
if '计算器' in res:
os.system('calc')
talk('爷,你的计算器打开了')
elif '取消关机' in res:
os.system('shutdown -a')
talk('已经取消关机了')
elif '关机' in res:
os.system('shutdown -s -t 1000')
talk('OK给你关机!')
else:
pass
文件操作
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
所有的文件都是在磁盘上的!
CPU只能处理在内存中的数据,也就是说,CPU无法直接去阅读磁盘里的文件
CPU <-> MEM <-> DISK
- 文件操作,在程序里都是对内存中的文件进行操作!
第一步:打开文件 fp = open(path, mode='r')
open函数返回的是一个文件的句柄,不是完全的文件展开体,只是一个可以导出整个文件的头指针
第二步:读
fp.read(num)
函数直接阅读整个文件,并返回整个文件为一个字符串
把整个文件读到了内存
如果给read函数传递了num变量
那么他是通过num来读取对应文件中的指定字符个数
read函数获取到的文件内容会保留行末尾的\n\r
fp.readline()
readline函数一次可以读取文件中的一行内容
当遇到了\n\r则停止,代表当前是一行了
当遇到了EOF(文件结束标志)
readline如果去读取超过文件本身行数的次数,那么不会报错,只会返回空
readline不会一次性把整个文件展开在内存
但是需要我们手动的维护行数
readline函数在获取到文件内容的每一行后,也会保留结尾的\r\n
fp.readlines()
返回了字符串列表
列表中每一个元素都是一行的数据
并且保留行末尾的换行符号
第三步:关闭文件
fp.close()
fp.tell() 获取文件指针位置
with open('1.txt') as fp 这里的with as 语句可以自动做资源创建和释放
文件权限:
w:权限可以让我们打开一个文件,进行写入,但是每一次打开都会将之前的文件内容清空
write函数在写入文件内容的时候,不会自动的带换行\r\n
a:append 追加,读写指针在文件末尾
缓冲和缓存
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
缓冲区( 内存(临时) )  针对读写文件 
- 缓冲区让效率慢的和效率快的组件之间可以协同工作,缓和速度之间的矛盾,不频繁的写入磁盘,可以保护设备。因为磁盘的寿命是由写次数决定的。
- 当你关闭文件的时候,缓冲区中的内容会刷新到磁盘上
- 手动刷新缓冲区:fp.flush()

- 磁盘是保存数据的
- 内存是流通数据的
- CPU才是真正计算数据的
- CPU处理内存中的数据,而内存中的数据来自于磁盘

缓存:为了提高数据流通速度
缓存是在CPU里有
缓存是一块超级告诉的数据流通空间(类似内存),但是太贵了,所以电脑上缓存空间一般不大
L1:CPU经常从L1中拿取数据、控制线程和进程
L2:存储数据
L3:管控内存
读写指针修改
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fp.seek(offset,when)
offset:偏移量
字节为单位
when: 从哪里开始移动
0:文件开头
1:当前位置
2:文件末尾
a模式下的文件末尾读写指针如何移动到文件头部呢?
fp.seek(0,0) -> 回到了文件开头
fp.tell() 获取文件指针,返回的也是以一个字节为单位

不同权限下读写指针位置:
- r: 文件开头
- w: 文件开头
- a: 文件末尾
csv文件操作
1
2
3
4
5
6
7
8
- CSV文件是一个用于电子表格存储类型
- csv文件是存储了以逗号分隔的数据

csv文件默认写入的时候 会在每两行之间多一个空行
解决办法:
在打开文件的时候
fp = open('1.csv','w',newline='')
#newline参数用来控制 每一次写入csv文件数据的时候,一行行之间是否需要空行
1
2
3
4
5
6
7
8
9
10
11
1: 处理普通文本对象为csv文本对象
打开文件:
fp = open(path,mode)
加工:
csv_read_fp = csv.reader(fp) 负责读取
csv_write_fp = csv.writer(fp) 负责写入
2: 对csv_read_fp进行for循环迭代,就可以一行行的访问csv表格中的内容
for var1,var2 in csv_read_fp:
print(var1,var2)
3: 对csv_write_fp文件写入内容,写入的是一些逗号分隔开的数据
csv_write_fp.wirterow([seq])
1
2
3
4
5
字典读取csv时:
dict_read_csv = csv.DictReader(fp)
for var in dict_read_csv:
print(var['name'],var['sex'])
csv文件中第一行是key值,下面的数据是value
1
2
3
4
5
6
7
8
9
字典写一个csv文件
dict_write_csv = csv.DictWriter(fp,fileds)
fp:
打开的文件对象,需要加工成csv字典处理文件对象
fileds: 标题行 第一行
fileds 也是一个逗号分隔的数据 比如: fileds = ['name','age','sex']

dict_write_csv.writeheader() #将指定的标题行先写入到csv文件里
dict_write_csv.writerow({'name':'BOB','age':'16','sex':'man'})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import csv
fp = open('test1.csv','w',newline='')
fileds = ['name','age','sex'] #标题行
name = ['Bob','Jack','Lucy']
age = [10,16,18]
sex = ['man','man','woman']
human_list = []
for index in range(3): #0-2
#外层循环用来控制生产三个数据
human_dict = {}
human_dict[fileds[0]] = name[index] #name
human_dict[fileds[1]] = age[index] #name
human_dict[fileds[2]] = sex[index] #name
human_list.append(human_dict)
#BOB = {'name':'BOB','age':'16','sex':'man'}
dict_write_csv = csv.DictWriter(fp,fileds) #加工文件对象,指明标题行
print(help(csv.DictWriter)) #写入标题行
#******************************
dict_write_csv.writeheader() #用来在csv文件中写入标题行
#******************************
for var in human_list: #遍历用户字典,分别写入csv文件中
dict_write_csv.writerow(var)
fp.close()
坚持原创技术分享,您的支持将鼓励我继续创作!