函数简介
函数也是一个对象 函数用来保存一些可执行的代码,并且可以在需要时,对这些语句进行多次调用
语法
def 函数名( [ 形参1 , 形参2 , 形参3 . . . . ] ) :
代码块
注意: 函数名必须符合标识符的规范(可以包含字母、数字、下划线但是不能以数字开头) print是函数对象 print()是调用函数
函数的参数
1. 形参和实参
形参(形式参数) 定义形参就相当于在函数内部声明了变量,但是并不是赋值 实参(实际参数)指定了形参,那么在调用函数时必须传递实参,实参将会赋值给对应的形参,简单来说有几个形参就要有几个实参
def fun ( a, b) :
print ( a, b)
fun( 1 , 2 )
定义形参时,可以为形参指定默认值。指定了默认值以后,如果用户传递了参数则默认值不会生效。如- - 果用户没有传递,则默认值就会生效
def fun ( a, b= 2 , c= 3 ) :
print ( a, b, c)
fun( 3 , 4 )
位置参数:位置参数就是将对应位置的实参赋值给对应位置的形参 关键字参数 : 关键字参数可以不按照形参定义的顺序去传递,而根据参数名进行传递 混合使用位置参数和关键字参数的时候必须将位置参数写到关键字参数前面去
def fun ( a, c, b) :
print ( a)
print ( b)
print ( c)
fun( 1 , 3 , b= 2 )
2. 函数的传递方式
定义形参时,可以为形参指定默认值。指定了默认值以后,如果用户传递了参数则默认值不会生效。如果用户没有传递,则默认值就会生效 位置参数:位置参数就是将对应位置的实参赋值给对应位置的形参 关键字参数 : 关键字参数可以不按照形参定义的顺序去传递,而根据参数名进行传递 混合使用位置参数和关键字参数的时候必须将位置参数写到关键字参数前面去
def fun1 ( a, b= 3 , c= 6 ) :
print ( a, b, c)
fun1( 1 , 4 )
def fun1 ( a, b= 3 , c= 6 ) :
print ( a, b, c)
fun1( 1 , b= 4 )
3. 不定长参数
定义函数时,可以在形参前面加一个*,这样这个形参可以获取到所有的实参,它会将所有的实参保存到一个元组中 带*号的形参只能有一个,可以和其他参数配合使用 *形参只能接受位置参数,不能接受关键字参数
def fun ( c, * a, d) :
print ( a)
r= 0
for i in a:
r+= i
print ( r)
fun( 1 , 3 , 4 , d= 2 )
**形参可以接收其他的关键字参数,它会将这些参数统一保存到字典当中。字典的key就是参数的名字,字典的value就是参数的值 **形参只有一个,并且必须写在所有参数的后面
def fun1 ( * g, ** e) :
print ( g)
print ( e)
fun1( 1 , 2 , a= 1 , b= 2 , c= 3 , d= 4 , h= 1 )
4. 参数的解包
传递实参时,也可以在序列类型的参数前添加星号,这样它会自动的将序列中元素依次作为参数传递 要求序列中的元素的个数必须和形参的个数一致
def fun1 ( a, b, c) :
print ( a, b, c)
dict1= { 'a' : 1 , 'b' : 2 , 'c' : 3 }
fun1( ** dict1)
函数的返回值
返回值就是函数执行以后返回的结果 通过return来指定函数的返回值 return后面可以跟任意对象,返回值甚至可以是一个函数
def fun ( * a) :
r = 0
for i in a:
r += i
print ( r)
return a
res= fun( 1 + 2 , 3 )
print ( res)
文档字符串
help()是Python中内置函数,通过help()函数可以查询Python中函数的用法 在定义函数时,可以在函数内部编写文档字符串,文档字符串就是对函数的说明
1 . 保留文本的格式
2 . 作为一个多行注释
'' '
def fun ( a, b) :
"""
:param a:
:param b:
:return:
"""
help ( print )
help ( input )
help ( fun)
函数的作用域
作用域(scope) 作用域指的是变量生效的区域 在Python中一共有两种作用域
全局作用域 全局作用域在程序执行时创建,在程序执行结束时销毁 所有函数以外的区域都是全局作用域 在全局作用域中定义的变量,都是全局变量,全局变量可以在程序的任意位置进行访问 函数作用域 函数作用域在函数调用时创建,在调用结束时销毁 函数每调用一次就会产生一个新的函数作用域 在函数作用域中定义的变量,都是局部变量,它只能在函数内部被访问
a= 1
def fun ( ) :
global a
a= 10
print ( a)
def fun1 ( ) :
print ( a)
fun1( )
fun( )
print ( a)
高阶函数
接收函数作为参数,或者将函数作为返回值返回的函数就是高阶函数
def fun2 ( i) :
if i % 2 == 0 :
return True
def fun ( fun2) :
list1 = [ ]
for i in range ( 101 ) :
if fun2( i) :
list1. append( i)
return list1
res= fun( fun2)
print ( res)
递归函数
递归是解决问题的一种方式,它的整体思想,是将一个大问题分解为一个个的小问题,直到问题无法分解时,在去解决问题 递归式函数有2个条件
基线条件 问题可以被分解为最小问题,当满足基线条件时,递归就不执行了 递归条件 可以将问题继续分解的条件
n= 1
for i in range ( 1 , 11 ) :
n= n* i
print ( n)
def fun ( n) :
r= 1
for i in range ( 1 , n+ 1 ) :
r= r* i
return r
print ( fun( 10 ) )
def fun ( m, n) :
if n== 1 :
return m
return m* fun( m, n- 1 )
print ( fun( 10 , 5 ) )
闭包
将函数作为返回值也是高阶函数我们也称为闭包 闭包的好处
通过闭包可以创建一些只有当前函数能访问的变量 可以将一些私有数据藏到闭包中 行成闭包的条件
函数嵌套 将内部函数作为返回值返回 内部函数必须要使用到外部函数的变量
def fun_out ( num1) :
def fun_inner ( num2) :
nonlocal num1
num1 = 10
res = num1 + num2
return res
print ( num1)
fun_inner( 1 )
print ( num1)
return fun_inner
f = fun_out( 1 )
print ( f( 2 ) )
匿名函数
匿名函数的特点
使用lambda关键字创建匿名函数。 所谓匿名函数,就是没有名字的函数。 匿名函数冒号后面的表达式有且只能有一个,注意:是表达式,而不是语句。 匿名函数自带return,而return的结果就是表达式的计算后的结果。
匿名函数的语法
print ( ( lambda a, b: a + b) ( 1 , 2 ) )
装饰器
装饰器的引入
我们可以直接通过修改函数中的代码来完成需求,但是会产生以下一些问题
如果修改的函数多,修改起来会比较麻烦 不方便后期的维护 这样做会违反开闭原则(ocp)
程序的设计,要求开发对程序的扩展,要关闭对程序的修改
装饰器的使用
通过装饰器,可以在不修改原来函数的情况下来对函数进行扩展 在开发中,我们都是通过装饰器来扩展函数的功能的
def old_fun ( fn) :
def new_fun ( * args, ** kwargs) :
print ( '函数开始执行' )
print ( fn( * args, ** kwargs) )
print ( '函数执行结束' )
return new_fun
def fun ( a, b) :
return a+ b
r= old_fun( fun)
r( 1 , 2 )
def old_fun ( fn) :
def new_fun ( * args, ** kwargs) :
print ( '函数开始执行' )
print ( fn( * args, ** kwargs) )
print ( '函数执行结束' )
return new_fun
@old_fun
def fun ( a, b) :
return a+ b
fun( 1 , 2 )
Homework
1.打印名片程序:输入姓名,电话号码,性别,最后打印出来名片
控制姓名长度为6-20 电话号码长度11 性别只能允许输入男或女 每一样信息不允许为空
while True :
name= input ( '请输入姓名' )
if len ( name) < 6 or len ( name) > 20 :
print ( '输入的姓名不对,请重新输入' )
continue
tel= input ( '请输入电话号码' )
if len ( tel) != 11 :
print ( '你输入的电话号码不对,请重新输入' )
continue
gender= input ( '请输入性别,男或女' )
if gender!= '男' and gender!= '女' :
print ( '性别不对请重新输入' )
continue
break
def Card ( name, tel, gender) :
print ( '''
**************************
姓名: {}
手机号: {}
性别: {}
--------------------------
''' . format ( name, tel, gender) )
Card( name, tel, gender)
2.使用函数求前20个斐波那契数列斐波那契数列:1,1,2,3,5,8,13,21…即: 起始两项均为1,此后的项分别为前两项之和
def feibo ( num) :
a, b= 1 , 1
list1= [ ]
for i in range ( num) :
if i< 0 :
list1. append( a)
elif i> 0 :
a, b= b, a+ b
list1. append( a)
print ( list1)
feibo( 20 )
3.用函数实现一个判断用户输入的年份是否是闰年的程序
能被400整除的年份 能被4整除,但是不能被100整除的年份 以上2种方法满足一种即为闰年
def main ( ) :
year= int ( input ( '请输入一个年份' ) )
if year % 400 == 0 :
print ( year, '是一个闰年' )
elif year % 4 == 0 and year % 100 != 0 :
print ( year, '是一个闰年' )
else :
print ( year, '不是一个闰年' )
main( )
4.猴子吃桃问题(递归): 猴子第一天摘下若干个桃子,当即吃了一半,还不瘾,又多吃了一个。第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩的一半零一个。到第10天早上想再吃时,见只剩下一个桃子了,求第一天共摘了多少桃子?
# 思路分析:
# 总共有f(1)个桃子,每天吃一半后再吃一个,第十天剩余一个
# 第一天桃子数f(1),第二天f(2)=f(1)/2-1,第三天f(3)=f(2)/2-1.......f(n+1)=f(n)/2-1,当n=10时 f(10)=f(9)/2-1=1
#则可以推导出f(n)=(f(n+1)+1)/2,使用递归函数求出总数
def fun(n):
if n<1 or n>10:
print('天数必须为1至10请重新输入')
else:
if n==10:
return 1
return (fun(n+1)+1)*2
res=fun(2)
print(res)