# 函数(2)
## 1.函数类型
函数也是一种类型,我们自定义的函数就是函数对象,函数名保存了函数对象的引用(地址)
```
def test():
print('我是测试函数')
print(test) #函数名是变量,指向了函数对象
pf = test #pf变量也指向了函数对象,所以也可以通过pf调用test函数
pf()
```
## 2. 匿名函数
不再使用def 函数名()这种形式定义函数,而是使用lambda来创建匿名函数
特点:
- lambda只是一个表达式,函数体比def简单的多
- lambda的函数体不再是代码块
- lambda只有一行,增加运行效率
语法:
```
lambda [arg1,arg2....argn]:表达式
add = lambda a,b:a + b
print(add(3,5))
```
## 3.传入函数
一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数,也可以称之为传入函数。可以实现通用编程,排序等复杂功能
~~~
#传入函数,高阶函数
#能被2整除数的和
def sum_even(n):
sum = 0
for i in range(1,n+1):
if i % 2 == 0:
sum += i
return sum
#能被7整除的数的和
def sum_seven(n):
sum = 0
for i in range(1,n+1):
if i % 7 == 0:
sum += i
return sum
#能被3和5整除,但不能7整除的数的和
def sum_fifteen(n):
sum = 0
for i in range(1,n+1):
if i % 15 == 0 and i % 7 != 0:
sum += i
return sum
#通用求和函数
def sum1(n,callback):
'''
功能:求满足callback规定条件的数的和
:param n: 大于0的整数
:param callback: 用于判断一个数是否满足指定条件,由调用者传入,有一个参数,形如:def callback(n)
:return: 求和的结果
'''
sum = 0
for i in range(1,n+1):
if callback(i):
sum += i
return sum
print(sum1(100,lambda x:x%2==0))
print(sum1(100,lambda x:x%7==0))
print(sum1(100,lambda x:x%15==0 and x % 7 != 0))
~~~
## 4.闭包
我们可以在一个函数中再定义一个函数,在函数内部定义的函数称之为***内部函数***,内部函数只能在函数内使用,不会污染外部空间。定义内部函数的函数称之为***外部函数***,这样的定义构成函数的嵌套
~~~
def outter(a): #外部函数
x = 10
def inner(y): #内部函数
print(x + y)
inner(a)
outter(20)
~~~
- 内部函数只能在外部函数里调用,外界无法直接调用内部函数
在一个外部函数中定义了一个内部函数,内部函数里引用了外部函数的变量,并且外部函数的返回值是内函数的引用。这样内部函数和其执行所需的环境变量就构成了一个***闭包***。
一般情况下,如果一个函数结束,函数的内部所有东西都会释放掉,局部变量都会消失。但是闭包是一种特殊情况,如果外函数在结束的时候发现有自己的局部变量将来会在内部函数中用到,就把这个局部变量绑定给了内部函数,然后自己再结束。
~~~
def outter(a): #外部函数
x = a
def inner(y): #内部函数
return x + y #引用外部变量
return inner #返回内部函数(闭包)
pf = outter(20)
print(pf(10)) #30
print(pf(20)) #40
~~~
在闭包中无法直接修改外部变量x的值
~~~
def outter(a): #外部函数
x = a
def inner(y): #内部函数
# x += 10 #UnboundLocalError: local variable 'x' referenced before assignment
return x + y
return inner
~~~
在python3中可以通过nonlocal关键字声明一下x,表示这个变量不是局部变量,需要向上一层变量空间找这个变量。
~~~
def outter(a): #外部函数
x = a
def inner(y): #内部函数
nonlocal x
x += 10
return x + y
return inner
~~~
## 5.偏函数
当一个函数有大量参数,调用的时候非常不方便,可以使用偏函数技术,将一些参数固定(给默认值),达到简化函数调用的目的。
~~~
import functools
def test(a,b,c,d):
print(a, b, c, d)
#从前面固定参数,使用位置参数就行,1=>a,2=>b
test1 = functools.partial(test,1,2)
test1(3,4) #3=>c 4=>d
#从后面固定参数,需要使用关键字参数
test2 = functools.partial(test,c=3,d=4)
test2(1,2) #1=>a 2=>b
#如果固定的参数不连续,则需使用关键字参数固定
test3 = functools.partial(test,b=2,d=4)
test3(a=1,c=3) #需要使用关键字参数,否则会报错
~~~
## 6.变量的作用域
程序中的变量并不是在任意的位置都可以随意访问,在哪里可以访问取决于这个变量的作用域,变量的作用域指的是变量在那段代码中可以使用,可以使用变量的那段代码就是变量的作用域。在python中,只有函数/类/模块才引入作用域,if/elif/else , while/for,try/except等并不会引入新的作用域
~~~
#if语句不引入新作用域,msg在外面可以使用
if True:
msg = "message"
print(msg)
~~~
### 6.1 变量作用域的分类
按照作用域划分,可以分为:
- L:Local,局部作用域
- E:Enclosing,闭包作用域【闭包外的函数中定义的变量】
- G:Global,全局作用域 在所有函数外定义的变量
- B:Built-in,內建作用域【内置作用域】
~~~
#1 局部作用域
#局部变量只能在函数内部使用,外部无法引用
#局部变量的作用域从定义开始到函数体结束
def demo():
num = 20 #局部变量
print(num)
demo()
#print(num) 错误
#闭包作用域
#
def outter():
x = 10 #函数作用域,从定义开始到本函数结束
def inner():
y = x #在闭包中可以引用
print(y)
return inner
pf = outter()
pf() #执行闭包
print(pf.__closure__)
#全局作用域
x = 100 #全局作用域 从定义开始到本文件结束
def demo():
print(x)
print(x)
#内建作用域,是指系统内建的函数或常量,在系统载入时加载,在所有模块中都可以直接引用
#比如说系统函数
print(max(1,2,3)) #max函数就是内建作用域 哪里都可以引用
def demo():
x = 30
y = 50
print(max(x, y))
~~~
### 6.2 变量作用域查找规则
以 L --> E --> G -->B 的规则查找,即:在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,最后到内建作用域中找。
### 6.3 全局变量和局部变量
定义在函数内部的变量拥有一个局部作用域,被称为局部变量
定义在函数外面的变量拥有一个全局作用域,被称为全局变量
~~~
total = 0 #全局变量
def sum(arg1,arg2):
total = arg1 + arg2 #局部变量
print("函数内部:",total)
return total
sum(10,20)
#print(total1)
print("函数外部:",total)
num = 1
def fun1():
print(num) #UnboundLocalError: local variable 'num' referenced before assignment
num = 123
print(num)
fun1()
~~~
### 6.4 global和nonlocal
~~~
#1.在Python中,当内部作用域想修改外部作用域的变量的时候,则就要使用global关键字进行声明
num = 1
def fun1():
global num #告诉编译器,此处的num是全局变量
print(num) #1
num = 123
print(num) #123
fun1()
a = 10
def test():
global a
a = a + 1
print(a)
test()
#2.如果要修改函数作用域中的变量,则使用nonlocal
#需要明确的是,nonlocal关键字定义在闭包里面
x = 0 #全局作用域
def outer():
x = 1 #函数作用域
def inner():
nonlocal x
x = 2 #局部作用域
print("inner:",x) #2
inner()
print("outer:",x) #1---->2
outer()
print("全局:",x) #0
#nonlocal关键字:声明了该变量不只是在inner函数内部才有效,而是在整个outer函数中有效
~~~