当前位置: 首页 > news >正文

python之函数总结

函数
对于函数的学习,我整理了网上的一些资料,希望可以帮助到各位!!!
世界级的编程大师Martin Fowler先生曾经说过:“代码有很多种坏味道,重复是最坏的一种!”。

为什么使用函数

问题:代码重复
        后期维护成本太高
        代码可读性不高
解决问题:函数
        在一个完整的项目中,某些功能会被反复使用,那么将这部分功能对应的代码提取出来,当需要使用功能的时候直接使用
本质:对一些特殊功能的封装
优点:
a.简化代码结构,提高应用的效率
b.提高代码复用性
c.提高代码的可读性和可维护性
        

建议:但凡涉及到功能,都尽量使用函数实现

定义函数

语法:
        def函数名(参数1,参数2,参数3.…)
                函数体
                返回值(可以有也可以没有,根据具体的场景)
说明:
a.函数由两部分组成:声明部分和实现部分
b.def,关键字,是define的缩写,表示定义的意思
c.函数名:类似于变量名,遵循标识符的命名规则,做到见名知意
d.():表示的参数列表的开始和结束
e.参数1,参数2,参数3…:参数列表[形式参数,简称为形参],其实本质上就是一个变量
名,参数列表可以为空
f.函数体:封装的功能的代码
g.返回值:一般用于结束函数,可有可无,如果有返回值,则表示将相关的信息携带出去,携带给调用者,如果没有返回值,则相当于返回None

#test() name'test'isnotdefined #函数调用不能在函数定义的上面
def test():print("平安!")

函数调用 

test()#函数调用
test()
test()
函数调用的格式:函数名()
1.函数是条狗,哪里需要哪里吼。函数定义以后不会自动执行,若想执行函数中的函数体,需要调用函数
2.函数必须先定义,后调用。调用函数必须在定义函数的下边。
3.函数可以多次调用。
4.在同一个文件中,出现了重名的函数,后面的函数会把前面的函数覆盖。调用的时候执行后面的函数。

函数的分类

1.按照函数是否是自己定义分为:
内置函数:比如:print()、int()、str()、upper()、lower()
python语言内部已经定义好的,可以直接使用的
自定义函数:根据自己的需求定义的函数


2.根据函数中有没有参数分为:
有参数的函数:在定义函数时传入的参数叫做形式参数(形参)在调用函数时传入的参数叫做实际参数(实参)
没有参数的函数:


3.根据定义的函数有没有函数名分为:
有名字的函数:

def函数名():
        函数体
匿名函数:通过lambda定义


4.根据函数中是否有返回值分为:
有返回值的函数:使用return返回数据
没有返回值的函数:

无参数的函数

def test():print("年少青春!")

 有参数的函数

# 有参数的函数:
def my_sum(a, b):  # a,b就是形参print(a + b)my_sum(12, 23)  # 12,23就是实参 35

没有返回值的函数

# 没有返回值的函数
def say():print("我是没有返回值的函数")say()

有返回值的函数

# 有返回值的函数:通过return关键字返回数据
def demo():return "我是有返回值的函数"str = demo()
print(str)
'''
1.return后面可以返回一个或者多个数据,返回多个数据,以元组的形式展示出来
2.return下面的代码不会执行
'''def demo1():print("哈你妹!")return 12, 34, 578print("haha")  # 不会执行tuple1 = demo1()
print(tuple1)  # (12,34,578)# 函数中没有return或者return后面没有数据返回,则默认返回的是None
def demo2():returnprint(demo2())  # None

注意:
1.有返回值的函数,使个变量接收返回的数据.用return关键字将数据返回,若想使用返回的数据,需要在调用函数的位置定义一个变量接收返回的数据
2.return返回的数据可以是一个或者多个,返回的多个数据是以元组的形式展示
3.return关键词下面的代码不会执行
4.在函数中若不写return或者return后面没有返回具体的数据,则返回的是None

 

函数嵌套函数

函数的调用顺序:
函数之间可以进行相互嵌套
def test():test1()print(11111)def test1():test2()print(22222)def test2():test3()print(333333)def test3():print(44444)test()

函数中的参数

参数列表:如果函数所实现的功能涉及到未知项参与运算,此时就可以将未知项设置为参数
格式:参数1,参数2…
分类:
形式参数:在函数的声明部分,本质就是一个变量,用于接收实际参数的值【形参】
实际参数:在函数调用部分,实际参与运算的值,用于给形式参数赋值【实参】
传参:实际参数给形式参数赋值的过程,形式参数=实际参数

def get_max(num1, num2):  # num1,num2是形参if num1 > num2:return num1else:return num2max_value = get_max(12, 345)  # 12,345是实参
print(max_value)

形参和实参之间的关系:
1.一般请况下,形参的数量和实参的数量保持一致
2.在函数中,形参的名字和实参的名字一样不会产生任何影响

参数的类型

a.必需参数
调用函数的时候必须以正确的顺序传参,传参的时候参数的数量和形参必须保持一致
# 必需参数
def student(name, age):print("我的姓名是%s,年龄是%d" % (name, age))student("py小王子", 21)
student(21, "py小王子")  # TypeError: %d format: a real number is required, not str
b.关键字参数
使用关键字参数允许函数调用的时候实参的顺序和形参的顺序可以不一致,可以使用关键字进行自动的匹配
def student(name, age):print("我的姓名是%s,年龄是%d" % (name, age))student(age=21, name="py小王子")
c.默认参数(默认参数是在函数定义的时候,直接给形参赋的值)
调用函数的时候,如果没有传递参数,则会使用默认参数,如果传输了参数,则使用传递的参数.
def get_sum(num1, num2=12):print(num1 + num2)get_sum(23)  # 35
get_sum(23, 87)  # 110
注意:
如果函数中有多个形参 , 给该函数设置默认参数时 , 一般把这个默认参数放在形参列表的最后面

 d.不定长参数(可变参数)

可以处理比当初声明时候更多的参数元组、字典
args:        用来接收多个位置参数        argments        得到的形式是        元组
kwargs:用来接收多个关键字参数        keyword arguments        得到的形式是        字典

# 不定长参数:*args **kwargs
def fn(*args):print(args)  # (34, 533, 4, 3)fn(34, 533, 4, 3)
# 注意:
"""
在自定义函数时,若函数中有多个参数,某一个参数是不定长参数,一般把不定长参数放在参数列表的最后面。
110"""def fn1(name, *args):print(name, args)  # py小王子 (12, 345, 6, 'hehe', True)fn1("py小王子", 12, 345, 6, "hehe", True)# kwargs接收的是关键字参数,格式是key=value这种形式
def fn2(**kwargs):print(kwargs)  # {'x': 10, 'y': 12, 'z': 88}fn2(x=10, y=12, z=88)

 函数使用练习:

1.封装函数,计算1-100之间所有的数字的和

# 计算1-100之间所有的数字的和
def total():sum = 0for i in range(101):sum = sum + ireturn sumif __name__ == '__main__':print(f'1-100的和为:{total()}')

2.封装函数,将1-100之间个位数为3的数字输出

# 将1-100之间个位数为3的数字输出
def three():list = []for i in range(101):if i == 3:list.append(i)elif i % 10 == 3:list.append(i)return listif __name__ == '__main__':print(f'1-100之间个位数为3的有{three()}')

 匿名函数(lqmbda)

不再使用def这种的形式定义函数,使用lambda来创健匿名函数
特点:
a.lambda只是一个表达式,比普通函数简单
b.lambda一般情况下只会书写一行,包含参数,实现体,返回值


语法:lambda参数列表:实现部分

# 匿名函数:lambda
def fn(n):return n ** 2print(fn(3))  # 9# 匿名函数
f1 = lambda n: n ** 2
print(f1(3))  # 9# 匿名函数
f2 = lambda x, y: x * y
print(f2(12, 3))  # 36# 有名字的函数的写法
def ji(x, y):return x * yprint(ji(12, 3))  # 36

回调函数 

def fn(a, b):print(a + b)fn(12, 34)  # 46test = fn  # 将函数fn赋值给一个变量test,那这个变量test能够实现和函数fn一样的功能
print(type(test), type(fn))  # <class 'function'><class function'>
test(12, 34)  # 46# 函数名:f既是函数的名称,同时也指向了该函数的对象(变量)
# 函数调用的格式:函数名()====>变量名)
# 回调函数:把一个函数(a)作为一个参数传递到另外一个函数(b)中去,那么函数就叫做回调函数。
def add(x, y):print(x + y)def cha(x, y):print(x - y)def ji(x, y):print(x * y)def shang(x, y):print(x / y)
add(56, 23)
cha(78, 21)# 封装一个函数,实现加减乘除运算。
def demo(x, y, func):func(x, y)
demo(56, 23, add)
# 此时add函数就是一个回调函数
demo(78, 12, cha)

闭包

如果在一个函数的内部定义另外一个函数,外部的函数叫做外函数,内部的函数叫做内函数
如果在一个外部函数中定义一个内部函数,并且外部函数的返回值是内部函数,就构成了一个闭包,则这个内部函数就被称为闭包【closure
实现函数闭包的条件 :
1. 必须是函数嵌套函数
2. 内部函数必须引用一个定义在闭合范围内的外部函数的变量 ,---- 内部函数引用外部变量
3. 外部函数必须返回内部的函数
# 最简单的闭包
# 外部函数
def outer():# 内部函数def inner():print("lala")return inner  # 将内部函数返回
fn = outer()
# fn=====>inner函数
fn()# 相当于调用了inneri函数输出lala# 内部函数使用外部函数的变量
def outerl(b):a = 10def innerl():# 内部函数可以使用外部函数的变量print(a+b)return innerl
fun1=outerl(12)
fun1()#22
注意:
1.当闭包执行完毕后,仍然能够保存住当前的运行环境
2.闭包可以根据外部作用域的局部变量得到不同的效果,类似于配置功能,类似于我们可以通过修改外部变量,闭包根据变量的改变实现不同的功能.
应用场景:装饰器

装饰器 

def test():print("你好啊!")test()# 需求:给上面的函数test增加一个功能,输出我很好# 第一种方式:修改了原来的函数
def test():print("你好啊!")print("我很好")test()# 第二种方式:定义一个新函数,在新函数中调用原函数,然后追加功能
def test1():test()print("我很好")
test1()

在代码运行期间,可以动态增加函数功能的方式,被称为装饰器
[Decorator]通过闭包函数实现。也就是说,在不修改原函数的基础上,给原函数增加功能
好处:在团队开发中,如果两个或者两个以上的程序员会用到相同的功能,但是功能又有细微的差别,采用装饰器:相互不影响,代码简化

 使用装饰器

装饰器是Python中用一个函数装饰另外一个函数或类并为其提供额外功能的语法现象。装饰器本身是一个函数,它的参数是被装饰的函数或类,它的返回值是一个带有装饰功能的函数。很显然,装饰器是一个高阶函数,它的参数和返回值都是函数。

简单装饰器

#原函数
def test():print("你好啊!")#需求:给上面的函数test增加一个功能,输出我很好
#第三种方式:通过装饰器的方式给函数追加功能
"""
装饰器使用闭包实现
闭包函数:
1.函数嵌套函数
2.内部函数使用外部函数的变量
3.外部函数中返回内部函数
"""
#a.书写闭包函数   此处的outer函数就是装饰器函数
def outer(fn):#b.fn表示形参,实际调用的时候传递的是原函数的名字def inner():fn()  # 先调用原函数print("我很好")  # 后打印“我很好”return innerprint("添加装饰器之前:",test,__name__)#<function test at 0x00000273421BA2A0>
test = outer(test)
print("添加装饰器之后:",test,__name__)#<function outer.<locals>.inner at 0x00000273423058A0>
test()

系统的简写

# a.书写闭包函数
# 此处的outer函数就是装饰器函数
def outer(fn):  # fn表示形参,实际调用的时候传递的是原函数的名字def inner():fn()  # c.调用原函数print("我很好")  # d.给原函数添加功能,注意:添加的功能可以写在原函数的上面也可以写在原函数的下面return inner# 装饰器的简写方式@+装饰器名称
@outer
# 等价于=====>test = outer(test)
def test():print("你好啊!")test()

注意:
1.在使用装饰器的简写方式的时候,原函数必须在装饰器函数的下面
2.outeri就是装饰器函数。@outer等价于test outer(test) 

不定长参数的装饰器(通用装饰器) 

#同一个装饰器装饰多个函数
def jisuan(fn):def inner(*args):print("数学运算的结果是:", end="")fn(*args)return inner@jisuan
def add(a, b):print(a + b)add(12, 34)@jisuan
def cha(a, b, c):print(a - b - c)cha(100, 23, 26)

1. 装饰器jisuan的原理

  • 闭包实现jisuan函数是一个装饰器,它利用了闭包的特性。在jisuan函数内部定义了inner函数,inner函数使用了外部函数jisuan的变量fn(这里fn是被装饰的函数)。
  • 功能实现inner函数在执行被装饰函数fn之前,会先打印"数学运算的结果是:",并且通过end=""设置不换行。这样,当使用这个装饰器装饰其他函数时,这些函数在执行计算并输出结果之前都会先输出这个提示。

2. 被装饰函数addcha的执行过程

  • add函数
    • 当定义add函数并使用@jisuan装饰时,add函数被传递给jisuan函数,jisuan函数返回inner函数,此时add实际上指向了inner函数。
    • 当执行add(12, 34)时,实际上是执行inner(12, 34)。首先会打印"数学运算的结果是:",然后执行fn(*args),这里fn就是原来的add函数,会计算并打印12 + 34的结果,即46
  • cha函数
    • 同理,cha函数被jisuan装饰后,当执行cha(100, 23, 26)时,先执行inner(100, 23, 26),会先打印"数学运算的结果是:",然后执行原来cha函数的功能,计算并打印100 - 23 - 26的结果,即51

带返回值的装饰器

def outer(fn):def inner():print("我的爱好是:", end="")return fn()return inner@outer
def swim():return "i like swimming!"love = swim()
print(love)
  • 首先定义了装饰器outer,它的内部函数inner在调用被装饰的函数fn之前会先打印"我的爱好是:"
  • 然后swim函数被outer装饰,swim函数返回"i like swimming!"
  • 当执行love = swim()时,实际上是先执行inner函数(因为swimouter装饰),inner函数先打印"我的爱好是:",然后调用swim函数,swim函数返回"i like swimming!",这个结果被赋值给love,最后print(love)输出我的爱好是:i like swimming!

多个装饰器作用同一个函数

  • 当多个装饰器修饰一个函数的时候,装饰器从上往下依次执行,并且原函数只执行一次(这里是先outer2,再outer1)。
  • 当调用show()时,首先执行outer2装饰器中的inner函数,打印-2222,然后执行outer1装饰器中的inner函数,打印-1111,最后执行原函数show,打印今晚我的好朋友从广州过来了,好开心!。。..
#多个装饰器作用于一个函数
def outer1(fn):def inner():print("-1111")fn()return innerdef outer2(fn):def inner():print("-2222")fn()return inner#原函数
@outer2
@outer1
def show():print("今晚我的好朋友从广州过来了,好开心!。。..")show()

用模块管理函数

不管用什么样的编程语言来写代码,给变量、函数起名字都是一个让人头疼的问题,因为我们会遇到命名冲突这种尴尬的情况。最简单的场景就是在同一个.py文件中定义了两个同名的函数

def foo():print('hello, world!')def foo():print('goodbye, world!')foo()    # goodbye, world!

如果项目是团队协作多人开发的时候,团队中可能有多个程序员都定义了名为foo的函数,这种情况下怎么解决命名冲突呢?答案其实很简单,Python中每个文件就代表了一个模块(module),我们在不同的模块中可以有同名的函数,在使用函数的时候我们通过import关键字导入指定的模块再使用完全限定名的调用方式就可以区分到底要使用的是哪个模块中的foo函数。

module1.py

def foo():print('hello, world!')

module2.py

def foo():print('goodbye, world!')

 test.py

方法1、模块名.函数名

import module1
import module2# 用“模块名.函数名”的方式(完全限定名)调用函数,
module1.foo()    # hello, world!
module2.foo()    # goodbye, world!

方法2、使用as关键字对模块进行别名

import module1 as m1
import module2 as m2m1.foo()    # hello, world!
m2.foo()    # goodbye, world!

方法3、用from...import..语法从模块中直接导入需要使用的函数

from module1 import foofoo()    # hello, world!from module2 import foofoo()    # goodbye, world!

方法4、如果想在上面的代码中同时使用来自两个模块中的foo函数也是有办法的,还是用as关键字对导入的函数进行别名

from module1 import foo as f1
from module2 import foo as f2f1()    # hello, world!
f2()    # goodbye, world!

标准库中的模块和函数

经典小案例

案例1:设计一个生成验证码的函数(说明:验证码由数字和英文大小写字母构成,长度可以用参数指定。)

# 案例1:设计一个生成验证码的函数(说明:验证码由数字和英文大小写字母构成,长度可以用参数指定。)
import random
import stringdef captcha(n):all_characters = string.ascii_letters + string.digits  # 包含所有大小写字母和数字的字符串captcha_code = ''.join(random.choice(all_characters) for _ in range(n))return captcha_codeif __name__ == '__main__':n = int(input('请输入验证码长度:'))print(f"验证码为:{captcha(n)}")

案例2:设计一个函数返回给定文件的后缀名。

说明:文件名通常是一个字符串,而文件的后缀名指的是文件名中最后一个`.`后面的部分,也称为文件的扩展名,它是某些操作系统用来标记文件类型的一种机制,例如在Windows系统上,后缀名`exe`表示这是一个可执行程序,而后缀名`txt`表示这是一个纯文本文件。需要注意的是,在Linux和macOS系统上,文件名可以以`.`开头,表示这是一个隐藏文件,像.gitignore这样的文件名,`.`后面并不是后缀名,这个文件没有后缀名或者说后缀名为`''

def get_suffix(filename, ignore_dot=True):"""获取文件名的后缀名:param filename: 文件名:param ignore_dot: 是否忽略后缀名前面的点:return: 文件的后缀名"""# 从字符串中逆向查找.出现的位置pos = filename.rfind('.')# 通过切片操作从文件名中取出后缀名if pos <= 0:return ''return filename[pos + 1:] if ignore_dot else filename[pos:]print(get_suffix('readme.txt'))       # txt
print(get_suffix('readme.txt.md'))    # md
print(get_suffix('.readme'))          #
print(get_suffix('readme.'))          #
print(get_suffix('readme'))           #

案例3:写一个判断给定的正整数是不是质数的函数。

def is_prime(num: int) -> bool:"""判断一个正整数是不是质数:param num: 正整数:return: 如果是质数返回True,否则返回False"""for i in range(2, int(num ** 0.5) + 1):if num % i == 0:return Falsereturn num != 1if __name__ == '__main__':num = int(input("请输入数字:"))if is_prime(num):print(f"{num}为质数")else:print(f"{num}不为质数")

案例4:写出计算两个正整数最大公约数和最小公倍数的函数 

方法1、

def gcd_and_lcm(x: int, y: int) -> int:"""求最大公约数和最小公倍数"""a, b = x, ywhile b % a != 0:a, b = b % a, areturn a, x * y // a

方法2、

def gcd(x: int, y: int) -> int:"""求最大公约数"""while y % x != 0:x, y = y % x, xreturn xdef lcm(x: int, y: int) -> int:"""求最小公倍数"""return x * y // gcd(x, y)

案例5:写出计算一组样本数据描述性统计信息的函数。

import mathdef ptp(data):"""求极差"""return max(data) - min(data)def average(data):"""求均值"""return sum(data) / len(data)def variance(data):"""求方差"""x_bar = average(data)temp = [(num - x_bar) ** 2 for num in data]return sum(temp) / (len(temp) - 1)def standard_deviation(data):"""求标准差"""return math.sqrt(variance(data))def median(data):"""找中位数"""temp, size = sorted(data), len(data)if size % 2 != 0:return temp[size // 2]else:return average(temp[size // 2 - 1:size // 2 + 1])

总结 

“代码有很多种坏味道,重复是最坏的一种!”

恭喜你学会了函数,快去试试吧!!!


http://www.mrgr.cn/news/64363.html

相关文章:

  • 【机器学习】26. 聚类评估方法
  • 九识智能与徐工汽车达成战略合作,共绘商用车未来新蓝图
  • 手机实时提取SIM卡打电话的信令声音-新的篇章(三、Android虚拟声卡探索)
  • openGauss数据库-头歌实验1-3 创建和管理模式
  • 优化低代码开发平台用户体验:功能树导航设计探讨
  • Vue前端开发:事件对象参数
  • 逼着自己深度思考
  • python对数据平滑处理
  • 线程的等待,分离,与异步获取执行结果
  • 线程的joinable属性,以及主线程出现异常时,对其等待应该进行的处理
  • MybatisPlus - 扩展功能
  • 文献阅读记录6-Toward computer-made artificial antibiotics
  • 初始JavaEE篇——多线程(8):JUC的组件
  • EDM平台升级 送达率与效果并进
  • tftp协议笔记
  • 【C++刷题】力扣-#643-子数组最大平均数I
  • 堆的实现--数据结构
  • 重装linux系统
  • 网页自动化测试和爬虫:Selenium库入门与进阶
  • C语言中的希尔排序
  • 大厂面试真题-如果使用guava limiter实现实例级别的缓存
  • JSP ft06 问题几个求解思路整理
  • 我国在AI领域的发展趋势
  • 【springcloud】服务之间调用失败的重试机制
  • 微服务架构面试内容整理-微服务架构的定义及优势
  • C++ --- 多线程的使用