*运维架构师-Python 自动化运维开发-024
十二、函数式编程介绍
6、函数调用
1、函数调用
函数的调用:函数名加小括号 func()先找到名字
根据名字调用代码
def myfunc():
url = "www.qfedu.com"
# 调用
myfunc()
2、函数使用的原则:必须先定义,才可以调用定义函数就是在定义“变量”,“变量”必须先定义后,才可以使用。
不定义而直接调用函数,就相当于在使用一个不存在的变量名
# 情景一
def foo():
print('from foo')
func()
foo() # 报错
# 情景二
def func():
print('from func')
def foo():
print('from foo')
func()
foo() # 正常执行
# 情景三
def foo():
print('from foo')
func()
def func():
print('from func')
foo() # 可以正常执行吗?
需求,自定义函数实现监控告警(cpu,disk,mem)
def email发送邮件()
(连接,发送,关闭)
def CPU告警()
cpu > 80
email发送邮件
def disk告警()
disk > 80
email发送邮件
def mem告警()
mem > 60
email发送邮件
# 发送邮件
import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr
msg = MIMEText('邮件内容', 'plain', 'utf-8')
msg['From'] = formataddr(["luoyinsheng",'18611142071@163.com'])
msg['To'] = formataddr(["luoyinsheng",'luoyinsheng@outlook.com'])
msg['Subject'] = "主题"
server = smtplib.SMTP("smtp.163.com", 25)
server.login("18611142071@163.com", "邮箱密码")
server.sendmail('18611142071@163.com', ['luoyinsheng@outlook.com',], msg.as_string())
server.quit()
思考,怎么才能实现告警内容不一样???
思考,怎么才能让告警内容不一样的同时,保证代码的高可用???
自定义函数
需求,实现监控告警
def cpu_email发送邮件()
(连接,发送,关闭)
def disk_email发送邮件()
(连接,发送,关闭)
def mem_email发送邮件()
(连接,发送,关闭)
def CPU告警()
cpu > 80
cpu_email发送邮件
def disk告警()
disk > 80
disk_email发送邮件
def mem告警()
mem > 60
mem_email发送邮件
引入函数参数
def email发送邮件(邮件内容)
(连接,发送,关闭)
while True:
if cpu利用率 > 90:
email发送邮件("CPU告警")
if 硬盘使用空间 > 90%:
email发送邮件("disk告警")
if 内存占用 > 80%:
email发送邮件("mem告警")
3、总结函数的使用,必须遵循的原则是:先定义,后调用
在使用函数时,我们一定要明确地区分定义阶段和调用阶段
在函数体里面的任何代码都只是定义而已,只有在调用此函数时,这个函数内的代码才会执行。
# 定义阶段
def foo():
print('from foo')
func()
def func():
print('from func')
# 调用阶段
foo()
7、函数返回值 return不定义,默认返回 None
返回多个值时,每个值用逗号隔开,也就是元组的形式
1、如何自定义返回值
使用 return 关键字
def foo():
x = 1
return x
ret = foo() # 给你, 这一步相当于下面的一行代码,就是 foo() 执行完毕,
#创建了 1 这个对象,之后把变量名 ret 分配给对象 1
# ret = 1
print(ret)
2、接收函数的返回值
注意:必须先执行函数,此函数的返回值才会被创建并返回
# 可以使用一个变量来接收一个函数的返回值
ret = foo()
print("foo 函数的返回值是:", ret)
# 也可以把函数的返回值直接作为参数来使用,这时函数 `foo` 会先被执行,
# 之后把其返回值放在其原来的位置,以供 `print` 函数作为参数使用
print("foo 函数的返回值是:", foo())在函数执行的过程中,当在函数体内遇到了 return关键字,函数就会立刻停止执行,并返回其返回值, return 之后的代码不会被执行。
def func():
x = 100
return
print('ok') # 不执行
print('qf') # 执行,因为此代码已不是函数体内的代码了,注意缩进。
func()
义一个有返回值的函数,并调用此函数
def echo(arg):
return arg # 用关键字 return 定义函数的返回
# 调用函数,并用一个变量接收其返回值
ret = echo('yangge')
print(ret)
# 执行 print 的结果
'yangge'
# 当一个函数没有显式的调用 return 时,默认会返回 None
def do_nothing():
print('ok')
# 下面的方式,会先执行函数体内的代码,之后把函数自身的返回值
# 放在其函数原来的位置,并且作为参数给 print
print(do_nothing())
ok # 函数体本身执行的结果
None # 函数自身的返回值
# 函数可以返回一个以及多个Python 的任何数据类型的结果
函数数返回值练习:
def email发送邮件(问题)
(连接,发送,关闭)
if 1==1: #发送成功
print('True')
else: # 发送失败
print('False')
while True:
if cpu利用率 > 90:
问题=‘cpu问题内容’
返回结果=email发送邮件(问题)
if 返回结果==false
#记录日志或者再次发送一次邮件
email发送邮件(问题)
if 硬盘使用空间 > 90%:
问题=‘disk问题内容’
返回结果=email发送邮件(问题)
if 返回结果==false
#记录日志或者再次发送一次邮件
email发送邮件(问题)
if 内存占用 > 80%:
问题=‘mem问题内容’
返回结果=email发送邮件(问题)
if 返回结果==false
#记录日志或者再次发送一次邮件
email发送邮件(问题)
8、函数的参数
以下是重点,需要加强练习,理解原理,掌握用法和技巧函数的参数是为函数体内的逻辑代码提供数据的。
函数的参数形式有 形参和实参
分类有:
普通参数
默认参数
动态参数
1. 什么是形参
对于函数来说,形式参数简称形参,是指在定义函数时,定义的一个变量名;
下面的代码中,x、y、z 就是形参
def foo(x, y, z):
print("第一个参数是", x)
print("第二个参数是", y)
print("第三个参数是", z)
2. 什么是实参
对于函数来说,实际参数简称实参。 是指在调用函数时传入的实际的数据,这会被绑定到函数的形参上; 函数调用时,将值绑定到变量名上,函数调用结束,解除绑定,并且实参将不再存在于程序中。
foo(1,2,3)上面的 1、 2 和 3 都是实参
3. 形参分为:位置参数和默认参数
a. 位置参数
def send_mail(to, title, content):
send_info = {"user": to,
"title": title,
"content": content}
return send_info形参的位置参数,在调用函数时必须给其传递实参。 但是,在函数内使用与否 ,没有限制。
b. 默认参数
def default_mail(title, content, to='xiannv@163.com'):
send_info = {"user": to,
"title": title,
"content": content}
return send_info默认参数在函数定义的时候,就已经绑定了实际的值了。 调用函数时,可以给其传值,也可以不传。不传值 就使用定义函数时绑定的值。
传值 就是使用传递的值。
同样,在函数内使用与否 ,没有限制。
4. 实参分为:位置参数和关键字参数
说的实参实质就是在调用函数时,给位置参数的进行赋值,这个行为通常叫做给函数 传参
因此,大家要明白,这里的 位置参数 和 关键字参数 是在函数调用的情况下的概念。
a. 位置参数传递参数
给形参的位置参数传参
info = send_mail("xiannv@163.com",
"一生问候",
"告诉你,一想到你,我这张丑脸上就泛起微笑。")
print(info)
还可以这样传参
def myfunc(x, y, z):
print(x, y, z)
tuple_vec = (1, 0, 1)
dict_vec = {'x': 1, 'y': 0, 'z': 1}
>>> myfunc(*tuple_vec)
1, 0, 1
>>> myfunc(**dict_vec)
1, 0, 1
给默认参数传参
info = default_mail( "一生问候",
"""因为你太美好了,我等你等了这么久,才能跟你在一起,我害怕得不得了,生怕自己搞砸了""",
"xiannv@163.com", )
print(info)当使用实参的位置参数传参时,需要考虑到定义函数时的形参的位置。
千锋教育云计算
b. 关键字参数传递参数
info = send_mail(content="我爱你,不光是因为你的样子,还因为和你在一起时,我的样子",
title="一生问候",
to="jingjing@126.com")
print(info)使用关键字参数传参时,不必考虑形参的位置。但是需要注意,关键字必须和在定义函数时形参一致。
实参角度的参数结论:在调用函数时,给形参的位置参数或形参的默认参数进行赋值时,可以用实参的位置参数进行传参; 此时传递的实参的顺序,必须和形参的位置顺序一一对应
在调用函数时,给形参的位置参数或形参的默认参数进行赋值时, 也可以使用实参的关键字参数进行传参; 此时,关键字参数之间是不区分位置顺序的
在调用函数时,形参的默认参数不传参数给它,此时,默认参数的值就是原来定义的值;假如传了参数,就使用传入的参数的值。
5. 万能参数: *args 和 **kwargs (动态参数)
a. 用 * 表达式接收传进来的任意多个未明确定义的位置参数
def foo(x, y, *args):
print(args)
foo(1, 3, 5, 6)
list1 = [1,2,3,4,5]
foo(*list1)
foo(list1)
def foo(x, y, *args):
print(args)
print(x)
print(y)
# foo(1, 3, 5, 6)
# foo(1,2,3,4,5,6)
# print(foo(1,2,3,4,5))
list1=['a','b','c','d']
t1=('a','b','c','d')
s1='helloworld'
#foo(list1,t1)
foo(1,2,list1,t1) # 不是序列的可以不用加*
foo(1,2,*list1) #只有在传入序列的时候加*
# 输出如下
(['a', 'b', 'c', 'd'], ('a', 'b', 'c', 'd'))
1
2
('a', 'b', 'c', 'd')
1
2在函数体内接收到的参数会放在元组中
b. 用 ** 表达式接收传进来的任意多个未明确定义的关键字参数
def func(x, y, **kwargs):
print(kwargs)
func(1, 3, name='shark', age=18)
func(1,2,3,4,5) #是否会报错
dict1={'k1':'a','k2':'b'}
func(1,2,**dict1)
def func(x,y,*args,**kwargs):
print(kwargs)
print(args)
print(x)
print(y)
#func(1,2,3,4)
func(1,3,name='aaa',age=18)
d2 = {'k1':'aaa','k2':'18'}
l1 = [1,2,3,4]
print(type(d2))
func(1,2,*l1,**d2) # 加*号调用,就会以序列的元素为元素组成一个元祖
func(1,2,l1) # 直接调用序列,会把整个序列作为元祖的一个元素
# 输出如下
{'age': 18, 'name': 'aaa'}
()
1
3
{'k2': '18', 'k1': 'aaa'}
(1, 2, 3, 4)
1
2
{}
([1, 2, 3, 4],)
1
2在函数体内接收到的参数会放在字典中
相结合的方式
def func1(*args,**kwargs):
print(args)
print(kwargs)
func1(1,2,3)
func1(k1=1,k2=2)
func1(1,2,3,k1='a',k2='b')
6、重要的东西,需要总结一下吧
函数参数从形参角度来说,就是在定义函数时定义的变量名,分为三种:位置参数 如: arg1,arg2
所用的参数是有位置的特性的,位置是固定的,传参时的值也是要一一对应的默认参数 如:arg = 5
动态参数 如: *args,**kwargs, 可以同时用
==三种形参在定义函数时的顺序如下:==
In [108]: def position_arg(arg1, arg2, *args, **kwargs):
...: pass
...:
函数参数从实参角度来说,就是在调用函数时给函数传入的实际的值,分为两种位置参数
在传参时,值和定义好的形参有一一对应的关系关键字参数
在传参时,利用key = value 的方式传参,没有对位置的要求
9、匿名函数
lambda 是用一条语句来表式的匿名函数,可以用它来代替简单的小函数。
# 与函数有相同的作用域,但是匿名意味着引用计数为0,使用一次就释放,除非让其有名字
# 先看一个简单的普通函数
In [125]: def f1(arg1,arg2):
...: return arg1 + arg2
...:
# 再看 lambda 表达式
# 语法格式:
# lambda 参数:函数体
# 示例:
In [126]: lambda arg: arg+1
sum1= lambda arg: arg+1
sum1(5)
In [127]: lambda arg1,arg2: arg1 + arg2
Out[127]: >
sum2 = lambda arg1,arg2:arg1 + arg2
sum2(5, 6)
def f1(arg1,arg2):
return arg1+arg2
print(f1(4,5))
sum1=lambda arg1,arg2: arg1+arg2
print(sum1(4,5))
l1=[1,2,3,4]
d1={'k1':'a','k2':'v'}
s1=lambda x,y,*args,**kwargs: print(x,y,args,kwargs)
s1(1,2,*l1,**d1)
# 处理简单逻辑
# 自动return
# 支持动态参数
10、作业
1、源数据
5497 click_sum:3 percent:100.0%
4826 click_sum:1 percent:0.0%
6522 click_sum:201 percent:51.24%
6367 click_sum:712 percent:1.83%
6368 click_sum:1462 percent:4.79%
5346 click_sum:733 percent:6.68%
3812 click_sum:29 percent:0.0%
4841 click_sum:851 percent:0.0%
5873 click_sum:217 percent:28.57%
6316 click_sum:4 percent:0.0%
6900 click_sum:28 percent:7.14%
7416 click_sum:6 percent:0.0%
6989 click_sum:50 percent:0.0%
6990 click_sum:21 percent:0.0%
4944 click_sum:15 percent:100.0%
6485 click_sum:88 percent:0.0%
7039 click_sum:28 percent:92.86%
2432 click_sum:153 percent:5.88%
6018 click_sum:4 percent:0.0%
6024 click_sum:28 percent:100.0%
1930 click_sum:175 percent:6.29%
2444 click_sum:3725 percent:7.54%
2451 click_sum:3505 percent:0.23%
7060 click_sum:111 percent:51.35%
3989 click_sum:715 percent:41.54%
6039 click_sum:42 percent:0.0%
2457 click_sum:13 percent:46.15%
5530 click_sum:64 percent:0.0%
7582 click_sum:124 percent:0.81%
7071 click_sum:8 percent:0.0%
5537 click_sum:5 percent:100.0%
4763 click_sum:1 percent:100.0%
5540 click_sum:186 percent:0.54%
5033 click_sum:2337 percent:73.47%
4522 click_sum:1668 percent:0.54%
4523 click_sum:62 percent:1.61%
7084 click_sum:432 percent:1.85%
6063 click_sum:247 percent:0.0%
5553 click_sum:68 percent:0.0%
6583 click_sum:13 percent:100.0%
6127 click_sum:22 percent:0.0%
6057 click_sum:6 percent:0.0%
6138 click_sum:15 percent:6.67%
4607 click_sum:10 percent:0.0%
6652 click_sum:8 percent:0.0%
4010 click_sum:1 percent:100.0%
3583 click_sum:2239 percent:36.8%
4446"in_offer_id":107466987-"in_affiliate_id":4631-"result_code":1604
1649"in_offer_id":98399105-"in_affiliate_id":5988-"result_code":1607
800"in_offer_id":106901072-"in_affiliate_id":4666-"result_code":1604
594"in_offer_id":106351217-"in_affiliate_id":7373-"result_code":1604
531"in_offer_id":107466987-"in_affiliate_id":3882-"result_code":1606
393"in_offer_id":108314256-"in_affiliate_id":5411-"result_code":1601
356"in_offer_id":108230131-"in_affiliate_id":5033-"result_code":1601
291"in_offer_id":108230207-"in_affiliate_id":5033-"result_code":1604
284"in_offer_id":108923434-"in_affiliate_id":3583-"result_code":1604
210"in_offer_id":108231457-"in_affiliate_id":5033-"result_code":1800
2、目标数据模板
7545 click_sum:149 percent:97.32%
4773 click_sum:277 percent:86.28%
5411 click_sum:466 percent:84.55%
2902 click_sum:147 percent:80.95%
5988 click_sum:2041 percent:80.84%
5033 click_sum:2337 percent:73.47%
5580 click_sum:250 percent:55.2%
7115 click_sum:346 percent:54.34%
4666 click_sum:1526 percent:54.26%
3、要求说明找到 click_sum 的值大于 100 且 percent 的值大于 30% 的数据,并且 按照 percent 的值 进行由大到小进行排序打印出来
4、代码
# click_num的值大于100且percent的值大于30,然后从大到到小排序
import traceback
# 读取文件内容
with open('source.txt', 'r') as f:
# 得到源数据并且成为列表
content_list = f.read().split('\n')
lines = []
# 循环源数据列表
for line in content_list:
# 判断是我们要的数据
if 'click_sum' in line:
# 拿到我们需要比较的两个数据部分
# click_sum:149 和 percent:97.32%
_, click_sum, percent = line.split()
# 分割得到具体数据
sum = click_sum.split(':')[-1]
per = percent.replace('%', '').split(':')[-1]
try:
# 类型转换
sum = int(sum)
per = float(per)
# 判断 click_num的值大于100且percent的值大于30 的数据行
if sum > 100 and per > 30:
# 把符合条件的数据和需要比对的数据放在一个列表中添加到中列表中
# # [[54.26, '4666 click_sum:1526 percent:54.26%']]
lines.append([per, line])
except Exception as e:
# 假如有异常就打印出如下信息
print("获取到的数据不是数字类型的,无法装换比较")
print(traceback.format_exc())
# print(lines)
# 最终的数据
# [[54.26, '4666 click_sum:1526 percent:54.26%'], [37.57, '6212 click_sum:173 percent:37.57%'], [52.04, '6214 click_sum:294 percent:52.04%'], [40.33, '3671 click_sum:362 percent:40.33%'], [86.28, '4773 click_sum:277 percent:86.28%'], [53.87, '7373 click_sum:1214 percent:53.87%'], [51.24, '6522 click_sum:201 percent:51.24%'], [84.55, '5411 click_sum:466 percent:84.55%'], [40.74, '3882 click_sum:1318 percent:40.74%'], [80.95, '2902 click_sum:147 percent:80.95%'], [80.84, '5988 click_sum:2041 percent:80.84%'], [97.32, '7545 click_sum:149 percent:97.32%'], [51.35, '7060 click_sum:111 percent:51.35%'], [41.54, '3989 click_sum:715 percent:41.54%'], [73.47, '5033 click_sum:2337 percent:73.47%'], [34.17, '7113 click_sum:120 percent:34.17%'], [54.34, '7115 click_sum:346 percent:54.34%'], [55.2, '5580 click_sum:250 percent:55.2%'], [36.8, '3583 click_sum:2239 percent:36.8%']]
# 排序
"""lambda item: item[0] 是一个匿名函数利用 [54.26, '4666 click_sum:1526 percent:54.26%'] 的第一元素进行比较# 给 sort 函数传入参数 reverse=True, 进行有大到下排序"""
lines.sort(key=lambda item: item[0], reverse=True)
# print(lines)
# [[97.32, '7545 click_sum:149 percent:97.32%'], [86.28, '4773 click_sum:277 percent:86.28%'], [84.55, '5411 click_sum:466 percent:84.55%'], [80.95, '2902 click_sum:147 percent:80.95%'], [80.84, '5988 click_sum:2041 percent:80.84%'], [73.47, '5033 click_sum:2337 percent:73.47%'], [55.2, '5580 click_sum:250 percent:55.2%'], [54.34, '7115 click_sum:346 percent:54.34%'], [54.26, '4666 click_sum:1526 percent:54.26%'], [53.87, '7373 click_sum:1214 percent:53.87%'], [52.04, '6214 click_sum:294 percent:52.04%'], [51.35, '7060 click_sum:111 percent:51.35%'], [51.24, '6522 click_sum:201 percent:51.24%'], [41.54, '3989 click_sum:715 percent:41.54%'], [40.74, '3882 click_sum:1318 percent:40.74%'], [40.33, '3671 click_sum:362 percent:40.33%'], [37.57, '6212 click_sum:173 percent:37.57%'], [36.8, '3583 click_sum:2239 percent:36.8%'], [34.17, '7113 click_sum:120 percent:34.17%']]
for line in lines:
print(line[-1])