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)

随机推荐

  1. 技术教程 | 基于 Web 端的屏幕共享实践

    ​ 屏幕共享的英文叫做 DesktopSharing,通俗点讲就是将自己电脑的画面分享给其他人, 被分享的可以是整个电脑屏幕.应用程序或者某一个打开的网页等等. 而随着音视频领域的深入发展,完备的功能 ...

  2. Angular 18+ 高级教程 – Component 组件 の Attribute Directives 属性型指令

    介绍 指令就是没有模板的组件.除了模板其它的都有,比如 selector.inject.@Input.lifecycle 等等. 那既然都有完整的组件了,为什么还搞一个少掉模板的指令呢? 很简单啊,因 ...

  3. Maven高级——分模块开发与设计

    分模块开发的意义 将原始模块按照功能拆分成若干个子模块,方便模块间的相互调用,接口共享 分模块开发 创建Maven工程 书写模块代码 注意:分模块开发需要先针对模块功能进行设计,再进行编码.不会先将工 ...

  4. Codeforces Round 973 (Div. 2) C

    #include <bits/stdc++.h> using namespace std; int T; int n; struct edge { int pre; int nxt; in ...

  5. 暑假集训CSP提高模拟18

    \[暑假集训CSP提高模拟 \ 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1 \] Very good problem, this make my news rotate. ...

  6. LeetCode 730. Count Different Palindromic Subsequences (区间DP)

    题意 给一个字符串S,求它所有子序列中不同非空回文串的数量.字符串由 'a' 'b' 'c' 'd' 四个字母组成. 由于题目要求的是不同回文串. abba 的回文串子序列为 a,b,aba,abba ...

  7. Spring事务的1道面试题

    每次聊起Spring事务,好像很熟悉,又好像很陌生.本篇通过一道面试题和一些实践,来拆解几个Spring事务的常见坑点. 原理 Spring事务的原理是:通过AOP切面的方式实现的,也就是通过代理模式 ...

  8. CSharp的lambda表达式的使用

    using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using Syst ...

  9. element-admin - 图片上传组件 ImageUpload

    预览详情 : 父组件:注册引入子组件 :只需要传递一个数据  limit  :这是限制显示多少张图片 : 子组件: - 图片上传 - el-upload 代码 : <template> & ...

  10. 倒计时 3 天!10.23 相约杭州,云原生 Meetup 等你来!

    云原生技术交流 Meetup 杭州站开启,快来报名吧! 活动简介 随着云原生技术的普及,整个市场已经变成了节奏非常快的软件驱动型市场,使用云原生技术栈来迭代发布应用已经成为常态,但是如何更好的应用云原 ...