python基础语法 - 函数进阶
本章内容索引:
- 高阶函数
- 递归函数
- 函数作用域
- 装饰器
- 内置函数
高阶函数
1.函数在内存种的储存情况

2.基本语法
def f(n):
return n*n
def foo(a,b,f):
return f(a) + f(b)
print(foo(2,4,f))
- 函数名是一个变量
- 函数名可以进行赋值
- 函数名可以作为函数参数,还可以作为函数的返回值
递归函数
定义:在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
实例1(阶乘)
5!=5*4*3*2*1=120
def f(n):
if n == 1:
return 1
return n*f(n-1)
f(5) #120
实例2(斐波那契数列)
1, 1, 2, 3, 5, 8, 13, 21, 34, 55
def fibo(n):
if n <= 1:
return n
return (fibo(n - 1) + fibo(n - 2))
fibo(10) #55
递归特性:
1. 必须有一个明确的结束条件
2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
3. 递归效率不高,递归层次过多会导致栈溢出
注:在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出
函数作用域
1.python中的作用域分4种情况:
- L:local,局部作用域,即函数中定义的变量;
- E:enclosing,嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的;
- G:globa,全局变量,就是模块级别定义的变量;
- B:built-in,系统固定模块里面的变量,比如int, bytearray等。 搜索变量的优先级顺序依次是:作用域局部>外层作用域>当前模块中的全局>python内置作用域,也就是LEGB。
x = int(2.9) # int built-in
g_count = 0 # global
def outer():
o_count = 1 # enclosing
def inner():
i_count = 2 # local
print(o_count)
# print(i_count) 找不到
inner()
outer()
# print(o_count) #找不到
当然,local和enclosing是相对的,enclosing变量相对上层来说也是local
2.作用域的产生
在Python中,只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如if、try、for等)是不会引入新的作用域的,如下代码:
if 2>1:
x = 1
print(x) # 1
这个是没有问题的,if并没有引入一个新的作用域,x仍处在当前作用域中,后面代码可以使用。
def test():
x = 2
print(x) # NameError: name 'x2' is not defined
def、class、lambda是可以引入新作用域的。
3.global关键字
当内部作用域想修改外部作用域的变量时,就要用到global和nonlocal关键字了,当修改的变量是在全局作用域(global作用域)上的,就要使用global先声明一下,代码如下:
count = 10
def outer():
global count
print(count)
count = 100
print(count)
outer()
#10
#100
4.nonlocal关键字
global关键字声明的变量必须在全局作用域上,不能嵌套作用域上,当要修改嵌套作用域(enclosing作用域,外层非全局作用域)中的变量怎么办呢,这时就需要nonlocal关键字了
5.作用域小结
(1)变量查找顺序:LEGB,作用域局部>外层作用域>当前模块中的全局>python内置作用域;
(2)只有模块、类、及函数才能引入新作用域;
(3)对于一个变量,内部作用域先声明就会覆盖外部变量,不声明直接使用,就会使用外部作用域的变量;
(4)内部作用域要修改外部作用域变量的值时,全局变量要使用global关键字,嵌套作用域变量要使用nonlocal关键字。nonlocal是python3新增的关键字,有了这个 关键字,就能完美的实现闭包了。
装饰器
1.作用域
- L_E_G_B
2.高阶函数
- 函数名可以作为参数输入
- 函数名可以作为返回值
3.闭包
定义:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)
def outer():
x=10
def inner(): #条件1 inner就是内部函数
print(x) #条件2 外部环境的一个变量
return inner #结论 内部函数inner就是一个闭包
f = outer()
f()
关于闭包:闭包=内部函数块+定义函数时的环境
4.装饰器
def foo():
print('foo...')
time.sleep(1)
def show_time(f):
strat = time.time()
f()
end = time.time()
print('spend %s' % (end - strat))
show_time(foo)
- 改变了原函数的调用方式
解决方式如下:
def foo():
print('foo...')
time.sleep(1)
def show_time(f):
def inner():
strat = time.time()
f()
end = time.time()
print('spend %s' % (end - strat))
return inner
foo = show_time(foo)
foo()
- 每个函数都需要重新赋值
解决方法如下:(语法糖)
def show_time(f):
def inner():
strat = time.time()
f()
end = time.time()
print('spend %s' % (end - strat))
return inner
@show_time #foo = show_time(foo)
def foo():
print('foo...')
time.sleep(1)
foo()

功能函数加参数:

不定长参数:
def show_time(f):
def inner(*a,**b):
strat = time.time()
f(*a,**b)
end = time.time()
print('spend %s' % (end - strat))
return inner
@show_time #foo = show_time(foo)
def foo(*a,**b):
sums = 0
for i in a:
sums += i
print(sums)
time.sleep(1)
foo(2,3,4,6)
装饰器加参数:

内置函数:
1. filter(function, sequence)
str = ['a', 'b','c', 'd']
def fun1(s):
if s != 'a':
return s
ret = filter(fun1, str)
print(list(ret))# ret是一个迭代器对象
- 对sequence中的item依次执行function(item),将执行结果为True的item做成一个filter object的迭代器返回。可以看作是过滤函数。
2. map(function, sequence)
str = [1, 2,'a', 'b']
def fun2(s):
return s + "alvin"
ret = map(fun2, str)
print(ret) # map object的迭代器
print(list(ret))# ['aalvin', 'balvin', 'calvin', 'dalvin']
- 对sequence中的item依次执行function(item),将执行结果组成一个map object迭代器返回,map也支持多个sequence,这就要求function也支持相应数量的参数输入
3. reduce(function, sequence, starting_value)
from functools import reduce
def add1(x,y):
return x + y
print (reduce(add1, range(1, 101)))## 4950 (注:1+2+...+99)
print (reduce(add1, range(1, 101), 20))## 4970 (注:1+2+...+99+20)
- 对sequence中的item顺序迭代调用function,如果有starting_value,还可以作为初始值调用
4. lambda
普通函数与匿名函数的对比:
#普通函数
def add(a,b):
return a + b
print add(2,3)
#匿名函数
add = lambda a,b : a + b
print add(2,3)
#========输出===========
5
5
匿名函数的命名规则,用lamdba 关键字标识,冒号(:)左侧表示函数接收的参数(a,b) ,冒号(:)右侧表示函数的返回值(a+b)。
因为lamdba在创建时不需要命名,所以,叫匿名函数

浙公网安备 33010602011771号