最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 科技 - 知识百科 - 正文

[python]初探'函数式编程'

来源:动视网 责编:小采 时间:2020-11-27 14:26:42
文档

[python]初探'函数式编程'

[python]初探'函数式编程':函数式编程上学期有上一门叫 '人工智能' 的课,老师强行要我们学了一个叫做 prolog 的语言,哇那感觉确实难受,思维方式完全和之前学过的不一样,写个汉诺塔想了半天,最后还是在网上找了段代码修改一下(怕被老师发现抄袭)才写出来,贴一段出来感受一
推荐度:
导读[python]初探'函数式编程':函数式编程上学期有上一门叫 '人工智能' 的课,老师强行要我们学了一个叫做 prolog 的语言,哇那感觉确实难受,思维方式完全和之前学过的不一样,写个汉诺塔想了半天,最后还是在网上找了段代码修改一下(怕被老师发现抄袭)才写出来,贴一段出来感受一


可能看完还是有些不太理解,不急,先看完这几个小节吧。

高阶函数

在数学和计算机科学中,高阶函数是至少满足下列一个条件的函数:

  • 接受一个或多个函数作为输入

  • 输出一个函数

  • 也就是说,把函数本身当成参数传递,或者返回一个函数。

    例如,可以像普通赋值一样将函数赋值给变量:

    >>> min(1, 2)
    1
    >>> f = min
    >>> f(1, 2)
    1
    >>> f
    <built-in function min>
    >>> min
    <built-in function min>

    也可以给函数赋值(代码接上):

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

    还可以传参,例如,一个计算所有数字的和的函数:

    >>> def add(a, b):
    ... return a+b
    ...
    
    >>> def mysum(f, *l):
    ... a = 0
    ... for i in l:
    ... a = f(a, i)
    ... return a
    ...
    >>> mysum(add, 1, 2, 3)
    6
    >>> mysum(add, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    55

    当然,将这个 f 换成乘法就是计算所有数字的乘积了。

    再来看看 python 内置的一些高阶函数,经常会用到。

    map/reduce

    记得上学期上云计算的课程时依稀有听到过这个词,不过这课很水,就没怎么听,在这里看到好像发现不太一样??

    不过没啥说的,简单说一下每个函数的作用。

    对于 map,其计算式可以看成这样:

    map(f, [x1, x2, ..., xn]) = [f(x1), f(x2), ..., f(xn)]

    对于 reduce,其计算式可以看成这样:

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

    廖大那里说得很清楚啦。

    filter

    filter 和 map 函数类似,接受一个函数和 iterable,返回也是一个 list,不过其功能是根据函数返回值是否为 True 来判断是否保留该值。例如:

    def is_odd(n):
     return n % 2 == 1
    
    list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
    # 结果: [1, 5, 9, 15]

    sorted

    sorted 函数同样是一个高阶函数,对参数 key 传递函数可以将需要排列的序列经过 key 函数处理后再进行排序,不过不会改变序列的值,例如:

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

    装饰器(decorator)

    匿名函数就不说了,以后用时再仔细看吧,装饰器我记得之前看 flask 的时候都研究了好久,这次再来复习一下。

    简单装饰器

    首先是一个简单的装饰器,在每次调用函数前打印出日志:

    import logging
    
    def log(func):
     def wrapper(*args, **kw):
     logging.warn("%s is running" % func.__name__)
     func(*args, **kw)
     return wrapper

    这就是一个极其简单的装饰器,如何使用它呢?我最先看到的用法是在需要装饰的函数前添加@,但其实这是 Python 的一个语法糖,最原始的用法反而更能让人理解,先定义一个函数 f:

    def f():
     print("in function f")
    
    f = log(f)

    这样定义了之后,我们再调用 f 函数:

    >>> f()
    WARNING:root:f is running
    in function f

    使用 @log 的结果与其一样,其实@符号作为装饰器的语法糖,与前面的赋值语句具有相同的功能,使代码看起来更简洁明了,避免再一次赋值操作,就像下面这样:

    @log
    def f():
     print("in function f")

    含参数的装饰器

    有时候我们还需要向装饰器中传入参数,例如,状态,层次等信息,只需要在 wrapper 函数外再'包裹'一层函数,如下所示:

    import logging
    
    def log(level):
     def decorator(func):
     def wrapper(*args, **kw):
     logging.warn("%s is running at level %d" % (func.__name__, level))
     return func(*args, **kw)
     return wrapper
     return decorator
    
    @log(2)
    def f():
     print("in function f")
     
    >>> f()
    WARNING:root:f is running at level 2
    in function f

    进一步理解

    为了再进一步理解装饰器,我们可以打印出函数 f 的 name 属性:

    #对于不加装饰器的 f,其 name 不变
    >>> def f():
    ... print("in function f")
    ...
    >>> f.__name__
    'f'
    
    #对于添加装饰器的函数,其 name 改变了
    >>> @log
    ... def f():
    ... print("in function f")
    ...
    >>> f.__name__
    'wrapper'

    联系到最前面的装饰器赋值语句,就可以大致明白发生了什么:f = log(f) 使得 f 指向修改为 log(f) 的返回值,即 wrapper 函数。每次运行原函数 f 时,则会调用 wrapper 函数,在我们这个例子中,则是先打印日志,然后运行原函数 f。

    不过这样有一个问题,这样使得原函数 f 的元信息被替换了,关于 f 的许多信息消失不见,这是很难令人接受的,不过好在我们有 functools 模块,修改函数为:

    import functools
    import logging
    
    def log(func):
     functools.wraps(func)
     def wrapper(*args, **kw):
     logging.warn("%s is running" % func.__name__)
     func(*args, **kw)
     return wrapper
    
    >>> @log
    ... def f():
    ... print("in function f")
    ...
    >>> f.__name__
    'f'

    另外,还可以对同一个函数添加多个装饰器:

    @a
    @b
    @c
    def f ():
    
    
    # 等价于
    
    f = a(b(c(f)))

    总结

    关于函数式编程我也不是很了解,这里只是大概了解了一下其概念吧,平时肯定还是使用命令式编程用得多。不过有语言是纯函数式语言,例如 Haskell 或 Lisp,学习它们会使得人打开一种新思路。

    更多[python] 初探'函数式编程'相关文章请关注PHP中文网!

    文档

    [python]初探'函数式编程'

    [python]初探'函数式编程':函数式编程上学期有上一门叫 '人工智能' 的课,老师强行要我们学了一个叫做 prolog 的语言,哇那感觉确实难受,思维方式完全和之前学过的不一样,写个汉诺塔想了半天,最后还是在网上找了段代码修改一下(怕被老师发现抄袭)才写出来,贴一段出来感受一
    推荐度:
    • 热门焦点

    最新推荐

    猜你喜欢

    热门推荐

    专题
    Top