情景介绍

一天,在你正在努力加班的时候,老板给交给你了一个任务,就是在这段代码里将所有函数开始输出一个‘hello’最后输出当前时间,再输出一个“end”,这段代码里包含了大量的函数,你会怎么做?

def f1():
print('proces a') def f2():
print('proces b') def f3():
print('proces c') def f4():
print('proces d') ...
...

刚拿到这个任务,我们可能想着这样做,在每个函数中添加相应的输出语句,这样就能完成任务。

import datetime

def f1():
print('hello')
print('proces a')
print('datetime.datetime.now()')
print('end')
  
def f2():
print('hello')
print('proces b')
print('datetime.datetime.now()')
print('end') def f3():
print('hello')
print('proces c')
print('datetime.datetime.now()')
print('end') def f4():
print('hello')
print('proces d')
print('datetime.datetime.now()')
print('end')
...
...

到我们进行实施的时候我们发现这样写,太麻烦,每一个函数最后都要添加一遍,于是,我们就想到了另一个方法,就是写一个函数,添加在每个函数中。

import datetime

def hel():
print('hello')
print(datetime.datetime.now())
print('end') def f1():
print('hello')
print('proces a')
hel() def f2():
print('hello')
print('proces b')
hel() def f3():
print('hello')
print('proces c')
hel() def f4():
print('hello')
print('proces d')
hel() ...
...

但是我们发现在开始输出的hello还是要添加在每个函数中,这样还是麻烦,为了解决这个问题就要讲讲装饰器了。

装饰器介绍

  装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。

简单装饰器

  就将开始那个问题来使用装饰器解决一下。

import datetime

def hel(func):
def inner():
print('hello')
r = func()
print(datetime.datetime.now())
print('end')
return r
return inner @hel
def f1():
print('proces a') @hel
def f2():
print('proces b') @hel
def f3():
print('proces c') @hel
def f4():
print('proces d') f1()
f2()
f3()
f4() 执行结果:
hello
proces a
2018-06-24 18:03:21.903651
end
hello
proces b
2018-06-24 18:03:21.915651
end
hello
proces c
2018-06-24 18:03:21.915651
end
hello
proces d
2018-06-24 18:03:21.915651
end

是不是使用装饰器相对于之前的写法简单。

针对上面的代码进行解析:

  装饰器符号“@”属于语法糖,@修饰符必须出现在函数定义前一行,将下面的函数的名作为参数,不允许和函数定义在同一行。

  在上面的代码中,func就是指f1、f2、f3、f4函数,以f1为例,将f1函数作为参数传入hel函数中,在hel函数中再定义一个inner()函数,在inner函数中,首先执行一个print('hello'),在执行f1函数兵将返回值赋值给r,接下来输出时间以及end,最后返回r,inner函数的最后返回inner函数,当我们执行f1函数的时候,就相当于执行了inner函数,并且可以可以拿到f1函数的返回值。

使用装饰器传递参数

  上面使用的装饰器中,传入的函数没有带参数,当需要修饰的函数带有参数,我们就在装饰器中的inner函数添加相应的参数,在inner函数里面调用func函数的时候,再次传入。

def hel(func):
def inner(name):
r = func(name)
print('bye')
return r
return inner @hel
def f1(name):
print('hello')
print(name) name = 'alexsel'
f1(name) 输出结果:
hello
alexsel
bye

虽然这样我们就解决了参数的问题,但是我们这次传入的参数仅仅是字符串,如果是更加复杂的参数怎么办,这时候我们可以使用我们之前学习函数时候用到的一些可以接收多种类型的参数,*args,**kwargs,使用这两个参数之后我们可以接收任何类型的参数。

def hel(func):
def inner(*args,**kwargs):
r = func(*args,**kwargs)
print('bye')
return r
return inner @hel
def f1(name):
print('hello')
print(name) name = 'alexsel'
f1(name) 输出结果:
hello
alexsel
bye

到这里,简单的装饰器就讲完了,装饰器还有更高级的用法,下一篇,装饰器二会继续给大家讲解装饰器。

Python学习:10.Python装饰器讲解(一)的更多相关文章

  1. python学习之day5,装饰器,生成器,迭代器,json,pickle

    1.装饰器 import os import time def auth(type): def timeer(func): def inner(*args,**kwargs): start = tim ...

  2. Python学习——迭代器&生成器&装饰器

    一.迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素.迭代器仅 ...

  3. Python学习笔记012——装饰器

    1 装饰器 1.1装饰器定义 在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator). 1.2 装饰器分类 装饰器:函数装饰器,类装饰器,函数的装饰器,类的装饰器 装饰器:函数装饰函 ...

  4. python学习笔记(五):装饰器、生成器、内置函数、json

    一.装饰器 装饰器,这个器就是函数的意思,连起来,就是装饰函数,装饰器本身也是一个函数,它的作用是用来给其他函数添加新功能,比如说,我以前写了很多代码,系统已经上线了,但是性能比较不好,现在想把程序里 ...

  5. Python学习笔记:装饰器

    Python 装饰器的基本概念和应用 代码编写要遵循开放封闭原则,虽然在这个原则是用的面向对象开发,但是也适用于函数式编程,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即: 封闭:已 ...

  6. python学习笔记:装饰器2

    python的装饰器本质是函数,为了不改变装饰目标函数内部代码而增加额外功能而存在 一.一般装饰函数实例: import datetime def func_name(func):#定义一个装饰函数, ...

  7. 从零开始的Python学习Episode 11——装饰器

    装饰器 装饰器是用来处理其他函数的函数,主要作用是在不修改原有函数的情况下添加新的功能,装饰器的返回值也是一个函数对象. 简单的装饰器 import time def show_time(f): de ...

  8. Python学习系列之装饰器

    装饰器的作用 装饰器用于装饰某个函数.方法或者类,它可以让这个函数执行之前或者执行之后做一些操作 手工实现一个装饰器 def outer(some_func): #装饰器 $1 def inner() ...

  9. Python学习日记(九) 装饰器函数

    1.import time a.time.time() 获取到当前的时间,返回值为浮点型 import time print(time.time()) #1565422783.6497557 b.ti ...

  10. Python 学习 —— 进阶篇(装饰器、类的特殊方法)

    Python基础部分学完之后,在进入其OOP部分前,先理解一下其装饰器这种结构,其功能可类比于Java中的面向切面编程,下面参见具体实例: def log(f): def fn(x): print ' ...

随机推荐

  1. Razor模板引擎 (RazorEngine)

    Razor模板引擎不仅在ASP.NET MVC中内置了Razor模板引擎,还有一个开源的RazorEngine, 这样以来我们可以在非ASP.NET MVC项目中使用Razor引擎,甚至在控制台,Wi ...

  2. QT的QPropertyAnimation讲解

    m_pAnimation->setEasingCurve(QEasingCurve::Linear); //直线风格 m_pAnimation->setLoopCount(-1); //无 ...

  3. 双十一问题:kafka消费能力低下原因思考

    抛去cpu.内存等机器原因,在每个分区皆分配一个进程消费的情况下,利用扩机器来提高kafka消费速率已无能为力 此时发现,在实际洪峰时段的消费速率元达不到先前压测时的消费速率 原因思考: 1.洪峰时段 ...

  4. shell脚本中针对sudo等密码输入的问题解决方案

    一.不希望手动输入的办法 1.安装expect工具:sudo apt-get install tcl tk expect 2.脚本文件内容如下: #! /usr/bin/expectspawn sud ...

  5. android 智能提示

    <AutoCompleteTextView android:id="@+id/autoCompleteTextView" android:completionThreshol ...

  6. Vue通过input筛选数据

    <div id="app"> <input v-model='search' /> <ul> <li v-for="item i ...

  7. 17、配置嵌入式servlet容器(1)

    SpringBoot默认使用Tomcat作为嵌入式的Servlet容器 1).如何定制和修改Servlet容器的相关配置         1.修改和server有关的配置            (Se ...

  8. c#类中字段和方法中变量的声明问题

    字段和局部变量的作用域冲突 某些情况下可以区分名称相同,作用域相同的两个标识符.原因是C#在变量之间有一个基本的区分,它把在类级别声明的变量看作 字段,而把在方法中声明的变量看作局部变量. class ...

  9. SpringMVC关于请求参数乱码问题

    String names =request.getParameter("name") request主要接收的参数是form提交 form提交有的时候会伴随着乱码,该乱码的格式为I ...

  10. 十二、IntelliJ IDEA 中的版本控制介绍(中)

    由于 IntelliJ IDEA 支持的版本控制工具非常的多,但咱们真正能够用到的也就两三个而已,因此在本篇博文中,咱们主要介绍 SVN.Git 和 GitHub 的配置方法. SVN 如果想要在 I ...