6、函数的高级运用
1、作用域
- 所谓作用域,就是变量的有效范围,就是变量可以在哪个范围以内使用。
- 有些变量可以在整段代码的任意位置使用,有些变量只能在函数内部使用,有些变量只能在 for 循环内部使用。
- 变量的作用域由变量的定义位置决定,在不同位置定义的变量,它的作用域是不一样的。
1.1、全局变量与局部变量
- 定义在模块最外层的变量是全局变量,它是全局范围内可见的,当然在函数里面也可以读取到全局变量的
- 定义在函数内部的变量是局部变量,它仅在函数内部可见
A = 10 # 全局变量,约定俗成需要大写
def foo():
b = 5 # 局部变量
print(A) # a是全局变量,函数内部可见,故结果是10
print(b) # b是局部变量,函数内部可见,故结果是5
foo()
print(b) # b是局部变量,仅在函数内部可见,在函数外部不可见,此结果报错
结果:
- 局部作用域和全局作用域的变量同名的情况
a=10 # 为了与局部变量一致,这里不大写
def func():
a=5 # 如果局部变量与全局变量重名,需要记住两者是不一样的变量,此时的局部变量是一个新定义的局部变量
print(a) # 故func()函数的结果是直接打印 5
func() # 5
print(a) # 10
# 结果是:
# 5
# 10
默认情况下,在局部作用域对全局变量只能进行 读取 和 修改内部元素(可变类型) 的操作,不能对全局变量进行重新赋值。重新赋值的情况请参考上面 局部作用域和全局作用域的变量同名的情况
- 读取:
CITY_LISY=['BEIJING','SHANGHAI','GUANGZHOU','SHENZHEN']
def download():
print(CITY_LISY)
download()
# ['BEIJING', 'SHANGHAI', 'GUANGZHOU', 'SHENZHEN']
- 修改内部元素:
CITY_LISY=['BEIJING','SHANGHAI','GUANGZHOU','SHENZHEN']
def download():
CITY_LISY.append("DONGGUAN")
print(CITY_LISY)
download()
# ['BEIJING', 'SHANGHAI', 'GUANGZHOU', 'SHENZHEN', 'DONGGUAN']
1.2、global
关键字
利用global
关键字在函数内部重新赋值全局变量
CITY_LISY=['BEIJING','SHANGHAI','GUANGZHOU','SHENZHEN']
def download():
global CITY_LISY # 利用global关键字在函数内部重新赋值全局变量
CITY_LISY=['北京','上海','广州','深圳']
print(CITY_LISY)
download()
# ['北京', '上海', '广州', '深圳']
print(CITY_LISY) # 全局变量已经被重新赋值
# ['北京', '上海', '广州', '深圳']
2、函数的对象
Python中,函数是「头等公民」。我们可以将函数赋值给变量,也可以将其作为参数传入其他函数,将它们存储在其他数据结构(如 dicts)中,并将它们作为其他函数的返回值。
即:可以把函数当成变量去使用
在函数名的末尾不添加()
,只写名称的格式所表示的是函数本身。我们将其称之为函数对象, 可以像值一样将其代入到变量中去。
- 可以将函数名(函数对象)赋值给变量,此时变量转化成函数对象,可直接调用
def foo():
print("foo")
bar=foo # 将函数赋值给变量bar,注意是函数名,不带()
bar() # 相当于调用了 foo()
# foo
bar # bar变量就是函数,即bar就是函数对象
# <function __main__.foo()>
- 把函数对象当做参数传给另外一个函数
# 先定义一个函数,用来求输入参数的10倍
def func1(x):
r = x * 10
return r
# 再定义一个函数,这个函数用来接收上一个函数
def func2(x, y, f): # f表示此参数是函数作为的参数
s = x + y + f(x) + f(y)
return s
# 调用
func2(2, 5, func1) # s=2+5+2*10+5*10=77
# 77
- 把函数对象当做另外一个函数的返回值
# 先定义一个函数,用来求输入参数的10倍
def func1(x):
r = x * 10
return r
# 再定义一个函数,该函数返回刚才定义的第一个函数
def func2(f): # f表示函数
return f
r=func2(func1) # 将func2赋值给变量,注意内部func1函数是函数名,此时r是函数
r(5) # 调用,相当于:func2(func1(5)) = func1(5) = 5*10 = 50
# 50
r
# <function __main__.func1(x)>
3、高阶函数
函数对象与变量平级,具有以下几个特性:
- 可以将函数对象赋值给变量,此时变量转化成函数对象,可直接调用
- 可以把函数对象当做参数传给另外一个函数
- 可以把函数对象当做另外一个函数的返回值
3.1、高阶函数
一个函数可以接收另一个函数作为参数,这种函数称之为高阶函数
示例:
def add(x, y, f): # add函数是高阶函数,除了接受x,y两个形参外,还接受了函数f作为参数
return f(x) + f(y)
add(-5,6,abs) # x=-5,y=6,f=abs ---> abs(-5) + abs(6) = 11
# 11
3.2、几个重要的高阶函数
3.2.1、map()
函数
map()
函数接收两个参数,一个是函数,一个是序列。map()
函数将传入的函数一次作用到序列的每个原色,并将结果作为新的序列返回。
示例:
比如我们有一个函数f(x)=x*x
,要把这个函数作用在一个序列[1,2,3,4,5,6,7,8,9]上,如下:
def f(x):
return x*x
r=map(f,[1,2,3,4,5,6,7,8,9]) # 传入函数对象,即f
r
# <map at 0x24d07c3bbb0>
type(r)
# map
list(r)
# [1, 4, 9, 16, 25, 36, 49, 64, 81]
示例:
序列[1,2,3,4,5,6,7,8,9],将序列的数字转化为字符串类型
a=[1,2,3,4,5,6,7,8,9]
r=map(str,a) # str即内置函数str()的函数对象
list(r)
# ['1', '2', '3', '4', '5', '6', '7', '8', '9']
3.2.2、reduce()
函数
在python3中,reduce()
不是内置函数,需要引用:from functools import reduce
reduce()
函数,把一个函数作用在序列[x1,x2,x3,x4...]
上,这个接受的函数必须是两个参数,reduce()
函数把结果继续和序列的下一个元素做累积计算,其效果是:
reduce(func(x,y),[x1,x2,x3,x4]) = func(func(func(x1,x2),x3),x4)
示例:
from functools import reduce
def f(x, y):
return x*y
r = reduce(f, [1, 2, 3, 4, 5])
r
# 120
图解map函数遇reduce函数的区别
3.2.3、filter()
函数
filter()
函数用于过滤序列。
- 和
map()
类似,filter()
也接收一个函数和一个序列。 - 和
map()
不同的是,filter()
把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。
示例:在一个list中,删掉奇数,只保留偶数
def oushu(x): # 定义一个函数oushu(),用来判断输入参数是否是偶数,如果是则返回True,如果否则返回False
return x%2==0
oushu(6)
# True
oushu(5)
# False
r = filter(oushu,[1,2,3,4,5,6,7,8,9]) # 利用filter过滤掉奇数
r
# <filter at 0x24d07bff2e0>
list(r)
# [2, 4, 6, 8]
3.2.4、sorted()
函数
sorted()
函数是python内置的,用来对序列排序的函数。
语法:
list = sorted(iterable, key=None, reverse=False)
iterable
表示指定的序列(可迭代对象)。key
参数可以自定义排序规则,可选。reverse
参数指定以升序(False,默认)还是降序(True)进行排序,可选。
sorted()
函数不会修改原本的序列,返回一个已经排好序的list。
示例:
对列表排序,返回的对象不会改变原列表
>>> list_1=[55,44,66,33,77]
>>> sorted(list_1) # 默认升序
[33, 44, 55, 66, 77]
>>> sorted(list_1,reverse=True) # reverse=True 降序
[77, 66, 55, 44, 33]
>>> list_1 # 继续输出 list_1 看下是否有变化
[55, 44, 66, 33, 77]
>>> r=sorted(list_1)
>>> type(r)
list
>>> r
[33, 44, 55, 66, 77]
示例:
对元组排序
tuple_1=(55,44,66,33,77)
sorted(tuple_1)
# [33, 44, 55, 66, 77]
示例:
根据自定义规则来排序,使用参数:key
# 根据字符的长短进行降序排序
chars=[ 'is', 'handsome','boy', 'bruce','a']
sorted(chars,key=lambda x:len(x),reverse=True) # lambda x:len(x) 匿名函数,返回每个字符的长度
# ['handsome', 'bruce', 'boy', 'is', 'a']
示例:
用一组tuple表示学生名字和成绩:L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)],分别按名字排序(升序)与按成绩从高到低排序。
L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
# 按名字排序(升序)
L1 = sorted(L, key=lambda x: x[0], reverse=False) # lambda x: x[0] 表示取得序列内每个元素的第一个内容
L1
# [('Adam', 92), ('Bart', 66), ('Bob', 75), ('Lisa', 88)]
# 按成绩从高到低排序
L2 = sorted(L, key=lambda x: x[1], reverse=True)
L2
# [('Adam', 92), ('Lisa', 88), ('Bob', 75), ('Bart', 66)]
4、匿名函数
匿名函数指一类无须定义标识符的函数或子程序。Python用 lambda
语法定义匿名函数,只需用表达式而无需申明。
语法如下:
lambda [参数1 [,参数2, ... 参数N]] : 表达式
如:
按照一般函数定义方法,定义一个求x平方的函数
def funca(x):
return x**2
funca(10)
# 100
用匿名函数来表示就是:
f = lambda x: x**2 # 匿名函数也是对象,将匿名函数的函数对象赋值给变量f,使得f转化为函数对象
f(10)
# 100
多参数
f2 = lambda a,b,c:a**2+b**2+c**2
f2(1,2,3)
# 14
默认值
f3 = lambda a,b,c=2:a**2+b**2+c**2 # c变量默认为2,注意:默认值只能放在最后,否则会出错
f3(1,3)
# 14
5、三元表达式
三元表达式
如有下面的程序:
a = 90
if a >= 60:
result = "及格"
else:
result = "不及格"
print(result)
# 及格
那么用三元表达式来改写,则如下所示:
a = 90
result= "及格" if a>=60 else "不及格" # 三元表达式
print(result)
# 及格
匿名函数遇三元表达式的结合
一般写法:
def f1(x):
if x >= 60:
result = "及格"
else:
result = "不及格"
print(result)
f1(90)
# 及格
匿名函数遇三元表达式结合的写法:
result=lambda x: "及格" if x>=60 else "不及格"
result(90)
# '及格'