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

10-Python基础编程之函数

Python基础编程之函数

  • 概念
  • 基本使用
  • 参数
    • 单个参数
    • 多个参数
    • 不定长参数
    • 缺省参数
    • 注意事项
  • 返回值
  • 使用描述
  • 偏函数
  • 高阶函数
  • 返回函数
  • 匿名函数
  • 闭包
  • 装饰器
  • 生成器
  • 递归函数
  • 函数的作用域

概念

写了一段代码实现了某个小功能:然后把这些代码集中到一块,起一个名字;下一次就可以根据这个名字再次使用这个代码块,这就是函数写了一段代码实现了某个小功能:然后把这些代码集中到一块,起一个名字;下一次就可以根据这个名字再次使用这个代码块,这就是函数。

作用:方便代码的重用;分解任务,简化程序逻辑;使代码更加模块化。

函数分为:内建函数;三方函数;自定义函数。

基本使用

简单定义:

def 函数名():函数体

函数调用:

函数名()

参数

单个参数

场景:需要动态的调整函数体中某一个处理信息,则可以以参数的形式接收到相关数据。

def 函数名(参数名称):函数体(函数体中,可以直接以变量的方式使用该参数)# 调用
函数体(参数值)

形参和实参的概念:
上述函数定义中,参数名称即为形参;
在调用函数的时候,传递的真实数据,即为实参。

def test(num): # num是形参print(num**1)print(num**2)print(num**3)
test(5) # 5是实参

输出:
5
25
125

多个参数

场景:需要动态的调整函数体中多个处理信息时,则可以以 逗号 做分割,接收多个参数。

def 函数名(参数名称1,参数名称2):函数体(函数体中,可以直接以变量的方式使用所有参数)

调用方式:

  1. 函数名(参数1, 参数2,参数3…)
    形参和实参:一一对应。
  2. 函数名(参数名称1=参数1,参数名称n = 参数n…)
    可以指明形参名称称为“关键字参数”,不需要严格按照顺序。
def Sum(num1, num2):print(num1,num2)print(num1 + num2)
Sum(4,5)
Sum(num2=5,num1=4)

输出:
在这里插入图片描述

不定长参数

场景:如果函数体中,需要处理的数据,不确定长度,则可以以不定长参数的方式接收数据。

方式一:

def 函数名(*args):函数体(元组,函数体中,可以直接以元组变量的方式使用该参数)
函数名(参数1,参数2,参数3...)
def mySum(*t):print(t, type(t))result = 0for v in t:print(v)result += vprint(result)
mySum(4,5,6,7)

输出:
在这里插入图片描述
方式二:

def 函数名(**dic):函数体(字典,函数体中,可以直接以字典变量的方式使用该参数)
函数名(参数名1=参数1,参数名2=参数2,参数名3=参数3...)
def Sum(**kwargs):print(kwargs,type(kwargs))
Sum(name="sz",age=12)

输出:
在这里插入图片描述
装包与拆包:
把传递的参数,包装成一个集合,称之为“装包”。
把集合参数,再次分解成单独的个体,称之为”拆包”。

def test(*args):print(args)# 拆包print(*args)test(1,2,3,4)

输出:
(1, 2, 3, 4)
1 2 3 4

# 根据此,我们就能用一个输入来直接进行多个参数的输入
def mySum(a,b,c,d):print(a+b+c+d)
def test(*args):print(args)#拆包print(*args)#mySum((1,2,3,4))#mySum(args[0],args[1],args[2], args[3])mySum(*args)
test(1,2,3,4)

输出:
在这里插入图片描述

def mySum(a,b):print(a)print(b)
def test(**kwargs):print(kwargs)# 拆包操作# 应该使用 **进行拆包操作# print(**kwargs)mySum(**kwargs)
test(a=1,b=2)

输出:
在这里插入图片描述

缺省参数

当我们使用一个函数的时候,如果大多数情况下,使用的某个数据是一个固定值,或者属于主功能之外的小功能实现:则可以使用默认值 · 这种参数,称为"缺省参数”。

def 函数名(变量名1=默认值1,变量名2=默认值2):函数体(函数体中,即使外界没有传递指定变量,也可以使用,只不过值是给定的默认值)函数名(变量1,变量2) # 此处如果是缺省参数,则可以不填写
def hit(somebody="DB"): # 若不写somebody="DB",只写somebody且函数内不写参数,则会报错print("我想打",somebody)
hit() 

输出:
我想打 DB

注意事项

值传递:是指传递过来的,是一个数据的副本;修改副本,对原件没有任何影响。
引用传递:是指传递过来的,是一个变量的地址通过地址,可以操作同一份原件。

但在Python当中,只有引用传递(地址传递)。
在这里插入图片描述
但是如果数据类型是可变类型,则可以改变原件;如果数据类型是不可变类型(在Python中不可变的数据类型有3种,分别是整型、字符串和元组),则不可以改变原件。

  1. 首先我们看看不可变的:
    在这里插入图片描述
    发现他的地址是不一样的
    在这里插入图片描述
  2. 来看看可变的:
    在这里插入图片描述
    发现他的地址是一样的
    在这里插入图片描述

返回值

场景:当我们通过某个函数,处理好数据之后,想要拿到处理的结果。

# 语法
def 函数():函数体return 数据

注意:return的后续代码不会被执行;只能返回一次;如果想要返回多个数据,可先把多个数据包装成一个集合,整体返回。

示例:

# 对于单个返回
def mySum(a,b):result = a+breturn resultres = mySum(6,7)
print(res)# 对于多个返回
def caculate(a,b):he = a+bcha = a-breturn (he,cha)he,cha=caculate(6,7)
res = caculate(6,7)
print(res[0])
print(res[1])
print(he,cha)

输出:
13
13
-1
13 -1

使用描述

当我们编写三方函数,为了方便他人使用,就需要描述清楚我们所写的函数功能以及使用方式等信息。

# 定义格式
''' 直接在函数体的最上面,添加三个双引号对注释 '''
def 函数():"""这里写帮助信息"""

查看函数使用文档:help(函数)

一般的函数描述包括:

  1. 函数的功能
  2. 参数(含义、类型、是否可以省略、默认值)
  3. 返回值(含义、类型)

示例:
在这里插入图片描述

偏函数

概念:当我们写一个参数比较多的函数时,如果有些参数,大部分场景下都是某一个固定值,那么为了简化使用,就可以创建一个新函数,指定我们要使用的函数的某个参数,为某个固定的值,这个新函数就是“偏函数”。

# 法1:自己写一个新的
def test(a,b,c,d=1):print(a+b+c+d)
def test1(a,b,c=1,d=4): # 偏函数test(a,b,c,d)
test1(1,2)# 法2:利用newFunc = functools.partial(函数, 特定参数=偏值)
import functools
newFunc = functools.partial(test,c=1) # 指定函数,和什么值做偏值
print(newFunc, type(newFunc))
newFunc(1,2)

输出:
在这里插入图片描述

示例:

# 利用偏函数
# 在往后的一段时间内,我都需要把一个二进制的字符串,转换成为对应的十进制数据
numStr='100100'
import functools
int2 = functools.partial(int, base=2)
print(int2(numStr))

输出:36

高阶函数

概念:当一个函数A的参数,接收的又是另一个函数时,则把这个函数A或为是“高阶函数”。

# 函数本身可以作为数据传递给另一个变量
def test(a,b):print(a + b)
print(test)
print(id((test)))
test2 = test
test2(1,2)

输出:
在这里插入图片描述

# 拿sorted举例
l=[{"name":"sz","age":18},{"name": "sz2", "age": 19},{"name":"SZ3","age" : 18.5}]
def getKey(x):return x["age"]
result = sorted(l, key=getKey) # key指定一个函数
print(result)

输出:
[{‘name’: ‘sz’, ‘age’: 18}, {‘name’: ‘SZ3’, ‘age’: 18.5}, {‘name’: ‘sz2’, ‘age’: 19}]

示例:
计算两个动态数据(利用回调函数)

# caculate称为高阶函数
def caculate(num1, num2, caculateFunc): # 参数caculateFunc接受的就是另外一个函数result = caculateFunc(num1, num2)print(result)
def sum(a, b):return a + b
def jianfa(a, b):return a-b
caculate(6,2,jianfa)

输出:4

返回函数

概念:是指一个函数内部,它返回的数据是另外一个函数,把这样的操作成为“返回函数”。

# 根据不同参数,获取不同操作,做不同计算
def getFunc(flag):# 1.再次定义几个函数def sum(a,b,c):return a+b+cdef jian(a,b,c):return a-b-c# 2.根据不同的flag值,来返回不同的操作函数if flag == "+":return sumelif flag == "-":return jian
result = getFunc("+")
# print(result, type(result))
res =result(1,3,5)
print(res)

输出:9

匿名函数

概念:称为lambda函数,指没有名字的函数。

语法结构:lambda 参数1, 参数2… :表达式
注意事项:只能写一个表达式,并且不能直接return;表达式的结果就是返回值;只适用一些简单的操作。

# 1.
result=(lambda x,y:x+y)(1,2)
print(result)
# 2.
newFunc = lambda x,y:x+y
print(newFunc(4,5))
# 3.
l=[{"name":"sz","age":18},{"name": "sz2", "age": 19},{"name":"SZ3","age" : 18.5}]
result = sorted(l, key= lambda x: x["age"]) 
print(result)

输出:
在这里插入图片描述

闭包

概念:在函数嵌套的前提下,内层函数引用了外层函数的变量(包括参数),外层函数又把内层函数当做返回值进行返回。这个内层函数+所引用的外层变量,称为"闭包。
在这里插入图片描述

# 函数定义理解
def test():a = 10def test2():print(a)return test2
newFunc = test()
newFunc()

作用:外层函数,根据不同的参数,来生成不同作用功能的函数。
示例:

# 根据配置信息,生成不同的分割线函数
def line_config(content, length):def line():print("-"*(length //2)+ content + "-"*(length // 2))return line
line1 = line_config("闭包",40)
line1()

输出:

注意事项:

  1. 闭包中,如果要修改引用的外层变量需要使用nonlocal变量声明,否则当做是闭包内,新定义的变量。
# 查看默认情况
def test():num = 16def test2():num = 666print(num)print(num) # 查看外部函数numtest2() # 调用内部函数,查看内部函数输出结果print(num) # 调用内部函数后,再次查看外部函数的num,发现并没有改变,说明内部的不会改变return test2
result = test()# 若想在内部改变
def test():num = 16def test2():nonlocal num # 设置为非局部变量num = 666print(num)print(num) # 查看外部函数numtest2() # 调用内部函数,查看内部函数输出结果print(num) # 调用内部函数后,再次查看外部函数的num,发现改变了return test2
result = test()

输出:
在这里插入图片描述

  1. 当闭包内,引用了一个,后期会发生变化的变量时,一定要注意
    在这里插入图片描述
def test():funcs =[]for i in range(1,4):def test2(num):#num1def inner():print(num)return innerfuncs.append(test2(i))return funcs
newFuncs = test()
print(newFuncs) # 发现是存储了四次函数
newFuncs[0]() # 调用第一个
newFuncs[1]()
newFuncs[2]()

输出:
在这里插入图片描述

装饰器

作用:在函数名以及函数体不改变的前提下,给一个函数附加一些额外代码。

设计思路:

  1. 业务逻辑代码非常多就造成了每一份逻辑代码,在调用具体的功能函数之前都需要去做一个验证,代码冗余度就比较大,代码的复用性比较差,代码的维护性比较差。
  2. 直接在功能函数里面,去修改,方便代码的重用。
  3. 函数名字不能发生改变。
  4. 函数体内部的代码不能发生改变。
  5. 装饰器的执行时间是立即执行。
def check(func):def inner():print("登录验证操作....")func()return inner
@check # 在此处就执行了check函数
def fss():print("发说说")
# @check 等于操作 fss = check(fss)
fss()

输出:
登录验证操作…
发说说

进阶使用:

  1. 装饰器可以叠加
    从上到下装饰,从下到上执行。
# 装饰器1
def zhuangshiqi_line(func):def inner():print("-"*20)func()return inner
# 装饰器2
def zhuangshiqi_star(func):def inner():print("*"* 30)func()return inner
@zhuangshiqi_line
@zhuangshiqi_star # 等效于print_content = zhuangshigi_star(print_content)
def print_content():print("菜就多练")
print_content()

输出:
在这里插入图片描述

  1. 对有参函数进行装饰:无论什么场景,保证函数调用参数个数一致;为了通用,可以使用不定长参数,结合拆包操作进行处理。
def zsq(func):def inner(*args, **kwargs): # 接受随机参数,组为元组和字典print("_"* 30)print(args, kwargs)func(*args, **kwargs) # 打印是要进行拆包的return inner
@zsq
def pnum(num, num2, num3):print(num,num2,num3)
@zsq
def pnum2(num):print(num)
pnum(123,222,num3=666)
pnum2(999)

输出:
在这里插入图片描述

  1. 对有返回值的函数进行装饰:无论什么场景,保证函数返回值一致。
# 对有返回值的函数进行装饰:无论什么场景,保证函数返回值一致。
def zsq(func):def inner(*args, **kwargs): # 接受随机参数,组为元组和字典print("_"* 30)# print(args, kwargs)res = func(*args, **kwargs) # 打印是要进行拆包的return resreturn inner@zsq
def pnum(num, num2, num3):print(num,num2,num3)return num+num2+num3
@zsq
def pnum2(num):print(num)res1 = pnum(123,222,num3=666)
res2 = pnum2(999)
print(res1)
print(res2)

输出:
在这里插入图片描述

  1. 带参数的装饰器
# 装饰器参数
def getzsq(char):# 装饰器def zsq(func):def inner():print(char * 30)func()return innerreturn zsq@getzsq("-") # 能够改变其中的前置打印参数
def f1():print('666')f1()

输出:
在这里插入图片描述

生成器

概念:
是一个特殊的迭代器(迭代器的抽象层级更高)。所以, 拥有迭代器的特性:惰性计算数据,节省内存;能够记录状态,并通过next0)函数,访问下一个状态;具备可迭代特性。但是,如果打造一个自己的迭代器,比较复杂需要实现很多方法,所以,就有一个更加优雅的方式"生成器”。

创建方式:

  1. 生成器表达式——把列表推导式的[]修改成()
l=(i for i in range(1,10000000) if i% 2 == 0)
print(l)
print(next(l))
print(next(l))
print(l.__next__())

输出:
在这里插入图片描述

  1. 生成器函数——函数中包含yield语句,这个函数的执行结果就是“生成器”(yield,可以去阻断当前的函数执行,然后,当使用next()数,或者,__ next__()都会让函数继续执行,然后,当执行到下一个yield语句的时候,又会被暂停)。
def test():print("xxx")yield 1print("a")yield 2print("b")yield 'c'print("c")yield 4print("d")yield 5print("e")
g= test()
print(g)
print(next(g))
print(next(g))
print(next(g))

输出:
在这里插入图片描述

访问方式:

生成器具备可迭代特性:next()函数等价于生成器__next__()或for in

Send方法:
send方法有一个参数,指定的是上一次被挂起的yield语句的返回值相比于__next__()。可以额外的给yield 语句传值(其中注意第一次调用t.send(None))

def test():# print("xxx")res1=yield 1#"ooo"print(res1)res2 = yield 2print(res2)
g = test()
# print(g.__next__())
# print(g.__next__())
#print(g.send("ooo"))
print(g.send(None))
print(g.send(666))

输出:
1
666
2

关闭生成器:

g.close()
后续如果继续调用,会抛出StopIteration异常提示

def test():print("xxx")yield 1print("a")yield 2print("b")yield 'c'print("c")yield 4print("d")yield 5print("e")
g= test()
print(g)
print(next(g))
print(next(g))
g.close() #!!!会直接跳出
print(next(g))

输出:
在这里插入图片描述
注意:如果碰到return生成器只会遍历一次,会直接终止,抛出StopIteration异常提示。

递归函数

概念:函数A内部,继续调用函数A体现;传递和回归。

# 比如拿阶乘举例子
def jiecheng(n):if n == 1:return 1#n!= 1return n * jiecheng(n-1)
result = jiecheng(4)
print(result)

输出:
24
在这里插入图片描述

函数的作用域

变量的作用域:
指的是变量的作用范围——可操作范围;Python是静态作用域,也就是说在Python中,变量的作用域源于它在代码中的位置;在不同的位置,可能有不同的命名空间。(其中命名空间是 作用域的体现形式;不同的具体的操作范围。)

Python的空间分为:
在这里插入图片描述
在这里插入图片描述

a = 999
def test():# 这里如果,直接使用赋值表达式,赋值给一个变量,其实是代表,定义一个新的变量a = 6print(a)def tes2():nonlocal aa = 77
print(a)
test()
print(a)

输出:
999
6
999

全局改变:

a = 999
def test():# 这里如果,直接使用赋值表达式,赋值给一个变量,其实是代表,定义一个新的变量global aa = 6print(a)
print(a)
test()
print(a)

输出:
999
6
6
在这里插入图片描述

a = 999
def test():# 这里如果,直接使用赋值表达式,赋值给一个变量,其实是代表,定义一个新的变量a = 6print(a)def tes2():nonlocal aa = 77print(locals())print(globals())
# print(a)
test()
# print(a)

输出:
在这里插入图片描述


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

相关文章:

  • SpringColoud GateWay 核心组件
  • java_跳转控制语句break
  • 力扣(leetcode)每日一题 3191 使二进制数组全部等于 1 的最少操作次数 I |贪心
  • px、rem、em等单位的区别
  • 【分布式微服务云原生】《解锁分布式锁的奥秘:由来、场景与技术大揭秘》
  • 晶体与晶振的区别
  • 华为杯”第十三届中国研究生数学建模竞赛-B题:具有遗传性疾病和性状的遗传位点分析(附MATLAB代码实现)
  • 【BGA布局布线-熬夜加班整理】
  • 网络编程基础-IO模型深入理解
  • Python酷库之旅-第三方库Pandas(157)
  • vs code 正则提取文本
  • Xamarin学习计划
  • JVM的基础
  • MyBatis Plus
  • Linux中pip安装python包失败原因是缺少python3-dev
  • C/C++逆向与反汇编01-寻找主函数
  • vue组件调用生命周期
  • [Unity Demo]从零开始制作空洞骑士Hollow Knight第十四集:制作新的场景以及制作创建切换管理系统
  • 详解Shell脚本与Ansible自动化工具差异
  • 为什么你总碰到渣男?伯克森悖论