python函数式编程(Functional Programming)

python函数式编程(Functional Programming)
函数式编程是一种抽象程度很低的编程范式,纯粹的函数式编程语言编写的函数没有变量,这种纯粹的函数式编程没有副作用(这里并不是很理解而为什么没有副作用以及副作用是一个什么概念)
函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数(然后呢)。python不是纯函数式编程语言。
高阶函数(Higher-order function)
1.变量可以指向函数
我们都知道变量可以指向函数的返回值 :

>>> x = abs(-10)
>>> x
10

变量f现在已经指向了abs函数本身。直接调用abs()函数和调用变量f()完全相同。

>>> f = abs
>>> f
<built-in function abs>
>>> f = abs
>>> f(-10)
10

2.函数名也是变量
函数名也是指向函数的变量。
abs函数定义在import builtins模块中

>>> abs = 10
>>> abs(-10)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'int' object is not callable

要恢复abs函数,请重启Python交互环境。
注:由于abs函数实际上是定义在import builtins模块中的,所以要让修改abs变量的指向在其它模块也生效,要用import builtins; builtins.abs = 10
3.传入函数
变量可以指向函数,函数的参数也可以接受变量,那么一个函数可以接受另外一个函数作为参数,这种函数称为高阶函数(感觉高阶这个词用的不错~西西)。高阶函数的目的就是让函数的参数能够接受别的函数

>>> add(-5, 6, abs)
11
x = -5
y = 6
f = abs
f(x) + f(y) ==> abs(-5) + abs(6) ==> 11
return 11

一>.map/reduce
map作为一个高阶函数将运算规则抽象,因此,我们可以用map将复杂的函数简单表示
例1:把这个list所有数字转为字符串:

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

例2:直接看代码~内容也比较容易就不解释了

>>> 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]

reduce把一个函数作用在一个序列[x1, x2, x3, …]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算。看以下例题:
如果要把序列[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

二>.filter
Python内建的filter()函数用于过滤序列。
注意到filter()函数返回的是一个Iterator,也就是一个惰性序列,所以要强迫filter()完成计算结果,需要用list()函数获得所有结果并返回list。
然后来一枚栗子:
用filter求素数
埃氏筛法算法思想:
首先,列出从2开始的所有自然数,构造一个序列:
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, …
取序列的第一个数2,它一定是素数,然后用2把序列的2的倍数筛掉:
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, …
取新序列的第一个数3,它一定是素数,然后用3把序列的3的倍数筛掉:
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, …
取新序列的第一个数5,然后用5把序列的5的倍数筛掉:
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, …
不断筛下去,就可以得到所有的素数。

def _odd_iter():
    n=1
    while True:
        n=n+2
        yield n     #一个生成无限序列的生成器


def _not_divisible(n):
    return lambda x:x%n>0   #定义一个筛选器


def primes():
    yield 2
    it=_odd_iter()
    while True:
        n=next(it)
        yield n
        it=filter(_not_divisible(n),it)

#这个生成器先返回一个素数2,然后利用filter不断产生筛选后的新序列


for n in primes():
    if n<1000:
        print(n)
    else:
        break

filter()的作用是从一个序列中筛出符合条件的元素。由于filter()使用了惰性计算,所以只有在取filter()结果的时候,才会真正筛选并每次返回下一个筛出的元素

我们注意lambda函数与其他函数语法定义不同的地方: 1、参数列表周围没有括号 2、没有 return 关键字(它是隐含存在的,因为整个函数只有一行) 3、该函数没有函数名称,但是可以将它赋给一个变量来使用,此时变量中是lambda函数的引用 lambda 是一种风格问题。不一定非要使用它。想要更多了解可以通过下面的链接
http://www.cnblogs.com/youxin/p/3157193.html
三>.sorted
Python内置的sorted()函数就可以对list进行排序:

>>> sorted([36, 5, -12, 9, -21])
[-21, -12, 5, 9, 36]

sorted()函数也是一个高阶函数,它还可以接收一个key函数来实现自定义的排序,例如按绝对值大小排序:

>>> sorted([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]

要进行反向且忽略 大小写排序,不必改动key函数,可以传入第三个参数reverse=True:

>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
['Zoo', 'Credit', 'bob', 'about']

通过以上可见python高阶函数的抽象能力很强。
返回函数
一个函数可以返回一个计算结果,也可返回一个函数。返回一个函数时,牢记这个函数并没有执行,返回函数中不要引用任何可能会变化的变量。这种程序结构叫做“闭包”。
如下,我们在函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中。

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

当我们调用该函数的时候:

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

调用f的时候,计算真正的结果:

>>> f()
25

需要注意的是每次调用 都会返回一个新的函数,即使参数相同:

>>> f1 = lazy_sum(1, 3, 5, 7, 9)
>>> f2 = lazy_sum(1, 3, 5, 7, 9)
>>> f1==f2
False

注意的是返回函数不要引用任何循环变量,或者后续会发生变化的变量。
如下代码:

def count():
    fs = []
    for i in range(1, 4):
        def f():
             return i*i
        fs.append(f)
    return fs

f1, f2, f3 = count()
>>> f1()
9
>>> f2()
9
>>> f3()
9

返回函数引用变量i,并非立刻执行,等到三个函数都返回的时候,他们引用的变量变成了3,所以返回9。
解决这个问题的方案是,方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变(这个代码没有看太懂,以后的实践中慢慢来吧):

def count():
    def f(j):
        def g():
            return j*j
        return g
    fs = []
    for i in range(1, 4):
        fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f()
    return fs
>>> f1, f2, f3 = count()
>>> f1()
1
>>> f2()
4
>>> f3()
9

匿名函数:
匿名函数即是用 关键字lambda表示的函数

>>> list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
[1, 4, 9, 16, 25, 36, 49, 64, 81]

:前面的x即是该函数的参数,其中的函数相当于:

def f(x):
   return x * x

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

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

此外匿名函数也可以作为返回值,这些就不用赘述了,其实感觉匿名函数就是在一些情况下可以化简代码。
装饰器:
装饰器的意思即是说,假设有一个now()函数,比如在函数调用后自动打印日志,但又不希望修改now()函数的定义,这种代码运行期间动态增加功能的方式称为装饰器。
一套完整的装饰器(decorator)如下:

import functools

def log(func):
    @functools.wraps(func)
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper

import functools是导入functools模块。Python内置的functools.wraps,防止依赖于函数签名的代码出错 ,需要把原始函数的name等属性复制到wrapper()函数中。
或者针对带参数的decorator:

import functools

def log(text):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print('%s %s():' % (text, func.__name__))
            return func(*args, **kw)
        return wrapper
    return decorator

偏函数
当函数的参数过多的时候,需要化简,使用functools.partial可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单。functools.partial的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。

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

这一章关于函数式编程就到这里啦~~其实这就是梳理了我的思维,很放在里面,如果想要系统这个过程,建议好好阅读廖官网的文章~西西~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值