Python开发-018_函数入门
1 初识函数
1.1 函数是什么?
我们可以把函数直接看成一大堆功能代码的集合
# 函数的定义方式
def 函数名():
'''函数的注释
函数内代码
:return: 返回值
'''
pass
# 函数的调用方式
函数名()
例如:
def daydream():
print("kinght超级帅")
print("kinght超级瘦")
print("kinght超有钱")
# 调用函数才会被执行函数里面的代码
daydream()
daydream()
1.2 什么时候使用函数
什么时候会用到函数呢?一般在项目开发中有会有两种应用场景:
1.2.1 有重复代码,使用函数增加代码的重复使用
案例:监控cpu的使用率,并发送邮件
def send_email():
'''
发送邮件的代码
并且,如果发邮件的代码需要修改,也只需要改这里一处,方便维护
'''
pass
def cpu_utilization():
'''
监控cpu使用率的代码
'''
pass
print("欢迎使用计算机监控系统")
cpu_utilization()
if CPU占用率 > 90%:
# 这里会重复使用发邮件的代码,使用函数可以直接封装变成一行代码
send_email()
if 硬盘使用率 > 99%:
send_email()
if 内存使用率 > 98%:
send_email()
...
1.2.2 代码太长增强代码的可读性
案例:
def calculate_same_num_rule():
"""判断是否是豹子"""
pass
def calculate_same_color_rule():
"""判断是否是同花"""
pass
def calculate_straight_rule():
"""判断是否顺子"""
pass
def calculate_double_card_rule(poke_list):
"""判断是否对子"""
pass
def calculate_single_card_rule():
"""判断是否单牌"""
pass
# 1. 生成一副扑克牌
card_color_list = ["红桃", "黑桃", "方片", "梅花"]
card_nums = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] # A
all_card_list = [[color, num] for color in card_color_list for num in card_nums]
# 2.洗牌
random.shuffle(all_card_list)
# 3.给玩家发牌
...
# 4.判断牌是:豹子?同花顺?顺子?对子?单点?
calculate_same_num_rule()
calculate_same_color_rule()
calculate_straight_rule()
...
以前我们变成是按照业务逻辑从上到下逐步完成,称为:面向过程编程;现在学了函数之后,利用函数编程称为:函数式编程
2 函数的参数
2.1 使用python发送邮件
在具体进入函数的参数之前,我们先学一下如何使用python进行邮件的发送
- 获得一个拥有smtp功能的邮箱
- 基本所有的邮箱都有,可以在设置中打开smtp
- 得到smtp服务器的地址
- 腾讯企业邮箱
- smtp.exmail.qq.com(使用SSL,端口号465)
- 腾讯企业邮箱
- 发送邮件的代码
import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr
def send_mali():
# 邮件文本内容编辑
msg = MIMEText("测试",'html','utf-8')
# 发件人
msg['From'] = formataddr(['kinght测试python','kinght@geekxk.com'])
# 邮件标题
msg['Subject'] = '内容发送测试'
# 发送邮件设置
server = smtplib.SMTP_SSL('smtp.exmail.qq.com')
server.login("kinght@geekxk.com","邮箱密码") # 个别邮箱需要使用专门的授权码
server.sendmail("kinght@geekxk.com",'419353653@qq.com',msg.as_string())
server.quit()
send_mali()
2.2 函数参数的应用
写这篇笔记的时候,正值大年三十,我们需要给朋友的邮箱广发新年祝福邮件,很明显,这时候将sendmail
里面的值都被写死了,这时候就需要进行一定的改造
import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr
user_qq_list = ['QQ号码1','QQ号码2','QQ号码3','QQ号码4','QQ号码5']
def send_mali(user_qq):
text = r'''
新年快乐,万事如意
'''
# 邮件文本内容编辑
msg = MIMEText(text,'html','utf-8')
# 发件人
msg['From'] = formataddr(['kinght测试python','kinght@geekxk.com'])
# 邮件标题
msg['Subject'] = '新年快乐'
# 发送邮件设置
server = smtplib.SMTP_SSL('smtp.exmail.qq.com')
server.login("kinght@geekxk.com","邮箱密码")
## user_qq变量值来源于循环中的qq_number
server.sendmail("kinght@geekxk.com",'{}@qq.com'.format(user_qq),msg.as_string())
server.quit()
for qq_number in user_qq_list:
send_mali(qq_number)
循环调用发送邮件的函数,将user_qq_list
列表进行循环取出QQ号码,然后调用函数send_mali
,在send_mali(qq_number)
括号里面的值,会被传送到def send_mali(user_qq)
括号里,相当于qq_number => user_qq
,然后user_qq
可以在send_mali
函数中直接作为变量使用
2.3 形参与实参
在定义函数时,如果在括号中添加变量
,我们称它为函数的形式参数:
Tips(个人注解):
形式参数的含义指的是在函数中占位,在函数编程中能够占位,以便实际参数传递过来后能够有位置进行处理的参数
# 定义有三个参数的函数(a1/a2/a3一般称为形式参数-形参)
def func(a1,a2,a3):
print(a1+a2+a3)
# 执行函数并传入参数(执行函数传值时一般称为实际参数-实参)
## 有几个形参,在调用时就要有几个实参
## 执行函数并传入参数
func(11,22,33)
# 参数传递的两种方式
## 按顺序传参
def demo(a,b,c):
print(a,b,c)
print(1,2,3)
## 按关键字传参
demo(b=1,a=2,c=3)
## 顺序和关键值可以混合,但关键字必须在顺序后面,且形参和实参数量对等
demo(3,c=2,b=4)
2.4 默认参数
形参与实参的数量要对齐,但是我们也遇到过使用函数的时候,同一函数传入两个或者三个参数的情况,而使用的时候效果并没有差异
file_object = open("user.text",encoding='utf-8') # 默认 mode = 'rt'
file_object = open("user.text",mode='rt',encoding='utf-8')
其实在定义的时候就可以提前给形参赋值,就可以达到有实参传入使用实参,没有实参传入就使用提前赋的值(默认参数)
def add(a,b,c,d=10):
print(a+b+c+d)
add(1,2,3) # 1+2+3+10=16
add(1,2,3,4) # 1+2+3+4=10
add(1,2,d=3,c=4) # 1+2+4+3=10
2.5 动态参数
现在需要编写一个加法计算器进行运算,但是我并不知道有多少个数字,在默认参数中那个add的案例就显得有点捉襟见肘,这时候我们可以使用动态参数解决这个问题
Tips:
在下文中会大量见到args、kwargs这个形参,但其实,args和kwargs并不是python语法规定的动态参数固定名字,只是程序员前辈们为了方便代码阅读而形成的编码潜规则
2.5.1 只能按照位置传参
按照位置传参的特点就是*args
,它的实现逻辑是元组args = ()
,将接收到的值,都放入元组中
def add(*args):
print(args) # (1, 2, 3, 4, 5, 6, 7)
number = 0
for i in args:
number += i
print(number)
add(1,2,3,4,5,6,7)
2.5.2 只能按关键值传参
按关键值传参的特点就是**kwargs
,它的实现逻辑是字典kwargs = {}
,将接收到的值,都成键值对放入字典中
def user(**kwargs):
print(kwargs)
user(name = "kinght",age = "18",work = "废物")
# 输出 {'name': 'kinght', 'age': '18', 'work': '废物'}
2.5.3 既能通过关键字传参也能按照位置传参
这其实就是上面两种对融合体,在传参后会分别放在对应的元组和字典中,不过需要注意的事情就是按照位置传参无论是定义还是传参,都必须在按关键值传参之前
def demo(*args,**kwargs):
print(args) # (1, 2, 3, 4, 5)
print(kwargs) # {'username': 'kinght', 'passwd': 'demo'}
# 同样的在调用的时候不允许出现关键字传参在位置传参之前
demo(1,2,3,4,5,username="kinght",passwd="demo")
# 如果只有关键字传参或只有位置传参
demo(1,2,3,4,5) # args = (1, 2, 3, 4, 5) kwargs = {}
demo(a=1,b=2) # args = () kwargs = {'a': 1, 'b': 2}
案例:是否还记得字符串格式化时的format功能
v1 = "我叫{},今年{},性别{}".format("kinght",18,"男")
v2 = "我叫{name},今年{age},性别{gender}".format(name="kinght",age=18,gender="男")
2.5.4 参数的定义和使用顺序
定义顺序和使用顺序是相同的,默认按照
普通参数 -> 动态位置传参 -> 默认参数 -> 动态关键字传参
案例
def demo2(a1, a2, a3, a4=10, *args, a5=20, **kwargs):
print(a1, a2, a3, a4, a5, args, kwargs)
demo2(11, 22, 33, 44, 55, 66, 77, a5=10, a10=123)
# 输出结果 11 22 33 44 10 (55, 66, 77) {'a10': 123}
11, 22, 33, 44 分别赋值给了 a1, a2, a3, a4
55, 66, 77 赋值给了 args 形成 (55, 66, 77)
a5=10 把10赋值给了 a5
a10=123 把a10=123赋值给了 **kwargs 形成 {'a10': 123}
3 函数的返回值
在开发过程中,我们希望函数可以帮助我们实现某个功能,但让函数实现某功能之后有时也需要有一些结果需要反馈给我们,例如:
def city_weather(city):
'''
查询输入城市的天气情况
:param city: 城市
:return: weather -> 天气
'''
data_list = []
url = "http://ws.webxml.com.cn//WebServices/WeatherWebService.asmx/getWeatherbyCityName?theCityName={}".format(city)
res = requests.get(url=url)
root = ET.XML(res.text)
for node in root:
data_list.append(node.text)
return data_list
# 可以直接接受return的返回值,然后进行下一步处理
result = city_weather("成都")
print(result)
3.1 返回值的知识点
3.1.1 返回值可以是任意类型
def func():
return [1,True,(11,22,33)]
result = func()
print(result)
当在函数中如果函数中未写返回值
或 return
或 return None
,执行函数获取的返回值都是None
# 没写返回值
def func():
value = 1 + 1
ret = func()
print(ret) # None
# 返回值只写了return
def func():
value = 1 + 1
return
ret = func()
print(ret) # None
# 返回值写了none
def func():
value = 1 + 1
return None
ret = func()
print(ret) # None
3.1.2 return后面的值如果有逗号,则默认会将返回值转换成元组再返回
def func():
return 1,2,3
value = func()
print(type(value)) # 查看元素类型 <class 'tuple'>
print(value) # (1,2,3)
补充:type(变量名) 等于查看元素类型
3.1.3 函数一旦遇到return就会立即退出函数(终止函数中的所有代码)
def return_demo():
print("1")
return "2"
print("3")
print(return_demo()) # 输出 1 2
3.2 return的用途
3.2.1 完成某个结果并希望的到结果
def add(*args):
a = 0
for i in args:
a += i
return a
print(add(1,2,3,4,5,6))
3.2.2 基于return控制让函数终止执行
def judge():
i = '123'
print(1)
if i.isdigit(): # 判断i是否是十进制数
return
print(2)
judge() # 1
4 案例 -> 账号密码登陆 使用excel做数据库
'''
写函数,读取的用户信息并构造为字典(用户信息存放在`files/user.xlsx`文件中)
# 构造的字典格式如下
user_dict = {
"用户名":"密码"
...
}
用户输入用户名和密码,进行校验。(且密码都是密文,所以,需要将用户输入的密码进行加密,然后再与Excel中的密文密码进行比较)
'''
import hashlib
import os.path
from openpyxl import workbook,load_workbook
from openpyxl.styles import Alignment,PatternFill,Font,Side,Border
def table_style():
'''表格风格'''
side = Side(style='thin', color='000000') # 表格线
border = Border(top=side, bottom=side, left=side, right=side) # 上下左右都运用表格线
align = Alignment(horizontal='center', vertical='center') # 居中
return border,align
def file_path():
'''创建路径'''
abs_path = os.path.abspath(__file__)
dir_path = os.path.dirname(abs_path)
excel_path = os.path.join(dir_path,'file','user.xlsx')
return excel_path
def dir_excel():
'''获取表格句柄'''
excel_path = file_path()
if not os.path.exists(excel_path):
wb = workbook.Workbook()
sheet = wb.worksheets[0]
# 表头列表
meter_header_words = {'A1':'ID','B1':'用户名','C1':'密码'}
for key,text in meter_header_words.items():
# 设置值
cell = sheet[key]
cell.value = text
# 设置居中
cell.alignment = table_style()[1]
# 设置背景颜色
cell.fill = PatternFill("solid",fgColor='4e72b8')
# 设置字体
cell.font = Font(name = "微软雅黑",color="130c0e")
wb.save(excel_path)
else:
wb = load_workbook(excel_path)
return wb
def import_user(username,password):
'''注册用户'''
wb = dir_excel()
sheet = wb.worksheets[0]
c1 = sheet['A']
# 读取空白文档
for cell in c1:
if cell.value == 'ID':
id = 1
else:
id = cell.value + 1
lie_id = id + 1 # 第几列
# password加密
password = hashlib.md5(password.encode('utf-8')).hexdigest()
# 写入表格数据
cell_id = sheet.cell(lie_id,1)
cell_id.value = id
cell_username = sheet.cell(lie_id,2)
cell_username.value = username
cell_passwd = sheet.cell(lie_id,3)
cell_passwd.value = password
wb.save(file_path())
def login(username,password):
wb = dir_excel()
sheet = wb.worksheets[0]
user_dict = {}
for row in sheet.rows:
user_dict[row[1].value] = row[2].value
# 加密输入的密码
password = hashlib.md5(password.encode('utf-8')).hexdigest()
# 然后进行比较
if username in user_dict:
if password == user_dict.get(username):
print("登录成功")
else:
print("密码错误")
else:
print("账户不存在")
# import_user('root','root')
login('root','roota')