专栏首页窗户Python装饰器的一点解读

Python装饰器的一点解读

  理论上,函数是一等公民(first class function)的语言都可以使用函数式编程,从而利用算子(高阶函数)来做装饰器。

  装饰器一般是这样一个算子,它接受一个函数作为参数,返回另外一个函数。装饰器,顾名思义,就是把一个函数“装饰”一下,得到另外一个函数。为何要装饰一下呢?目的一般是可能设计上需要对函数做一些改装,比如原函数输出结果需要再加工加工,或者原函数的输入参数传入不一样,或者两者兼有之,等等。

  迭代是编程中常用的手段,它的计算方式表现为状态的不断变换,且状态的变换具有唯一性。

  比如我们使用Scheme来表示迭代。

;stat代表当前状态,next代表状态改变函数,final?代表判断状态是否终止
(define (iterate-orgin stat next final?)
  (if (final? stat)
      stat
      (iterate-orgin (next stat) next final?)))

;将next函数和final?函数封成一个函数
(define (iterate stat f-stat)
  (iterate-orgin stat (f-stat 'next) (f-stat 'final)))

;最终我们需要的迭代函数
(define (it f-stat)
  (lambda (stat) (iterate stat f-stat)))

  以上构造出一个算子it,就是用来“装饰”迭代的函数。

  我们构造一个对list求和的迭代:

  可以每次把list的前面两个相加,比如对(1 2 3 4 5)求和,经过以下状态:

  (1 2 3 4 5)

  (3 3 4 5)

  (6 4 5)

  (10 5)

  (15)

  15

  得到最后结果15。

  代码可以如下:

(define (make-sum-func sym)
 (if (eq? sym 'next);next函数
  (lambda (lst)
   (if (pair? lst)
    (if (null? (cdr lst))
     (car lst)
     (cons (+ (car lst) (cadr lst)) (cddr lst)))
    lst))
  (if (eq? sym 'final?);final?函数
   (lambda (lst) (not (pair? lst)))
   '())))

  然后测试一下((it make-sum-func) '(1 2 3 4 5)),得到最后结果15。

  上面两个函数写在一起,我们还可以再分离一下。

;定义一个打包函数
(define (wrap-next-final next final?)
 (lambda (sym)
  (if (eq? sym 'next)
   next
   (if (eq? sym 'final?)
    final?
    '()))))

;下面next和final?两个函数可以分开写
(define make-sum-next
 (lambda (lst)
  (if (pair? lst)
   (if (null? (cdr lst))
    (car lst)
    (cons (+ (car lst) (cadr lst)) (cddr lst)))
   lst)))

(define make-sum-final?
 (lambda (lst) (not (pair? lst))))

;于是函数就可以下面这样表示
(define make-sum-func (wrap-next-final make-sum-next make-sum-final?))

  总而言之,装饰器就是这样一类算子。

  Python也是这样,只是Python提供了@这样的语法,实际上是个语法糖,与其说是简写,倒是更像是个语法提醒这是一个装饰器。

  我们这次希望来显示一下mysym,还是用求和。

  先写一个简单的mysum函数用于求和: 

def mysum(*args):
    ret = 0
    for i in args:
        ret += i
    return ret

  做一个算子,来扩充它的输入参数:

  这里需要用来判断一个对象是否是可迭代对象,

from collections import Iterable

  然后,如果判断对象x是否是可迭代对象,只需要:

isinstance(x, Iterable)

  算子如下:

from collections import Iterable
def args_expan(f):
    def f2(*args):
        lst = []
        for i in args:
            if isinstance(i, Iterable):
                lst.append(f(*i))
            else:
                lst.append(i)
        return f(*lst)
    return f2

  然后在mysum前添加装饰器标志

@args_expan
def mysum(*args):
    ret = 0
    for i in args:
        ret += i
    return ret

  测试如下:

print(mysum(1,2,3,4,5))
print(mysum((1,2,3,4,5)))
print(mysum([1,2,3,4,5]))
print(mysum(range(1,6)))
print(mysum(map(lambda x:x+1, range(5))))
print(mysum(filter(lambda x:x<6, range(10))))

#构造了一个生成器
def gen_range(a, b):
    while a < b:
        yield a
        a += 1

print(mysum(\
    filter(lambda x:x<6, range(10)), \
    6, \
    [7,8], \
    (9, 10), \
    map(lambda x:x+11, range(10)), \
    gen_range(21,101)))

  运行得到:

15 15 15 15 15 15 5050

  终于看到,函数功能已被扩充。

  这个装饰器还可以装饰别的函数,比如乘积、统计等。

  从而,装饰器就是这样一个算子,一般用来改造函数的输入或输出,避免重复写代码。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 自然数到底可以表示到多大?

      小朋友都对巨大的数有一种天然的憧憬,以至于很多人都会想过这么一个问题,我们可以表示出多大的数?

    窗户
  • tensorflow的基本认识

      tensorflow是一个很流行的计算框架,目前主要用来做深度学习。但实际上,tensorflow不仅仅可以做深度学习,理论上说任何算法都可以用tensor...

    窗户
  • 高速网络包过滤

      WAF(Web Application Firewall, Web防火墙)的实现有多种手段,基于regex(Regular Expression,正则表达式...

    窗户
  • 使用责任链模式实现中间件功能

    其实中间件无非就相当于一个过滤器的东西,在框架中将 请求或者响应 进行一层层的过滤,实现这种功能最合适不过的就是责任链模式啦

    码缘
  • scrapy爬虫框架(一):scrapy框架简介

    安装完成后,python会自动将 scrapy命令添加到环境变量中去,这时我们就可以使用 scrapy命令来创建我们的第一个 scrapy项目了。

    渔父歌
  • java增量发布工具

    有些公司由于没有使用maven作为构建工具,全量发布时没问题,而修改bug增量发布往往是将改动的代码手动编译后,从classes目录下拷贝到jar中然后再放到t...

    一笠风雨任生平
  • 速读原著-Android应用开发入门教程(应用程序包含的各个文件)

    Android 应用程序一般包含在一个单一的文件夹中,即每一个 Android 应用程序是一个独立的工程,包含了以下文件:

    cwl_java
  • Android框架RePlugin使用详解

    Android开发人员不多,又要求使用插件化开发的模式。(简单点讲就是自己需要写宿主APP,还有N多个插件需要开发)

    砸漏
  • 2021腾讯犀牛鸟精英工程人才培养计划常见问题解答

    ? 犀牛鸟精英工程人才计划FAQ Q1:“犀牛鸟精英人才培养计划”与 “犀牛鸟精英工程人才培养计划”和“犀牛鸟精英科研人才培养计划”是什么关系? A1:“犀牛...

    腾讯高校合作
  • 钥匙不在锁上

    我指导在职研究生论文。他们平时都有工作,只有周末来学校集中上课。我和院里许多老师一样,没有他们平时的教学任务,只负责指导毕业论文。

    王树义

扫码关注云+社区

领取腾讯云代金券