Python(六)

高阶函数Higher-order function:一个函数的参数是另外一个函数(复合函数?)

特点1:变量可以指向函数(f→abs,f(-10)=10)

特点2:函数名(abs()函数中的abs)也是变量(如果指定abs=10,就无法启用abs()函数了。要恢复,重启Python交互环境。)

 

map(function,iterable):根据提供的函数对指定序列做映射。map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。

>>> def f(x):
...     return x * x
...
>>> r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> list(r)
[1, 4, 9, 16, 25, 36, 49, 64, 81]

map()传入的第一个参数是f,即函数对象本身。由于结果r是一个IteratorIterator是惰性序列,因此通list()函数让它把整个序列都计算出来并返回一个list

其实,不需要map(),通过循环也能实现计算结果:

L = []
for n in [1, 2, 3, 4, 5, 6, 7, 8, 9]:
    L.append(f(n))
print(L)

事实上,map()作为高阶函数,事实上它把运算规则抽象了,因此,我们不但可以计算简单的f(x)=x2,还可以计算任意复杂的函数,比如,把这个list所有数字转为字符串:

>>> list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
['1', '2', '3', '4', '5', '6', '7', '8', '9']

reduce(function,iterable [,initializer]:将一个数据集合(listtuple等)中的所有数据进行下列操作:用传给 reduce 中的函数 function有两个参数)先对集合中的第 1、2 个元素进行操作,得到的结果再与第三个数据function 函数运算,最后得到一个结果。

reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

问题:如何对一个序列各元素进行求和。

>>> from functools import reduce
>>> def add(x, y):
...     return x + y
...
>>> reduce(add, [1, 3, 5, 7, 9])
25

当然求和运算可以直接用Python内建函数sum(),没必要动用reduce

sum(iterable [,start]:对数据集合(listtuple等)进行求和计算。(iterable -- 可迭代对象,如:列表、元组、集合。start -- 指定相加的参数,如果没有设置这个值,默认为0。)

但是,如果要把列表[1, 3, 5, 7, 9] 变换成整数13579,就可以通过reduce实现。

>>> from functools import reduce
>>> def fn(x, y):
...     return x * 10 + y
...
>>> reduce(fn, [1, 3, 5, 7, 9])
13579

 因为字符串str也是一个序列,对上面的例子稍加改动,配合map(),我们就可以写出把str转换为int的函数:

>>> from functools import reduce
>>> def fn(x, y):
...     return x * 10 + y
...
>>> def char2num(s):
...     digits = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
...     return digits[s]
...
>>> reduce(fn, map(char2num, '13579'))
13579

整理成一个str2int的函数就是

from functools import reduce

DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}

def str2int(s):
    def fn(x, y):
        return x * 10 + y
    def char2num(s):
        return DIGITS[s]
    return reduce(fn, map(char2num, s))

还可以用lambda函数进一步简化

from functools import reduce

DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}

def char2num(s):
    return DIGITS[s]

def str2int(s):
    return reduce(lambda x, y: x * 10 + y, map(char2num, s))

filter(function, iterable:用于过滤序列,过滤掉不符合条件的元素,返回一个迭代器对象,如果要转换为列表,可以使用 list() 来转换【因为filter()函数返回的是一个Iterator,也就是一个惰性序列】。

该接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判,然后返回 True 或 False,最后将返回 True 的元素放到新列表中。

#要求只保留一个list中的奇数:
def is_odd(n):
    return n % 2 == 1

list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
# 结果: [1, 5, 9, 15]
# 要求删掉一个序列中的空字符串:
def not_empty(s):
    return s and s.strip()

list(filter(not_empty, ['A', '', 'B', None, 'C', '  ']))
# 结果: ['A', 'B', 'C']

str.strip([chars]:移除字符串头尾指定的字符(默认为空格或换行符)或字符序列,返回移除字符串头尾指定的字符生成的新字符串。     chars -- 移除字符串头尾指定的字符序列(即要移除的部分)。

注意:该方法只能删除开头或是结尾的字符,不能删除中间部分的字符。

 

问题:如何实现用filter()求素数。

 

 

sorted(iterable[,cmp[,key[,reverse]]]:对所有可迭代的对象进行排序操作。

  • iterable -- 可迭代对象。
  • cmp -- 比较的函数,这个具有两个参数,参数的值都是从可迭代对象中取出,此函数必须遵守的规则为,大于则返回1,小于则返回-1,等于则返回0。
  • key -- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。
  • reverse -- 排序规则,reverse = True 降序 , reverse = False 升序(默认)。

我们再看一个字符串排序的例子:

>>> sorted(['bob', 'about', 'Zoo', 'Credit'])
['Credit', 'Zoo', 'about', 'bob']

默认情况下,对字符串排序,是按照ASCII的大小比较的,由于'Z' < 'a',结果,大写字母Z会排在小写字母a的前面。

sorted传入key函数,即可实现忽略大小写的排序:

>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)
['about', 'bob', 'Credit', 'Zoo']
sort 与 sorted 区别:
sort 是应用在 list 上的方法sorted 可以对所有可迭代的对象进行排序
list 的 sort 方法返回的是对已经存在的列表进行操作,无返回值内建函数 sorted 方法返回的是一个新的 list,而不是在原来的基础上进行的操作

 

返回函数(返回值是一个函数)

问题:实现一个可变参数的求和,要求不需要立刻求和,不返回求和的结果,返回求和的函数,后续有需要再进行计算。

def lazy_sum(*args):
    def sum():
        ax = 0
        for n in args:
            ax = ax + n
        return ax
    return sum

#调用lazy_sum()时,返回的结果是:
>>> f = lazy_sum(1, 3, 5, 7, 9)
>>> f
<function lazy_sum.<locals>.sum at 0x101c6ed90>

#调用函数f时,才真正计算求和的结果:
>>> f()
25

本例中,在函数lazy_sum()中又定义了函数sum(),并且,内部函数sum()可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力。

注意:调用lazy_sum()时,每次调用都会返回一个新的函数,即使传入相同的参数(如f1 = lazy_sum(1,2,3,4) f2 = lazy_sum(1,2,3,4),f1≠f2),彼此的调用结果互不影响。

 

 

匿名函数

当我们在传入函数时,有些时候,不需要显式地定义函数,直接传入匿名函数更方便。

Python支持所谓的 匿名 或者 lambda 函数。匿名函数是一种通过单个语句生成函数的方式,其结果是返回值。匿名函数使用lambda关键字定义,该关键字仅表达“我们声明一个匿名函数”的意思。

语法:lambda arg1,arg2,.....argn:expression

匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果。

用匿名函数有个好处,因为函数没有名字,不必担心函数名冲突。此外,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数。

>>> f = lambda x: x * x
>>> f
<function <lambda> at 0x101c6ef28>
>>> f(5)
25

#同样,也可以把匿名函数作为返回值返回,比如:
def build(x, y):
    return lambda: x * x + y * y

装饰器(Decorator)

 

偏函数Partial function

Python的functools模块提供了很多有用的功能,其中一个就是偏函数(Partial function)

即:当函数的参数个数太多,需要简化时,使用functools.partial可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单。

int()函数默认按十进制转换把字符串转换为整数,但它同时也提供修改base参数(默认值为10),实现对N进制的转换

【改变base值,就是指定N进制转换为十进制!】

>>> int('12345', base=8) #将八进制表示的12345转换为十进制表示的数
5349
>>> int('12345', 16)  #将十六进制表示的12345转换为十进制表示的数
74565

如果要转换大量的二进制字符串,每次都传入int(x, base=2)非常麻烦,我们就可以定义一个int2()函数来实现:

def int2(x,base =2):
    return int(x,base)

functools.partial就是帮助我们创建一个偏函数的,不需要我们自己定义int2(),可以直接使用下面的代码创建一个新的函数int2()

>>> import functools
>>> int2 = functools.partial(int, base=2)
>>> int2('1000000')
64
>>> int2('1010101')
85

简单总结functools.partial的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。

注意到上面的新的int2()函数,仅仅是把base参数重新设定默认值为2,但也可以在函数调用时传入其他值:

>>> int2('1000000', base=10)
1000000

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值