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)

# '及格'




posted @ 2022-03-23 13:57  taoshushu  阅读(67)  评论(0编辑  收藏  举报