一、函数的概念
1.定义
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
2.作用
函数能提高应用的模块性,和代码的重复利用率
3.定义
函数代码块以 def 关键词开头,后接函数标识符名称和圆括号()。
任何传入参数和自变量必须放在圆括号中间。圆括号之间可以用于定义参数。
函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
函数内容以冒号起始,并且缩进。
return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。
def functionname( parameters ):
"函数_文档字符串"
function_suite
return [expression]
二、参数传递
以下是调用函数时可使用的正式参数类型:
1.位置参数(必备参数)
位置参数须以正确的顺序传入函数。调用时的数量必须和声明时的一样。
def fun3(name,age,score):
print(f"name={name:}\tage={age}\tscore={score}")
fun3(score=98.5,name='梨花',age='8848')
fun3(98.5,'梨花',8848)
fun3('梨花','8848',98.5)
结果
name=梨花 age=8848 score=98.5
name=98.5 age=梨花 score=8848
name=梨花 age=8848 score=98.5
调用该函数,你必须传入一个参数,不然会出现语法错误:
Traceback (most recent call last):
File "test.py", line 11, in <module>
printme()
TypeError: printme() takes exactly 1 argument (0 given)
2.关键字参数
关键字参数:调用函数传递参数时,按照 参数名=值 的方式,传参的顺序可以和定义参数的顺序不一致。
关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。
使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。
下例能将关键字参数顺序不重要展示得更清楚:
def printinfo(name, age):
print("Name: ", name)
print("Age ", age)
return
printinfo(age=50, name="miki")
Name: miki
Age 50
3.默认参数
默认参数:在函数定义时给参数设置默认值,那么在函数调用时,若不传参就是用默认值,若传参就是用传参的值。
下例会打印默认的age,如果age没有被传入:
def printinfo(name, age=35):
print("Name:", name)
print("Age ", age)
return
printinfo(age=50, name="miki")
printinfo(name="miki")
Name: miki
Age 50
Name: miki
Age 35
4.位置不定长参数
位置不定长参数:在定义函数时参数名前加 * ,也就是def fun( *args ),那么在传参的时候就可以传若干个位置参数。
一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数,和上述2种参数不同,声明时不会命名。
将参数打包成——元组。
加了星号(*)的变量名会存放所有未命名的变量参数。不定长参数实例如下:
无法同时使用两个位置不定长参数,只有关键字参数能与不定长参数同时使用
def fun5(*num,a,b):
print(f"num={num}\ta={a}\tb={b}")
fun5('1',3,4,5,[1,2,34,"rev"],a="我是关键字参数a",b="我是关键字参数b")
num=('1', 3, 4, 5, [1, 2, 34, 'rev']) a=我是关键字参数a b=我是关键字参数b
5.关键字不定长参数
关键字不定长参数:在定义函数参数名前加 ** ,也就是 def fun( **kwargs ),那么传参的时候就可以传若干个 关键字参数。
将参数打包成——字典。
def fun7(**kwargs):
print(kwargs)
fun7(姓名='张三',学号='10086',成绩=97.5)
d1 = dict(姓名='张三',学号='10086',成绩=97.5)
print(d1)
{'姓名': '张三', '学号': '10086', '成绩': 97.5}
{'姓名': '张三', '学号': '10086', '成绩': 97.5}
6.形参与实参
实参(argument)——全称为"实际参数"是在调用时传递给函数的参数。 实参可以是常量、变量、表达式、函数等, 无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值, 以便把这些值传送给形参。 因此应预先用赋值,输入等办法使实参获得确定值
形参(parameter)——全称为"形式参数" 由于它不是实际存在变量,所以又称虚拟变量。是在定义函数名和函数体的时候使用的参数,目的是用来接收调用该函数时传入的参数.在调用函数时,实参将赋值给形参。因而,必须注意实参的个数,类型应与形参一一对应,并且实参必须要有确定的值。
形参出现在函数定义中,在整个函数体内都可以使用, 离开该函数则不能使用。实参出现在主调函数中,进入被调函数后,实参变量也不能使用。形参和实参的功能是作数据传送。
1、参变量只有在被调用时才分配内存单元,在调用结束时, 即刻释放所分配的内存单元。因此,形参只有在函数内部有效。 函数调用结束返回主调函数后则不能再使用该形参变量。
2、实参可以是常量、变量、表达式、函数等, 无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值, 以便把这些值传送给形参。 因此应预先用赋值,输入等办法使实参获得确定值。
3、实参和形参在数量上,类型上,顺序上应严格一致, 否则会发生“类型不匹配”的错误。
4、函数调用中发生的数据传送是单向的。 即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。 因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化
三、函数的返回值
1.定义
函数需要先定义后调用,函数体中 return 语句的结果就是返回值。如果一个函数没有 reutrn 语句,其实它有一个隐含的 return 语句,返回值是 None,类型也是 'NoneType'。
2.return 语句的作用
结束函数调用、返回值
3.指定返回值与隐含返回值
指定 return 返回值函数举例
def showplus(x):
print(x)
return x + 1
num = showplus(6)
add = num + 2
print(add)
6
9
隐含 return None 举例:
def showplus(x):
print(x)
num = showplus(6)
print(num)
print(type(num))
6
None
<class 'NoneType'>
4.return 语句位置与多条 return 语句
python 函数使用 return 语句返回 "返回值",可以将其赋给其它变量作其它的用处;
所有函数都有返回值,如果没有 return 语句,会隐式地调用 return None 作为返回值;
一个函数可以存在多条 return 语句,但只有一条可以被执行,如果没有一条 reutrn 语句被执行,同样会隐式调用 return None 作为返回值;
如果有必要,可以显式调用 return None 明确返回一个None(空值对象)作为返回值,可以简写为 return,不过 python 中懒惰即美德,所以一般能不写就不写;
如果函数执行了 return 语句,函数会立刻返回,结束调用,return 之后的其它语句都不会被执行了
def showplus(x):
print(x)
return x + 1,x
print(x + 1) #该语句会执行么
print(showplus(6),type(showplus(6)))
6
6
(7, 6) <class 'tuple'>
5.返回值类型
无论定义的是返回什么类型,return 只能返回单值,但值可以存在多个元素;
return [1,3,5] 是指返回一个列表,是一个列表对象,1,3,5 分别是这个列表的元素;
return 1,3,5 看似返回多个值,隐式地被Python封装成了一个元祖返回
6.函数嵌套
函数有可见范围(内外可见关系),这就是作用域的概念;
内部函数不能被外部直接调用,会抛异常 NameError
def outer():
def inner():
print("inner")
print("outer")
outer()
outer
此时如果调用 outer(),只会执行 print("outer"),因为 inner 虽然在 outer 函数内,但它也是一个函数,函数如果要调用,就必须用 '函数名()' 方式。
def outer():
def inner():
print("inner")
print("outer")
inner()
outer()
outer
inner
四、递归函数
1.定义
递归函数是一种在其定义中调用自身的函数。在Python中,递归函数可以用来解决那些可以分解为更小相似问题的任务。递归函数的核心在于定义一个明确的结束条件,避免无限递归导致栈溢出。
2.结构
递归函数通常包含三个基本部分:
- 边界条件/基线条件 跳出/结束递归的条件
- 递归返回段 满足结束条件时,返回
- 递归前进段 不满足结束条件时,前进/继续递归
3.优缺点
递归函数的优点在于其定义简单,逻辑清晰。对于某些问题,递归解决方案比非递归解决方案更容易理解和实现。然而,递归函数也有其缺点,包括可能的低效率和栈溢出风险。在Python中,递归深度有限制,通常为1000层,超过这个限制会引发RecursionError。
五、函数中变量的作用域
变量的作用域:是指变量能起作用的范围,根据作用范围大小不同分为全局变量和局部变量。
- 全局变量:定义在函数外,作用范围是整个程序,程序结束时全局变量声明周期结束。
- 局部变量:定义在函数代码块里或者函数的参数里,作用范围是整个函数,函数执行结束时局部变量生命周期结束。
1.作用域的必要性
为啥变量要有作用域呢?
在Python里遇到的内置、局部、全局及自由变量,就是说变量的作用域。
语言区分作用域,是为了复用变量名。引入作用域,相当于给变量划分了各自的“隔离区”,在不同”隔离区“里,查找变量变得很容易。
正是因为有了作用域,我们在函数内才可以随意使用变量名,而不担心其与全局变量、其他函数中的变量冲突——因为这两个作用域是分割的。
2.LEGB规则
在本地空间寻找不到的变量,逐级向上级寻找。
里的LEGB分别指代Local,Enclose,Global和Builtin。
在函数中读取和赋值全局变量,在内嵌函数中读取和赋值自由变量,会有一些不同的地方。
3. nonlocal 和 global
为了解决局部作用域中赋值全局变量和自由变量导致的变成局部变量问题,Python引入关键字 global
和 nonlocal
。
global
x = '我是函数外的x'
def out_fun():
global x
x = '我是外函数的x'
def in_fun():
global x
x = '我是内函数的x'
print(x)
in_fun()
print(x)
out_fun()
print(x)
我是内函数的x
我是内函数的x
我是内函数的x
x = '我是函数外的x'
def out_fun():
# global x
x = '我是外函数的x'
def in_fun():
# global x
x = '我是内函数的x'
print(x)
in_fun()
print(x)
out_fun()
print(x)
我是内函数的x
我是外函数的x
我是函数外的x
在嵌套函数中,如果需要修改外部函数的变量,可以使用 nonlocal
关键字。 nonlocal:
def out_fun():
x = 111
def in_fun():
nonlocal x
x = '我是内函数的x'
print(x)
in_fun()
print(x)
out_fun()
我是内函数的x
我是内函数的x
六、函数嵌套
函数嵌套允许我们在一个函数内部定义另一个函数,这个内部定义的函数被称为内函数,而包含它的函数被称为外函数。内函数可以访问外函数的变量,这种行为称为作用域链。函数嵌套的优点
定义:
在一个函数的内部 还嵌套定义了 另外一个函数。
外部的我们称之为 外函数,内部的我们称之为 内函数。
def out_fun():
print("我是外函数")
def in_fun():
print("我是内函数")
return in_fun()
out_fun()
函数嵌套的优点
-
封装:内函数可以作为数据隐藏的一种方式,它不会被外部作用域直接访问。
-
DRY原则:不重复自己。如果多个函数需要执行相似的操作,可以将这些操作封装在一个内函数中,避免代码重复。
-
闭包:通过闭包,可以维持函数的状态,使得函数可以记住某些值,而不需要使用全局变量。
函数嵌套的缺点
-
作用域混乱:如果嵌套过多,可能会导致作用域链混乱,难以追踪变量的来源。
-
性能问题:每次外函数执行时,都会创建一个新的内函数实例,如果不断地调用外函数,可能会导致性能问题。
七、闭包
闭包是一种特殊的函数嵌套,其中内函数引用了外函数的变量,即使外函数的执行已经结束,这些变量仍然可以被内函数访问。闭包常用于创建只有内函数可以访问的私有变量。
def out_fun():
print("我是外函数")
def in_fun():
print("我是内函数")
return in_fun
out_fun()()
我是外函数
我是内函数
定义
什么是闭包函数?——如果内函数中使用了外函数的局部变量,并且外函数把内函数返回的过程就叫闭包。
形成闭包的条件:
- 函数嵌套
- 将内函数作为返回值返回
- 内函数必须使用外函数的局部变量
作用域:
def outer():
a=1
print('我是外层函数')
def inner():
a=10
print('我是内层函数')
print('内层函数打印',a)
return inner #
f=outer()
f()
在内层函数中又有a=10,此时并不是改变的外层函数中的a,而是在内层函数中定义的新变量,是两个不同的东西。从结果也能看出来。这就是作用域的问题。
内层函数中调用的变量首先会从内层函数中找,找不到就去外层函数中找,再找不到就到函数外代码中找,再找不到就到内置的模块中找,最后还是找不到,就报错。
在内层函数中修改外层函数中的变量
在内层函数中修改外部函数中的变量a,此时会报错中的变量冲突——因为这两个作用域是分割的。
def outer():
a=1
print('我是外层函数')
def inner():
a+=10
print('我是内层函数')
print('内层函数打印',a)
return inner
f=outer()
f()
我是外层函数
Traceback (most recent call last):
File "C:\Users\31284\OneDrive\Desktop\PYTHON\day6\1.py", line 355, in <module>
f()
File "C:\Users\31284\OneDrive\Desktop\PYTHON\day6\1.py", line 350, in inner
a+=10
^
UnboundLocalError: cannot access local variable 'a' where it is not associated with a value
如果想修改外部函数中的变量,必须加一个nonlocal的声明,修改如下。这和在函数中修改全局变量,加global 有异曲同工之妙
def outer():
a=1
print('我是外层函数')
def inner():
nonlocal a
a+=10
print('我是内层函数')
print('内层函数打印',a)
return inner
f=outer()
f()
我是外层函数
我是内层函数
内层函数打印 11
标签:fun,return,函数,--,python,007,print,参数,def
From: https://blog.csdn.net/Z211613347/article/details/143633143