PythonDay4Advance
PythonDay4Advance
函数
引言:比如植物大战僵尸,这个游戏本身也是由代码编写,现在假设有一种豌豆射手,每发射一次
炮弹会执行100行逻辑代码
如果我在程序,每当需要发射炮弹的时候,都要编写100行逻辑代码,就会觉得该程序过于冗余,
代码重复度较高。
解决方案:
如果我将这100行代码放到一个区域中,然后给这个区域起一个名字,今后在需要发射炮弹的代码
逻辑中,通过这个名字就可以调用起这100行代码。这个区域【代码段】在python中称之为函
数,先将函数定义出来,并对该函数起一个名字,将来在合适的地方通过函数名调用该函数,执行
该函数的内部逻辑。
函数的定义
语句定义格式:
# 使用python中的关键字 def
def 函数名(...):
函数代码逻辑
函数使用特点
- 函数不调用不执行
- 定义函数必须在调用之前出现
函数的参数
参数种类
- 形式参数:指的是函数定义时,小括号中定义的参数
- 实际参数:指的是将来调用函数时,实际传入进去的具体的值
def fun1(hhs, zcy): # hhs zcy是形式参数,名字自定义
print(hhs + zcy)
a1 = int(input("请输入第一个数值:"))
b1 = int(input("请输入第二个数值:"))
fun1(a1,b1) # a1 b1 是实际参数,可以是变量,也可以是具体的值本身
参数的传值方式
- 位置传参
def show1(a, b, c):
print(f"a:{a},b:{b},c:{c}") # a:11,b:22,c:33 show1(11, 22, 33)
- 关键字传参 【通过形参的名字传参】
def show1(a, b, c):
print(f"a:{a},b:{b},c:{c}") show1(b=100, c=200, a=300)
- 混合传参
def show1(a, b, c):
print(f"a:{a},b:{b},c:{c}") show1(100, c=200, b=300)
注意: 混合传参的时候,前面没有关键字的实参是会按照形参的位置来的,后面关键字传参可
以顺序不一样。
函数传参的场景【扩展知识】
# 未使用函数
'''
编写登录时的逻辑代码
'''
编写发送邮件的代码 50行
'''
编写注册时的逻辑代码
'''
编写发送邮件的代码 50行
# 使用函数
import smtplib
from email.mime.text import MIMEText
from email.header import Header def send_email(msg_to, send_info):
msg_from = '1165872335@qq.com' # 发送方邮箱
passwd = 'owbciardnivafija' # 填入发送方邮箱的授权码
subject = "33期邮件信息" # 主题 msg = MIMEText(send_info) # 生成邮件内容
msg['Subject'] = subject # 设置邮件主题
msg['From'] = msg_from # 设置发件人 with smtplib.SMTP_SSL("smtp.qq.com", 465) as s: # 使用上下文管理器自动关闭连接
s.login(msg_from, passwd) # 登录邮箱
s.sendmail(msg_from, msg_to, msg.as_string()) # 发送邮件
print('邮件发送成功') if __name__ == "__main__":
p = input("请输入要接收邮件的QQ邮箱地址:")
info = input("请输入要发送的内容:")
send_email(p, info)
- 默认值传参
需求:调用一个函数,传入一个大字符串和一个小字符串,查找小字符串在大字符串中出现
的次数,调用函数的时候,可以不传小字串,默认查找字符'a'在大字符串中的出现次数。
def str_number(big_str, small_str='a'): # 定义函数时,可以设置形式参数的值,作为默 认值
# dadqwwfwqfjwqaoiaiosijpoaospjfqwasaapjosaja
list1 = list(big_str)
counts = list1.count(small_str)
print(f"{small_str}在大字符串中总共出现了{counts}次。。。") str_number('dadqwwfwqfjwqaoiaiosijpoaospjfqwasaapjosaja') # 调用时若不传入第二个 参数,使用的就是定义时的默认值 str_number('dadqwwfwqfjwqaoiaiosijpoaospjfqwasaapjosaja','f') # 若传入第二个参 数,使用的就是实际传入的值
- 动态传参
未使用动态参数时,解决需求,比较麻烦,参数需要另外定义一个函数
# 需求1:定义一个函数,将来传入两个int类型的值求和
def sum1(a, b):
print(a + b)
sum1(10, 20)
def sum2(a, b, c):
print(a + b + c) # 需求2:定义一个函数,将来传入三个int类型的值求和
sum2(10, 20, 30)
使用动态参数,只需要定义一个函数就可以了
def sum1(*num): # 这里的num 是一个元组,接收若干个将来调用时传入的实参
n = 0
for i in num:
n = n + i
print(f"总和为:{n}")
sum1(10, 20) # (10, 20)
sum1(10, 20, 30) # (10, 20, 30)
sum1(10, 20, 30, 40) # (10, 20, 30, 40)
使用动态参数时的注意事项
- 传参的内容,多个参数的类型可以是不一样的
def sum1(*num): # 这里的num 是一个元组,接收若干个将来调用时传入的实参
# n = 0
# for i in num:
# n = n + i
# print(f"总和为:{n}")
print(num, type(num))
# sum1(10, 20) # (10, 20)
# sum1(10, 20, 30) # (10, 20, 30)
# sum1(10, 20, 30, 40) # (10, 20, 30, 40)
# sum1(11) # (11,)
# sum1(11, '小虎', [11, 22, 33]) # (11, '小虎', [11, 22, 33])
sum1((11,22,33)) # ((11, 22, 33),)
传入两个**的动态参数
def sum1(**num):
print(num, type(num))
sum1(name='小虎', age=18)
结论:
* : 表示传入的每一个单独的元素都被封装成一个元组
** : 表示传入的是一个一个的键值对,所有的键值对会被封装成一个字典
我们今后开发的时候,定义动态参数时,起名字是固定的,若一个*的动态参数,名字起为 *args, 若**的动态参数,名字起为**kwargs
def show1(a, b, *args, **kwargs):
print(args, type(args))
print(kwargs, type(kwargs))
# show1(11,22,33,44,name='小虎',address='合肥')
show1(11, 22, 33, 44, name='小虎', address='合肥')
函数的返回值
有些函数,我们调用完之后,是能够得到结果的,理论上来说,python中所有的函数都有返回值
python中提供了一个关键字给我们在函数中使用,表示调用完后返回的值,这个关键字叫做
return
- 例子
def sum1(a, b):
c = a + b
return c
res1 = sum1(10, 20)
print(res1)
print(res1+20)
函数返回值的特点
- 一个函数中如果没有写return, 默认情况下,这个函数最后一句话会有一个return None
- return 和print的区别?
- return是调用完函数时,可以返回一个值给调用者
- print就直接输出了,没有返回值
- 一个函数中,如果遇到了return,那么这个函数就结束了,函数中的后续代码不执行
def fun1(a, b):
print("今天是星期二")
c = a + b
return c
print("明天自习") # 不执行
res1 = fun1(10, 20)
print(res1)
- 一个函数中只能有一个return
def fun1(a, b):
print("今天是星期二")
c = a + b
return c
print("明天自习") # 不执行
return 100 # 无效代码
res1 = fun1(10, 20)
print(res1)
def fun1():
for i in range(1,11):
return i
res1 = fun1()
print(res1) # 1
- 函数返回值return后面,要返回的类型可以是任意的类型
函数参数和返回值的练习
定义 两个函数,第一个函数用户循环输入要累加的数值,函数内部将用户输入的值封装成一
个列表返回;第二个函数将第一个函数返回的列表当作参数传入,返回列表中所有数据之和的
结果。
def get_list():
list1 = []
while True:
n = int(input("请输入一个数值:"))
if n == -1:
break
list1.append(n)
return list1 def sum_list(l2):
n = 0
for i in l2:
n += i
return n l1 = get_list()
print(l1)
res2 = sum_list(l1)
print(res2)
函数返回值的的一些进阶用法
- 直接返回多个值,多个值之间使用英文逗号分隔,实际返回的内容是一个元组
def show1():
return 11, 22, 33
res1 = show1()
print(res1, type(res1))
- 分别接收每个返回元素的值
def show1():
return 11, 22, 33
a1, a2, a3 = show1()
print(f"a1:{a1}")
print(f"a2:{a2}")
print(f"a3:{a3}")
def show1():
return 11, ['hello','world','python'], 33
a1, a2, a3 = show1()
print(f"a1:{a1}") # a1:11
print(f"a2:{a2}") # a2:['hello', 'world', 'python']
print(f"a3:{a3}") # a3:33
函数的分类
- 无参无返回值
def login():
# 登录的操作逻辑
login()
- 无参有返回值
def get_number(): # 随机生成一个数
return num
n = get_number()
print(n)
- 有参无返回值
def sum1(a,b):
print(a+b)
sum1(10,20)
- 有参有返回值
def fun1(s1):
return "shujia:" + s1
res1 = fun1('hello')
函数可以进行嵌套
- 嵌套调用
def fun1():
print("hello world 1")
def fun2():
return 100
def fun3(a1, b1):
fun1() # 调用fun1函数
res1 = fun2() # 调用fun2函数
return a1 + b1 + res1
res2 = fun3(11,22)
print(res2)
- 嵌套定义
def fun1():
a = 10
def fun2():
print("hello world")
print(a)
fun2() # 不调用 不执行
fun1()
fun2() # 报错,调用不了函数内部定义的函数
函数练习2:定义一个函数,传入一个文本路径,和一个关键词,将文本中包含关键词的那一句话
拿出来放在一个列表中返回该列表
import os
def get_word_list(file_os, word):
res_list = []
if os.path.exists(file_os):
f = open(file_os, 'r', encoding='UTF-8')
line_list = f.readlines()
for line in line_list:
if word in line:
res_list.append(line.strip())
else:print("该路径不存在!!")
return res_list
list1 = get_word_list('data/words.txt', 'shujia')
print(list1)
def get_word_list(file_os, word):
res_list = []
if not os.path.exists(file_os):
print("该路径不存在!!")
return res_list
f = open(file_os, 'r', encoding='UTF-8')
line_list = f.readlines()
for line in line_list:
if word in line:
res_list.append(line.strip())
return res_list
list1 = get_word_list('data/words.txt', 'shujia')
print(list1)
函数的传值问题
在python中,调用函数时,传入的是对象的引用。
- 不可变对象【str, int, float, bool】
def fun1(x, y):
print(f"x:{x}, y:{y}") # x:hello, y:world
x = y
x = x + x
print(f"x:{x}, y:{y}") # x:worldworld, y:world s1 = "hello" s2 = "world"
print(f"s1:{s1}, s2:{s2}") # s1:hello, s2:world
fun1(s1,s2)
print(f"s1:{s1}, s2:{s2}") # s1:hello, s2:world
不可变对象的调用,仅在函数内生效,而不会通过地址影响到函数外的值
- 可变对象【list, tuple, dict, set, 类】
def fun1(x, y):
print(f"x:{x}, y:{y}") # x:['hello'], y:['world']
x = y
x.append('java')
print(f"x:{x}, y:{y}") # x:['world','java'], y:['world','java'] s1 = ['hello']
s2 = ['world']
print(f"s1:{s1}, s2:{s2}") # s1:['hello'] , s2:['world']
fun1(s1,s2)
print(f"s1:{s1}, s2:{s2}") # s1:['hello'], s2:['world', 'java']
可变对象函数内部可以进行操作,改变可变对象中存储的值,间接影响到函数外变量的引用
作用于与变量
在python中,作用域分为两个区域
- 函数外是一个作用域
- 函数内部是一个作用域
全局变量:将变量定义在函数外
局部变量:将变量定义在函数内部
全局变量和局部变量使用特点
- 局部作用域中可以使用到全局变量【可以使用函数外部定义的变量】
- 函数与函数内部的作用域是相互独立的,不能互相调用函数内部创建的局部变量
if 1==1:
a=10
print(f"a:{a}") for i in range(11):
pass
print(f"i:{i}")
python中提供了一个关键字 global, 在函数内部定义一个全局变量,出了函数也是可以被访问到
的。
def fun1():
global a
a = 100 fun1()
print(a)
注意:如果函数内部有变量被global修饰,需要先调用该函数,让内存中出现这个变量,后
续才能去使用。
进阶:函数名也可当一个变量使用
- 用法场景1:
def fun1():
print("好好学习,天天向上!")
fun2 = fun1
fun2()
赋值的时候,注意有没有小括号,方法名直接赋值,相当于给函数另起了一个名字;如果加了小括
号,相当于调用函数的结果赋值。
- 用法场景2:
def fun1():
print("鹅鹅鹅")
def fun2():
print("曲项向天歌")
def fun3():
print("白毛浮绿水")
def fun4():
print("红掌拨清波")
fun_list = [fun1, fun2, fun3, fun4]
flag = input("请输入开始:")
for i in fun_list:
i()
- 用法场景3:将函数作为返回值使用
def fun1():
print("鹅鹅鹅")
def fun2():
print("曲项向天歌")
def fun3():
print("白毛浮绿水")
def fun4():
print("红掌拨清波")
fun_list = [fun1, fun2, fun3, fun4]
def show1():
for i in fun_list:
i()
def function1():
return show1
res1 = function1()
res1()
- 用法场景4:将函数作为参数传递
def fun1():
print("鹅鹅鹅")
def fun2():
print("曲项向天歌")
def fun3():
print("白毛浮绿水")
def fun4():
print("红掌拨清波")
fun_list = [fun1, fun2, fun3, fun4]
def show1():
for i in fun_list:
i()
def function1(s):
s()
function1(show1)
随机推荐
- springboot 前端访问服务器上的图片及附件
一.需求 后端是springboot,附件上传到服务器上,前端访问服务器上的附件,如:显示图片.视频.文件等 二.解决方法 springboot 中进行资源映射,根据路径将磁盘上的文件映射为资源返回到 ...
- AI工具合集
以下工具来源于互联网,可能会失效,请参考使用 网红工具 名称 链接 说明 GPT-4 https://chat.openai.com/ 需要梯子,需要付费.功能最强大的聊天机 器人. 文心一言 h ...
- Angular Material 18+ 高级教程 – CDK Accessibility の ListKeyManager
介绍 ListKeyManager 的作用是让我们通过 keyboard 去操作 List Items. 一个典型的例子:Menu 有 4 个步骤: tab to menu enter 打开 menu ...
- Google – Cloud Translation API
前言 通常网站内容翻译,我们都不推荐使用 Google Translate.但网站中一些不那么重要的内容确实可以用 Google Translate.比如 Customer Reviews. 这篇是续 ...
- 课时09:Metasploit使用基础
下载地址:https://docs.metasploit.com/docs/using-metasploit/getting-started/nightly-installers.html Explo ...
- balance_dirty_pages_ratelimited分析
balance_dirty_pages_ratelimited分析 nr_dirtied_pause:当前task的脏页门限: dirty_exceeded:全局的脏页数超过门限或者该bdi的脏页数超 ...
- android系统启动流程- ServiceManager进程启动流程
*注:基于Android11源码 ServiceManager进程是在init进程创建的,所以我们从init进程的main()开始分析: // 文件路径: system/core/init/main. ...
- slab分配器正式被弃用,slub成为分配器唯一选择
在使用slab分配器进行内存分配时,可能会出现以下缺点: 内存碎片化.由于slab分配器需要将内存分成大小相同的块,如果分配不均衡或者对象大小不同,就容易导致内存碎片化. 性能下降.Slab分配器将内 ...
- 将一个Eigen::Matrix中的数据(数组格式),按行写入到json文件当中.
1.这里主要实现如何以数组的形式写入到json文件当中,因为c++的Jsoncpp库中的.append只支持一个字符的写入(还是python的json友好).去网上找了老久的解决办法,发现中文解答全是 ...
- Java日期时间API系列18-----Jdk8中java.time包中的新的日期时间API类,java日期计算5,其他常用日期计算,星期计算,闰年计算等
通过Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析中可以看出,java8中的方法特别丰富,一些常用的计算如星期计算,闰年计算等 ...