1.什么是函数

(1)函数就是把完成特定功能的代码封装起来 (代码缩进)

(2)给该功能起一个名字(函数名),哪里需要实现该功能就在哪里调用该函数。

(3)函数可以在任何时间和地方调用

(4)所谓函数,就是把具有独立功能的代码块组织为一个小模块,在需要时调用。

注意:函数名的规范

​ (A)字母、数字,下划线,但不能以数字开头 (B)不能使用关键字或保留字 (C)多个单词使用下划线命名: get_num()

2.函数的定义方式

def 函数名(形参1,形参1...): 函数体

  

 1 def func():
 2     for i in range(3):
 3         print("hello world")
 4  5 func()
 6  7 执行结果:
 8 hello world
 9 hello world
10 hello world

 

提示:定义函数使用def关键字,如果要返回值则可以使用return。如果函数执行完毕后没有使用return返回值,或者使用return结束函数但是没有指定返回值,默认就会返回None

  • def 是定义函数的关键字。

  • 函数名是这个函数的符号,调用这个函数的时候,我们需要函数名。

  • 函数名后的圆括号是必须的

  • 圆括号后面必须有一个分号

3调用函数:

语法:函数名(实参)

  • 定义函数的目的是为了让函数做一些事情,但是函数如果仅仅定义是不会自己去执行

  • 所以时刻记住一句话,函数只有被调用才能被执行!

  • 所以想要函数执行,必须去调用函数。

  • 在使用函数的时候,一定要保证声明在前,调用在后!


#定义函数
def func():
for i in range(10):   #函数体
print("hello world")   #函数体
#函数调用
func()

3.1简单的函数调用

函数调用非常简单,语法: 函数名(实参) 。当然如果函数定义的时候没有形参,则就不用实参。

 1 #定义无参数函数
 2 def show():
 3     print("我是函数内的代码1")
 4     print("我是函数内的代码2")
 5     
 6 #无参数函数调用    
 7 show() 
 8  9 show() #一个函数可以多次调用。每次调用都会执行一次函数体的代码
10 11 执行结果:
12 我是函数内的代码1
13 我是函数内的代码1
14 15 我是函数内的代码1
16 我是函数内的代码1

  

3.2带形参的函数调用

函数声明的时候,在括号内的是形参。

那么在调用函数的时候应该传递相同属性的参数过去,函数调用的时候的参数,叫做实参!

语法:函数名(实参1,实参2,。。。)


#定义带参数的函数
def add(a, b):
print(a + b)
       
#调用时,需传入相同属性数据类型的实参
add(2, 3)
add(20, 3)

执行结果:
5
23

4.函数的作用:

  • 函数是能够完成某一功能的代码段

  • 函数是可重复执行的代码段

  • 函数方便管理和维护,便于复用

5.函数的参数

函数声明的时候,有参数,是希望外界向函数内传递内容,故在括号内的是形参。那么在调用函数的时候应该传递相同属性的真实参数过去,函数调用的时候的参数,叫做实参!

5.1函数参数的分类

5.1.1按照是否是可变类型分:不可变类型 和 可变类型

(1)不可变类型:

值的内容改变,地址也发生改变了

 1 #声明定义函数,传入不可变数据类型
 2 def fun(name):
 3     print("----1111111",id(name))#------------->6430944
 4     if name !="admin":
 5         print("---22222",id(name))#------------>6430944
 6         name="admin123"
 7         print("---33333",id(name))#------------->6424800
 8         
 9 name=ad  
10 print("----4444",id(name))#--------------------->6430944
11 #调用函数     
12 fun(name)
13 print("----5555",id(name))#--------------------->6430944

 

(2)可变类型:

如果传入的是可变类型,比如列表,函数里改变了列表的排序。则会影响到外部变量对应的列表,因为它俩的值地址指向是一样的。值的内容发生改变,但是地址不发生改变.


#定义函数,传入可变数据类型
 1 def fun(l):
 2     print(id(l))#---------------3737920
 3     print(l)#--------------[2,5,1,3,8,7]
 4     l.sort()
 5     print(id(l)))#---------------3737920
 6     print(l)#--------------[1,2,3,5,7,8]
 7     
 8 list1=[2,5,1,3,8,7]
 9 print(id(list1)))#---------------3737920
10 #调用函数,传入实参列表
11 fun(list1)
12 13 print(list1)#--------------[1,2,3,5,7,8]
14 print(id(list1)))#---------------3737920

5.1.2按照参数的类型:默认参数、关键字参数、可变参数

(1)默认值参数

默认值参数:在函数定义的时候,设置的.

  • (A)默认值赋值的时候只要负责默认值前面的赋值

  • (B)不想使用默认的值,则传递一个值(传递的值覆盖原来的了)

  • (C)非默认值的元素必须在默认值的前面,如果在后面则语法错误

  • (D)如果有多个默认值,只想改变其中的某一个,使用:关键字=新值

  • (E)默认值是列表(可变类型),固定不变的地址。该可变的类型就是共享空间。注意:默认值是可变类型的,则在定义的时候,内存地址就固定了。

  • (F)后一个默认值不能引用前一个默认值,如果引用则报错

案例一:默认值赋值的时候只要赋值默认值前面的赋值


#定义一个有默认值参数函数
def func(a,b=5):
   return a+b
#调用函数,如果想使用b默认值,则只需要传入一个实参赋值给a
fun(2)

执行结果:
7

案例二:不想使用默认的值,则传递一个值(传递的值覆盖原来的了)


def func(a,b=5):
return a+b

#调用函数,如果不想使用b默认值,则实参传入一个新值,就会覆盖默认值了
fun(2,10)

执行结果:
12

案例三:非默认值的元素必须在默认值的前面,如果在后面则语法错误


def func(a,b=2,c):
return a+b+c
fun(2,4,5)

执行结果:
SyntaxError:non-default argument follows default argument

案例四:如果有多个默认值,只想改变其中的某一个,使用:关键字=新值


def login(username,password="1234",count=3):
for i in range(count):
       if username="admin" and password="1314":
           print("登录成功!")
           break
  else:
           print("第%d登录失败!"%(i+1))
#调用函数
login("admin",password="1314")

案例五:默认值是列表(可变类型),固定不变的地址。该可变的类型就是共享空间


def func(a,b=[]):
   b.append(a)

fun("马思纯")----->["马思纯"]
fun("周冬雨")----->["马思纯","周冬雨"]
fun("刘若英")----->["马思纯","周冬雨","刘若英"]

案例六:后一个默认值不能引用前一个默认值,如果引用则报错


def func1(x,y=5,z=y):
print(x,y,z)

func1(8)

执行结果:
NameError:name "y" is not defind
(2)关键字参数
  • 关键字参数明确赋值

    ​ 关键字:拿到形参名字,明确的赋值。好处,可以明确赋值,顺序可以对调

     

  • 使用关键字改变默认值


    def func1(x=1,y=2,z=3): #定义默认值
    print(x,y,z)

    func1()

    func1(x=8)=====>关键字改变默认值

     

(3)可变参数

def func(*args,**kwargs)

​ *args :单个元素 "奥特曼"

​ **kwargs:成对出现 name="奥特曼"

在形参前面添加一个 *号, 这样的参数就是可变参数, 可以接受任意多个参数.


def foo(a, *b): # b 就是可变参数, 在函数内部可以作为元组使用
print(a)#------->10
print(b)#------->(20,4,7,9)

foo(10, 20, 4, 7, 9)

解析:
在python解释器中,当遇到函数形参带*时,就会准备一个空元组来装包,实参传入,就装包在一个元组里并赋值给形参带*变量。

在形参前面添加一个 **号, 这样的参数就是可变参数, 可以接受任意多个参数.


def test(**kwargs):
print(type(kwargs),kwargs)

test1()
test1(song1="听海")
test1(name="阿妹",song="听海")

执行结果:
<class 'dict'> {}
<class 'dict'> {'song1': '听海'}
<class 'dict'> {'name': '阿妹', 'song': '听海'}

定义一个万能参数


def funcA(*args,**kwargs):
if len(args)>0:
for i in args:
print("args:---->",i)
if len(kwargs)>0:
for key,value in kwargs.item():
print(key,"--",value)

funcA()
funcA("英雄联盟")
funcA("英雄联盟","绝地求生")
funcA("英雄联盟",player1="faker",player2="小明")

会报错,只要有关键字参数存在以后的参数必须是关键字
funcA(player1="faker","英雄联盟","绝地求生")

*就是一个分隔符,用于分割前面的单个元素和后面的关键字赋值


def func2(a,b,*,age,name):
   print(a)
   print(b)
   print(name)
   print(age)
   
func2(1,2,age=18,name="马思纯")

6.返回值return

  • 只要函数有返回值,则必须接收

  • 在函数里 return 会结束函数,后面的代码不再执行

  • 只能结束循环体,会继续执行下边的代码

提示:参数:外界往里面送值 返回值:函数里面向外界送值


def login(userName,passWord):
if userName=="admin"and passWord=="1234":
print("登录成功!")
return True
else:
print("登录失败!")
       
def pay(money):
   if login():
       print("付款金额为:",money)
       print("正在付款....")
       print("付款成功!")
       

特殊的返回值:可以接收多个返回值


def func ():
a="hello"
b="world"
list1=[1,2,3,4,5]
return a,b,list1

n1,n2,n3=func()
print(n1)
print(n2)
print(n3)

7.递归函数

  函数内部自己调用自己

8.匿名函数

1.什么是匿名函数?

函数没有名称。关键字 lambda 来定义匿名函数。匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果。

匿名函数主要作为参数出现:可参照 sort(key=function)。结合系统函数使用较多

2.匿名函数的定义方式

lambda 形参列表:表达式

例如:f=lambda x:x+1


f=lambda x:x+1
r=f(5)
print(r)

执行结果:
>>>6
定义一个匿名函数的流程:

(1)定义匿名函数lambda表达式 lambda x : x+1

(2)将lambda表达式赋值给一个变量 f=lambda x : x+1

(3)f就是匿名函数,调用:f(实参)

(4)接收f函数调用的结果, result=f(实参)

案例一:求三个数的和


f=lambda x,y,z:x+y+z
result=f(1,2,3)
print(result)

执行结果:
>>>6

案例二:传一个字符串,返回字符串的大写形式


f=lambda s : s.upper()
result=f("abc")
print(result)

执行结果:
>>>ABC

案例三:传一个列表,返回升序结果


f=lambda l : l.sort()
ll=[5,3,1,7,9,0]
f(ll)
print(ll)

执行结果:
>>>[0,1,3,5,7,9]

解析:由于l.sort()没有返回值,是对原列表进行升序操作,所有f就不用接受返回值。

案例四:函数作为参数


def func(f):  #f=lambda x,y:x+y
if callable(f):
result=f(1,4)
print("result",result)
func(lambda x,y:x+y)

执行结果:
>>>5

案例五:按照年纪升序排序


lists=[("梅西",33),("C罗",30),("内马尔",26),("凯恩",28)]
def func2(t):
return t[1]
lists.sort(key=func2)
print(lists)

执行结果:
>>>[("内马尔",26),("凯恩",28),("C罗",30),("梅西",33)]

解析:底层是拿出列表的一个元素给函数的形参t :t=("梅西",33)
return t[1]-------->表示的是扔出来的是一个年龄
key=func2---------->按照关键字func2返回的值进行排序

案例六:利用匿名函数按照年纪升序排列


lists=[("梅西",33),("C罗",30),("内马尔",26),("凯恩",28)]
lists.sort(key=lambda x:x[1])
print(lists)

执行结果:
>>>[("内马尔",26),("凯恩",28),("C罗",30),("梅西",33)]

list2=[{"name":"马思纯""age":30},{"name":""周冬雨,"age":24}]
list2.sort(key=lambda x:x["age"])
print(list2)

执行结果:
>>>[{"name":""周冬雨,"age":24},{"name":"马思纯""age":30}]

9.高阶函数

1.什么是高阶函数

(1)一个可以接收函数作为参数的函数称为高阶函数

(2)函数作为结果返回

案例一:函数作为一个参数传入另一个函数的高阶函数


def func(a,b,f):  ------------>#a=n1 b=n2 f=f1
return f(a)+f(b)  --------> #f1(n1)+f1(n2)
def f1(m):
return m**2
n1=2
n2=4
func(n1,n2,f1)
result=func
print(result)

执行结果:
>>>20

案例二:函数作为结果返回


def outer():
a=100
def inner():
b=80
c=a+b
print(a,b,c)
return inner
f=outer()
result=f()

执行结果:
>>>100  80  180

2.常用的高阶函数

map() filter() reduce()

2.1 map(function,iterable)

map:映射 ------->在built-in function模块中,无需引入,直接可调用

案例一:使一个列表中的每个元素都加2


result=map(lambda a :a+2,[1,2,3,4,5,6])
print(list(result))

执行结果:
>>>[3,4,5,6,7,8]

案例二:使两个列表里的元素相加,得到一个新列表


result=map(lambda a,b:x+y,[2,4,5,7],[1,6,9])
print(list(result))

执行结果:
>>>[3,10,14]

案例三:使一个列表中的字符串元素的首字母都是大写


result=map(lambda s:s.title(),["hello","tom","jack"])
print(list(result))

执行结果:
>>>["Hello","Tom","Jack"]
2.2filter(function,iterable) 过滤

function的返回值必须是布尔类型

案例一:利用filter过滤一组数,得到这组数中的偶数


result=filter(lambda x:x%2==0,(1,2,3,4,5,6,7))
print(list(result))

执行结果:
>>>(2,4,6)

案例二:利用filter过滤一组数据,得到这组中所有的数字


result=filter(lambda x: x.isdigit(),["hello","1","9","tom"])
print(list(result))

执行结果:
>>>[1,9]

案例三:["hello","1","9","tom"]找出里面的非数字元素,并将里面的首字母大写


list1=["hello","1","9","tom"]
result=filter(lambda s:s.isalpha(),list1)
result=map(lambda a:a.title(),list(result))
print(list(result))

执行结果:
>>>["Hello","Tom"]
2.3functools.reduce(function,iteranle[,intializer])

reduce 在functools模块里,所以在引用reduce需要引入functools模块

案例一:对一组数,利用reduce实现累加和


import functools
result=functools.reduce(lambda x,y:x+y,[1,2,3,4])
print(result)

执行结果:
>>>10

解析:reduce 在底层其实是个递归过程,第一次x=1,y=2,结果等于3,赋值给x=3,y再取列表的一个元素,y=3。这时x+y=3+3=6 ,再将结果6赋值给x=6。y再取列表的一个元素,y=4, 此时x+y=10.

案例二:reduce的初始化值


import functools
result=functools.reduce(lambda x,y:x+y,[1,2,3,4,5],5)
print(result)

执行结果:
>>>20

解析:
默认值5,第一次会赋值给x=5,y从列表取一个元素,y=1,此时x+y=6
第二次,x+y=6的结果重新赋值给x=6, y从列表中取一个元素y=2,此时x+y=8
第三次,x+y=8的结果重新赋值给x=8, y从列表中取一个元素y=3,此时x+y=11
以此类推。。。
最终得出结果为20

案例三,利用reduce统计一个字符串里一个字母出现的次数

s="abc hsiue hdui jeda abc wkahd djoad wjdoaj djoad abc wjdoadjam
dao abc wjdai djao dhiaw jad jfp abc"
import functools
result=functools.reduce(lambda x,y:x+y.count("abc"),s.split(),0)
print(result)

执行结果:
>>>5


10.闭包

1.什么是闭包

外层函数+内层函数,并且返回值是内层函数

​ (1)函数里有内层函数

​ (2)将内层函数作为结果返回

案例一:按照闭包的方式完成:外层函数接收一个列表参数,内层函数只对列表中的数字部分进行累加求和


import functools
lists=["aa","3","b","8","5","e"]
def outer(l):
def inner():
result=filter(lambda x:x.isdigit(),l)
new_list=list(result)
result2=functools.reduce(lambda x,y:int(x)+int(y),new_list)
return=result2
return inner
f=outer(list2)
result=f()
print(result)

执行结果:
>>>16

2.闭包参数的几种形式:

(1)外层无参数,内层无参数

(2)外层有参数,内层无参数

(3)外层无参数,内层有参数

(4)外层有参数,内层有参数

(5)外层有返回值,内层有返回值

案例三:外层无参数,内层有参数


def outer():
content=input("请输入姓名")
def inner(number):
for i in range(number):
print("%s说,今天天气真好!"%content)
return inner
f=outer()
f(3)

执行结果:
>>>
请输入姓名:马思纯
"马思纯说,今天天气真好!"
"马思纯说,今天天气真好!"
"马思纯说,今天天气真好!"

案例四:外层有参数,内层有参数


def outer(friend):
name=input("请输入姓名")
def inner(number):
for i in range(number):
print("%s邀请%s一起出去玩!"%(friend,name))
return inner
f=outer("马思纯")
f(3)

执行结果:
请输入姓名:周冬雨
"马思纯邀请周冬雨一起出去玩!"
"马思纯邀请周冬雨一起出去玩!"
"马思纯邀请周冬雨一起出去玩!"

案例五:外层有返回值,内层有返回值


import random
def outer(friend):
name=input("请输入姓名")
def inner(number):
n1=0
n2=0
print("=====%s大战%s====="%(friend,name))
for i in range(number)
ran1=random.randint(1,7)
ran2=random.randint(1,7)
if ran1>ran2:
n1+=1
print("ran1:%d PK ran2%d,此局游戏获胜者是:%s"(ran1,ran2,friend))
elif  ran1==ran2:
print("平局")
else:
n2+=1
print("ran1:%d PK ran2:%d,此局游戏获胜者是:%s"%(ran1,ran2,name))
if n1>n2:
return friend
else:
return name
return inner
f=outer("马思纯")
r=f(3)
print("获胜者是:"r)

执行结果:
请输入姓名:周冬雨
ran1:7 PK ran2:5,此局游戏获胜者是:马思纯
ran1:2 PK ran2:6,此局游戏获胜者是:周冬雨
ran1:6 PK ran2:1,此局游戏获胜者是:马思纯
获胜者是:马思纯

案例六:实现一个简单的计数器


def count_machine(num):
def next():
nonlocal num
temp=num
num+=1
return temp
return next
f=count_machine(0)
while True:
value=f()
print(value)
if value==5:
break

执行结果:
>>>1
>>>2
>>>3
>>>4
>>>5

3.闭包的总结:

  • 闭包优化了变量,原来需要类对象完成的工作,闭包也可以完成。

  • 由于闭包引用了外部函数的局部变量,则外部函数的局部变量没有及时释放,消耗内存

  • 闭包的好处,使代码变得简洁,便于阅读代码。

  • 闭包是理解装饰器的基础

4.三层闭包

4.1什么三层闭包

def a1():
a=100
print("a1函数中打印:",a)
def a2():
b=99
print("a2函数中打印:",a,b)
def a3():
c=88
print("a3函数中打印:",a,b,c)
return a3
return a2
f=a1()  #------>f=a2
f1=f()  #------>f1=a3
f2=f1() #------>a3()

执行结果:
100
100,99
100,99,88