Jay jay
文章28
标签2
分类0
python学习之函数

python学习之函数

函数定义

函数:完成特定功能的一个语句组,通过调用函数名来完成语句组的功能,可以反馈结果,提供不 同的参数实现对不同数据的处理。

自定义函数由用户自己编写,系统自带函数有python中内嵌的函数和标准库函数

使用函数的目的:降低编程难度,代码重用。

函数定义语句:

  1. 函数关键字:函数以关键字def开头,后接函数名和圆括号()
  2. 函数名:必循遵循标识符的命名规则,最好有意义增加可读性
  3. 参数:必须放在圆括号中间,成为形式参数(形参),形参是可选的,可以有一个也可以有多个,多个参数间用‘,’分隔
  4. 函数说明:函数第一行的语句可以选择性地使用文档字符串,用于存放函数说明
  5. 函数内容:以冒号起始并且缩进
  6. 返回值:使用“return [表达式]”结束函数,返回一个值给调用方,若没有renturn返回值则默认返回None,当函数返回多个值时其本质是把这些值作为一个元组返回。
  7. 函数体:当函数体为pass语句,表示什么工作也不做,如抽象类中的抽象函数
def 函数名([参数1,参数2,...]):
"""函数说明"""
函数体

以sum函数定义为例

例子:

def myHello():
return "hello,everone!"

函数有自己的成员,也可以为函数动态增减删除成员,在函数外部删除函数内部定义成员是无效的。

函数调用:

函数调用时需要指出函数名称,并传入相应的函数调用时传入的参数称实参,默认情况下传入的实参必须等于定义时形参个数,顺序一制

函数调用顺序:

  1. 执行函数调用前语句
  2. 执行函数调用,运行被调用函数内语句,并返回结果
  3. 执行函数调用后的语句

函数调用的两种方法:

  1. 调用函数传入实参
  2. 把函数对象赋给变量

以sum函数调用为例

定义一个求梯形面积函数并调用

#求梯形面积
def echelonArra(top,bottom,height):
area=1 / 2 * (top+bottom) *height
return area
if __name__ == '__main__':
t=3.6;b=6.2;h=4.5
area1=echelonArra(t,b,h) #第一种调用
print("area1=",area1)
area2=echelonArra
print("area2=",area2(t,b,h)) #第二种调用

结果

函数参数传递

python中的对象分为不可变对象(数字、字符串、元组)和可变对象(列表、字典、集合)

  1. 实参为不可变对象,函数调用时将实参的值复制一份给形参,在函数调用中修改形参时不会影响函数外面的实参
  2. 实参为可变对象,函数调用时将实参引用复制给形参,在函数调用中修改形参时会影响函数外面的实参

实参为不可变对象调用:

def Swap(x,y):
print("交换前:x={},y={}".format(x,y))
x,y=y,x
print("交换后:x={},y={}".format(x,y))

if __name__ == '__main__':
a=6;b=5
Swap(a,b)
print("a={},b={}".format(a,b))

实参为可变对象调用:

def changeList(myList):
myList.append(4)

if __name__ == '__main__':
list=[1,2,3]
print("调用前list:",list)
changeList(list)
print("调用后list:",list)

参数类型

必须参数

要求调用时传入的实参个数、顺序和函数定义时形参的个数、顺序完全一致

def myAdd(x,y,z):
return x+y+z
a=1;b=2;c=3
print("结果:",myAdd(a,b,c))

关键字参数

在函数调用时使用形参作为关键字来确定传入的参数值,允许函数调用时实参的顺序与函数定义时形参的顺序不一致

def stuInfo(sno,sname):
return "学号:"+sno+"\n"+"姓名:"+sname

print(stuInfo(sname="假的",sno="66666"))

默认参数

调用函数时,如果没有传递实参,则会使用函数定义时赋予的参数的默认值

def stuInfo1(sno,sname,age=18):
return "学号:"+sno+"\n"+"姓名:"+sname+"\n"+str(age)

print(stuInfo1(sname="假的",sno="66666"))
print(stuInfo1(sname="假的",sno="66666",age=25))

不定长参数

在实际使用中有可能需要一个函数能处理比当初声明时更多的参数,这种参数成为不定长参数

两种形式:

  • *args:将接受的多个参数放在一个元组中
  • **args:将显示赋值的多个参数放入字典中
def addFunc(x,y,*args):
res=x+y
for k in args:
res +=k
return res

def func(**args):
for key,value in args.items():
print("{},{}".format(key,value))

if __name__ == '__main__':
print("调用结果:",addFunc(1,2,3,4,5))
func(新发明1="高铁",新发明2="扫码支付")

参数传递的序列解包

参数传递的序列解包针对的是实参,有*或**两种形式,加了后会将列表、元组、字典等迭代对象中的元素分别传递给形参中的多个变量

将列表、元组、字典中的值分别迭代取出赋值给形参

特殊函数

1、匿名函数

​ 匿名函数是指没有函数名的简单函数,只可以包含一个表达式,不允许包含其他复杂语句,表达式的结果就是函数的返回值

​ 一般格式:

lambda [arg1[,arg2,...,argn]]:expression

arg1,arg2,…:形参,可以没有,可以有一个或多个

expression:表达式

默认情况下调用匿名函数时传入实参个数与顺序同样要和匿名函数定义时形参个数顺序一致

map()会根据提供的函数对指定序列做映射。

第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表。

2、递归函数

​ 如果一个函数在函数体中直接或间接的调用自身,那么这个函数就是递归函数,在执行的过程中可能会返回以再次调用该函数

​ 函数a调用函数a自身为直接递归,函数a调用b,函数b在函数体中调用a则称简介递归

  • ​ 递归函数求前n项的和:

    #递归求前n项的和
    def fac(n):
    if n==1:
    return 1
    else:
    return fac(n-1)+n
    if __name__ == '__main__':
    print("前{}项的和为:{}".format(9,fac(9)))

    在递归时需要注意的两点:
    1、递归函数就是在函数里调用自身
    2、递归函数必须有一个明确的递归结束条件,称递归出口,否则造成死循环
    3、前n-1项的和再加第n项,当n=1时为递归出口返回一
  • 使用递归求斐波那契数列前20项和

#递归求斐波那契数列20项的和
def fib(n):
if n==1 or n==2:
return 1
else:
return fib(n-1)+fib(n-2)
if __name__ == '__main__':
#求前20项:
sum=0
for i in range(1,21):
sum=sum+fib(20)
print("前20项的和为{}".format(sum))

递归函数的优点:
1、递归函数使代码看起来更整洁优雅
2、可以用递归将复杂任务分解成更简单的子问题
3、使用递归比使用一些嵌套迭代更容易
递归函数缺点:
1、递归逻辑很难调试跟进
2、递归调用的代价高效率低,占用了大量的内存和时间
递归层数太多时不适合使用递归函数完成程序

3、嵌套函数

​ 嵌套函数是指在一个函数(外函数)中定义了另一个函数(内函数),称为内函数,嵌套函数中的内函数只能在外函数中调用,不能在外函数外面直接调用

#嵌套函数
def outfunc():
def infunc():
print("我是内函数")
print("我是外函数")
infunc()

def outerFunc(x):
def innerFunc(y):
return x+y;
return innerFunc #调用内函数

if __name__ == '__main__':
outfunc()
# infunc() #此句报红内函数在外部不可见出现语法错误

print("方法一调用结果:",outerFunc(3)(4)) #调用时参数从最外层开始传递(最外层层参数)(内层参数)
wai=outerFunc(3) #调用外函数,传递外函数参数
print("方法二调用结果",wai(4)) #间接调用内函数传递参数

4、装饰器

​ 装饰器是python中的一个比较特殊的功能,是用来包装函数的函数,装饰器可以是程序代码更简洁

使用的情况:

  • 将多个函数中的重复代码拿出来整理成一个装饰器,对每个函数使用装饰器,从而实现代码的重用
  • 对多个函数的共同功能进行处理

定义装饰器的一般格式:

def decorator(func):
pass
@decorator
def func():
pass

其中decorator为装饰器。@decorator为函数装饰器的修饰符。func为装饰器的函数对象参数,装饰器可以返回一个值、一个函数、一个装饰器或其他对象

如:

# 装饰器
def decorator(func):
print("I am in deco.")
func()
return "deco return value."

@decorator
def funca():
print("I am in func!")
print(funca)

执行原理:
1、装饰器deco()的参数为一个函数对象func
2、在函数前使用@deco修饰相当于将函数对象func作为参数调用装饰器deco(func)
3、func的值为调用装饰器deco(func)返回的结果

使用装饰器修改网页文本格式:

def deco(f):
def modify_text(str):
return "<string>"+f(str)+"</string>"
return modify_text

@deco
def texfun(str):
return str

if __name__ == '__main__':
print(texfun("text"))

5、带参数的装饰器

​ 装饰器除了默认函数对象参数还可以定义带参数的装饰器,带来更多的灵活性

def DECO(args):
def deco(func):
def call_func(x,y):
print("%d %s %d="%(x,args,y),end=' ')
return func(x,y)
return call_func
return deco

@DECO('&')
def andfunc(x,y):
return x&y

@DECO('|')
def orfunc(x,y):
return x|y

if __name__ == '__main__':
print(andfunc(5,6))
print(orfunc(5,6))

若一个函数有多个装饰器装饰,则称为多重装饰器,多重装饰器的执行顺序是:先执行后面的装饰器,在执行前面的装饰器。

变量作用域

python中不同位置定义的变量决定了这个变量的访问权限和作用范围:

  • 局部变量和局部作用域L(Local):包含在def关键字定义的语句块中即函数中定义的变量,局部变量在函数结束就消失了,调用时创建新的,结束时消失
  • 全局变量和全局作用域G(Global):在模块的函数外定义的变量,在模块顶层声明的变量具有全局作用域,从外部看全局变量是模块对象的属性,全局作用域的作用仅限于单个模块文件内
  • 闭包变量和闭包作用域E(Enclosing):定义在嵌套函数的外函数内、内函数外的变量,闭包变量作用域为嵌套函数内定义它的位置开始的整个函数内
  • 内建变量和内建作用域B(Built-in):系统内固定模块里定义的变量一般预定义在内建模块内的变量

按照L→E→G→B的顺序查找,局部变量和全局变量使用的多,内建变量使用的最少

局部变量只能在其声明的函数内使用,全局变量在整个模块内访问

修改变量作用域的关键字:

  1. global:加上global即可将变量设置为全局变量
  2. nonlocal:加上即可将嵌套函数中的内函数局部变量变为闭包变量

结束

本文作者:Jay jay
本文链接:https://yyj-xx.github.io/2021/09/24/python%E5%AD%A6%E4%B9%A0%E4%B9%8B%E5%87%BD%E6%95%B0/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可