python高阶函数

高阶函数介绍

Higher-order function

  • 变量可以指向函数
  • 函数名又可以是变量
def hello():
    print("hello world!")
f=hello
print(f)
abs=10
print(abs)
"""
<function hello at 0x0000023168ED9D08>
10
"""

由函数与变量的相互关系知道,可以把一个函数作为参数传入到另一个函数:

def hello(str):
    print("hello "+str+"!")
def f(a,hello):
    hello(a)
f("world",hello)
# hello world!

内置高阶函数

map

map()函数接收两个参数,一个是函数,一个是序列,map 将传入的函数依次作用到序列的每个元素 ,并把结果作为新的 list返回

  • 但实际上,在python3中,map()返回的是迭代器而不再是list,可使用list(map())的形式得到list
def times(x):
    return x*x
a=map(times,[1,2,3,4,5])
print(a,list(a))
"""<map object at 0x0000023168CCF390> [1, 4, 9, 16, 25]"""

reduce

reduce()同样接受两个参数,一个是函数,一个是序列,reduce将累计运算结果与下一个元素计算,效果如下:

reduce(f,[a,b,c])=f(f(a,b),c)

reduce在python3当中已经被移除到了functlools模块中了,使用方法如下:

from functools import reduce
def add(a,b):
    return a+b
c=reduce(add,[1,34,7,8])
print(c)
# 50

例子2:

from functools import reduce
def char2num(s):
    return {'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9,'0':0}[s]
def num2int(a,b):
    return a*10+b
str1=reduce(num2int,map(char2num,"23523"))
print(str1)
# 23523

filter

filter函数同样接收两个参数,一个函数和一个序列,filter将函数应用于每个元素,然后再根据返回值是True或False来决定是否保留或丢弃元素。

例子1:

def is_odd(x):
    return x%2==1
a=filter(is_odd,[233,4,5,65,7,7,8,6])
print(list(a))
# [233, 5, 65, 7, 7]
"""只保留了奇数"""

例子2:

def del_none(s):
    return s and s.strip     #解析看下面
b=filter(del_none,["hello "," ","","hel lo"])
print(list(b))
"""['hello ', ' ', 'hel lo']"""
  • and布尔逻辑演算:
    • 如果布尔上下文中的所有都为真,那么and返回最后一个值
    • 如果布尔上下文中有一个为假,那么and返回第一个假值
  • or布尔逻辑演算:
    • 从左到右进行演算找到第一个真值就返回,其余的忽略
    • 如果找不到真值,就返回最后一个假值
"a" and "b" and "c"
'c'
"a" and "" and "c"
''

"a" or "b"or "c"
'a'
"a" or ""or "c"
'a'
"" or "a"or "c"
'a'
0 or ""or []
[]

sorted

sorted用来对可迭代对象排序,通常规定,对于两个元素x和y,如果认为 x < y,则返回-1 ,如果认为 x == y,则返回0 ,如果认为 x > y,则返回1

a=sorted([12,5,2,47,9])
b=sorted([12,5,2,47,9],reverse=True)
print(a,b)
c=[(123,"A",34),(23,"D",34),(65,"B",84)]
d=sorted(c,key=lambda x:x[1])
print(d)
"""
[2, 5, 9, 12, 47] [47, 12, 9, 5, 2]
[(123, 'A', 34), (65, 'B', 84), (23, 'D', 34)]
"""

将函数作为返回值

例子1:

def lazy_sum(*args):
	"""total=0不能放在这里,会出错,因为这里定义的变量不能在内部函数sum()里面被修改,除非使用nonlocal关键字"""
    def sum():
        total=0
        for i in args:
            total=total+i
        return total
    return sum
f=lazy_sum(23,5,63)
print(f)
f()
  • 内部函数sum可以调用外部函数lazy_sum的参数或局部变量(只能使用不能修改,修改需加关键字nonlocal),相关的参数和变量都保存在了返回的函数中,这种程序结构称为 ”闭包“
  • lazy_sum被f调用时,返回的并不是结果,而是sum函数
  • 当调用f时才会返回最终结果

针对total=0位置的改变,代码可以修改成如下:

def lazy_sum(*args):
    total=0
    def sum():
        nonlocal total
        for i in args:
            total=total+i
        print(total)
    return sum
f=lazy_sum(23,5,63)
print(f)
f()
闭包函数:

概述: 在外部函数中定义了内部函数,内部函数使用了外部函数的参数或者变量,外部函数的返回是内部函数的引用。

例子1:

def outter(a):
    b=2
    def inner():
        print(a+b)
    return inner
c=outter(4)
c()
# 6

例子2:

def outter():
    fs=[]
    for i in range(4):
        def f():
            return i*i
        fs.append(f)
    return fs
a=outter()
print(a)
"""[<function outter.<locals>.f at 0x000001555C584400>, <function outter.<locals>.f at 0x000001555C584488>, <function outter.<locals>.f at 0x000001555C584510>, <function outter.<locals>.f at 0x000001555C584598>]"""
a[1](),a[2](),a[3]()
#(9, 9, 9)
  • 分析:
    • 从结果可知,三个值都是9,而不是[1,4,9],这是因为循环创建的3个函数f都没有被立刻执行,导致每个函数里面的 i值最终都变成了3,所以调用时候结果都为9
    • 因此,返回函数里建议不要使用循环变量,如果要使用,则再建一个函数,修改如下:
def outter():
    fs=[]
    for i in range(4):
        def f(j):
            def g():
                return j*j
            return g
        fs.append(f(i))
    return fs
a=outter()
a[1](),a[2](),a[3]()
# (1, 4, 9)

匿名函数

没有名字的函数,同时匿名函数也是一个函数对象,可以把匿名函数赋值给一个变量

a=map(lambda x:x*x,[2,3,5,6,7])
print(list(a))

装饰器

在代码运行期间 动态增加函数功能 的方式称之为“装饰器”

例子1:

def now():
    print("2019/7/5")
now()
"""2019/7/5"""


"""下面给now()函数增加功能"""
def log(func):
    def wrapper(*args,**kw):
        print("call {}".format(func.__name__))
        return func(*args,**kw)
    return wrapper
@log
def now():
    print("2019/7/5")


""""重新运行now()函数:"""
now()
"""
call now
2019/7/5"""

print(now)
<function log.<locals>.wrapper at 0x000001C87FC78400>
now.__name__
"""wraper"""

分析:

  • print(now)输出可以知道,now变量已经指向了另一个函数wrapper
  • 执行装饰后的now()函数,相当于执行log(now())
  • 学习过程的疑惑:为什么a=log(now())直接返回结果了,而不是返回对象,分析如下:
    • a=log(now())可以拆分成两步:
      • a=log #此步返回wrapper函数对象
      • a(now()) # 执行结果运算输出
  • 每个函数都有一个属性 .__name__,返回函数的名字

例子2: 在上面的例子基础上 给装饰器添加参数,代码修改如下:

def decorator(parameter):
    def log(func):
        def wrapper(*args,**kw):
            print("call {}".format(func.__name__))
            print(parameter)
            return func(*args,**kw)
        return wrapper
    return log
@decorator("hello world!")
def now():
    print("2019/7/5")

now()
"""
call now
hello world!
2019/7/5
"""


print(now)
<function decorator.<locals>.log.<locals>.wrapper at 0x000001C87FE210D0>
now.__name__
"""wraper"""

分析:

  • print(now)输出可以知道,now变量已经指向了另一个函数log
  • now()相当于执行decorator(“hello world”)(now())
上面还不是装饰器的完整写法,下面继续补充:
  • 以第一例子为例,now.__name__的结果为"wrapper",因为now变量名指向了wrapper函数,而wrapper函数的名字是“wrapper”
  • 如果要把原始函数now的__name__等属性复制到wrapper函数中,从而使得now.__name__的结果还是"now",可以利用python内置的functools.wraps,这就是装饰器的完整写法,如下:
import functools
def log(func):
    @functools.wraps(func)   """不需要编写wrapper.__name__ = now.__name__这样的代码"""
    def wrapper(*args,**kw):
        print("call {}".format(func.__name__))
        return func(*args,**kw)
    return wrapper
@log
def now():
    print("2019/7/5")


print(now)
now.__name__
# 'now'

偏函数

通过设定参数的默认值,可以 降低函数的调用难度,这个就是偏函数做的东西,是利用 functools.partial 实现的

例子1:

"""int可以把字符串转换为整数,并通过base=转为一定进制"""
int("2363")
2363
int("2363",base=8)
1267
int("2363",base=16)
9059
int2=functools.partial(int,base=16)
int2("2363")
905
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值