欢迎添加华为云小助手微信(微信号:HWCloud002HWCloud003),输入关键字“加群”,加入华为云线上技术讨论群;输入关键字“最新活动”,获取华为云最新特惠促销。华为云诸多技术大咖、特惠活动等你来撩

关于诉求

昨天简单聊了下Flask的学习感想,然后分享了一些Flask的学习方式与视频。其中提到在学习Python Web前,请先将python基础及装饰器等知识有一个了解,这样学习起来不至于太过吃力。


然后,今天有朋友私信说对python的类和装饰器不甚了解,希望能讲讲这些知识。关于函数、方法、类,我之前发过一篇文章,就不再赘述了。其实去年详细总结过一篇关于Python装饰器的文章,只不过是在公司博客写的,没办法复制出来,所以今天就这之前的知识做一个总结和复习吧。

引子

谈及python装饰器,很多人第一时间想到的是@这个符号。在方法上一行加上@decorator就行了。但很多人看着都会、一用就跪,而且很多时候,我们都不知道什么场景下适合使用装饰器。那么今天就带大家一步步了解装饰器的使用吧

装饰器(Decorator)是python的一个重要部分,简单来说,他是修改其他函数功能的函数。

他们有助于让我们的代码更简短,也更Pythonic!

万物皆对象

在Python的世界中,万物皆对象,听起来比较抽象,但其实理解起来很简单,你可以用将任何一个变量、函数、方法、类等等赋值给另一个变量。只有你了解了这些,才能进一步的理解装饰器。

函数赋值

而学习装饰器前,我们先来举一个简单的函数例子:

def hello(name='BreezePython'):
return "say hello to {}".format(name) hello()
# 'say hello to BreezePython' hi = hello hi('tommorow')
# 'say hello to tommorow'

我们首先创建一个hello的函数,然后调用,之后将hello赋值给hi,之后调用hi,完成了相同的操作,也许你觉得这个例子so easy,那就接着往下走。

函数嵌套

当我们在函数中再次定义一个函数是,即完成了一个函数的嵌套操作:

def hello():
print('is hello function...') def hi():
return 'hi ,nice to meet you!' def bye():
return 'bye,stranger...' print(hi())
print(bye()) hello()
output:
is hello function...
hi ,nice to meet you!
bye,stranger... hi()
output:
Traceback (most recent call last):
File "<input>", line 1, in <module>
NameError: name 'hi' is not defined

上面的例子看到了,函数中可以调用子函数,但如果你直接去调用子函数,则会抛出未定义的异常,那么我们如何调用子函数?

函数中返回函数

让我们由浅入深,先考虑从函数中返回函数

def hello(name=None):
print('is hello function...') def hi():
return 'hi ,nice to meet you!' def bye():
return 'bye,stranger...' if name == 'BreezePython':
return hi
else:
return bye main = hello('BreezePython')
>>> output: is hello function...
main()
>>> output: 'hi ,nice to meet you!'

初学者可能对python中的小括号有些迷糊,添加小括号与否有什么影响呢?

当你在函数或者实例化的对象后添加小括号,代表立即执行;

然而,当你不添加小阔爱好时,他可以被到处传递,并可以复制给变得变量而不去执行它。

函数作为参数传递

def child():
return 'is child function...' def main(func):
print('is main function...')
print(func()) main(child) output:
>>> is main function...
>>> is child function...

我们新建了一个child函数,然后将child话术传递给main函数,在main函数中调用child函数,达到了将函数作为参数传递的结果。

python闭包

我们先将上面的函数嵌套与传参来进行一下合并:

def main(func):
print('is main function...') def child():
print('it print before exec func...')
func()
print('it print after exec func...')
return child def alone():
print("I'm alone function ...") fix = main(alone)
fix() output:
>>> is main function...
>>> it print before exec func...
>>> I'm alone function ...
>>> it print after exec func...

通过合并,我们将上面两个例子进行和组装,变成了一个升级版的闭包,很多人会说,什么是闭包呢?其实很简单…

我们可以将闭包理解为一种特殊的函数,这种函数由两个函数的嵌套组成,

且称之为外函数和内函数,外函数返回值是内函数的引用,此时就构成了闭包。

first Decorator

上面的例子中,我们看到了一个闭包与函数传参的例子,那么装饰器是什么?其实就是闭包+函数传参,如果上面的例子你看懂了,那么现在你只需要对代码格式稍作修改,就变成了一个装饰器!

def main(func):
print('is main function...') def child():
print('it print before exec func...')
func()
print('it print after exec func...') return child @main
def alone():
print("I'm alone function ...") alone() # output:
>>> is main function...
>>> it print before exec func...
>>> I'm alone function ...
>>> alone
>>> it print after exec func...

我们只是修改了一行代码的格式,就转化成了装饰器,@main就代表func = main(func)

可这样就算完美的装饰器了么?NO….

我们将alone函数稍作变更,即可看出问题所在:

def alone():
print("I'm alone function ...")
print(alone.__name__)

正常情况下,调用alone带引的alone.__name__就是函数名即alone,但如果我们是通过装其实调用后打印呢,结果是什么?相信大家能猜到,是child。child是main函数的内建函数,它重写了我们的函数名,如何解决这个问题呢?

使用functools.wraps

from functools import wraps

# first Decorator
def main(func):
print('is main function...') @wraps(func)
def child():
print('it print before exec func...')
func()
print('it print after exec func...') return child @main
def alone():
print("I'm alone function ...")
print(alone.__name__) alone() # output:
>>> is main function...
>>> it print before exec func...
>>> I'm alone function ...
>>> alone
>>> it print after exec func...

我们通过引入functools方法中的wraps,保证了函数名称的原始性

@wraps接受一个函数,进行装饰,并加入了复制函数名称、注释文档、参数列表等功能,这样可以是我们在装饰器里面访问在装饰之前的函数的属性

装饰器实例

装饰器比大量的使用在Flask、Django中,学好了它不管是对于你理解flask的路由,还是之后的代码开发都有很多帮助,那么我们来做个简单的例子,日志打印装饰器:

import time
from functools import wraps def log_level(level='DEBUG'):
def log_format(func):
@wraps(func)
def format(*args, **kwargs):
logtime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
print("[{}]{}: ".format(level, logtime), end='')
return func(*args, **kwargs) return format return log_format @log_level()
def log1():
print("Hello,Welcome to 清风Python...") @log_level('ERROR')
def log2():
print("清风Python 是我的公众号...") log1()
time.sleep(1)
log2() # output:
>>> [DEBUG]2019-08-20 01:24:23: Hello,Welcome to 清风Python...
>>> [ERROR]2019-08-20 01:24:24: 清风Python 是我的公众号...

类的装饰器

讲了这么多,本来觉得该结束了,可总觉得还差点什么!没错,我们只是讲到了函数的装饰器,那么类的装饰器该如何操作呢?

import time
from functools import wraps class Logger:
def __init__(self,level='DEBUG'):
self.level = level def __call__(self, func):
@wraps(func)
def log_format(*args, **kwargs):
log_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
print("[{}]{}: ".format(self.level, log_time), end='')
return func(*args, **kwargs)
return log_format @Logger()
def log1():
print("Hello,Welcome to 清风Python...") @Logger('Error')
def log2():
print("清风Python 是我的公众号...") log1()
time.sleep(1)
log2() # output:
>>> [DEBUG]2019-08-20 01:24:23: Hello,Welcome to 清风Python...
>>> [ERROR]2019-08-20 01:24:24: 清风Python 是我的公众号...

今天的装饰器内容就分享到这里吧…

The End

OK,今天的内容就到这里,如果觉得内容对你有所帮助,欢迎点击文章右下角的“在看”。

期待你关注我的公众号清风Python,如果觉得不错,希望能动动手指转发给你身边的朋友们。

作者:清风Python

Python装饰器总结,带你几步跨越此坑!的更多相关文章

  1. [python 基础]python装饰器(二)带参数的装饰器以及inspect.getcallargs分析

    带参数的装饰器理解无非记住两点: 1.本质不过在基本的装饰器外面再封装一层带参数的函数 2.在使用装饰器语法糖的时候与普通装饰器不同,必须要加()调用,且()内的内容可以省略(当省略时,admin默认 ...

  2. Python装饰器实现带参数和不带参数

    1 def log(text=None): 2 3 if isinstance(text, str): 4 def decorator(func): 5 @functools.wraps(func) ...

  3. 【转】九步学习python装饰器

    本篇日志来自:http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html 纯转,只字未改.只是为了学习一下装饰器.其实现在也是没有太看明白 ...

  4. Python高级特性: 12步轻松搞定Python装饰器

    12步轻松搞定Python装饰器 通过 Python 装饰器实现DRY(不重复代码)原则:  http://python.jobbole.com/84151/   基本上一开始很难搞定python的装 ...

  5. python 装饰器 (多个参数的函数,带参数的装饰器)

    最简单的模板是这样的 #-*-coding:utf-8-*- def outer(func): def inner(): print 'before' func() print 'after' # r ...

  6. Python 装饰器学习

    Python装饰器学习(九步入门)   这是在Python学习小组上介绍的内容,现学现卖.多练习是好的学习方式. 第一步:最简单的函数,准备附加额外功能 1 2 3 4 5 6 7 8 # -*- c ...

  7. (转载)Python装饰器学习

    转载出处:http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html 这是在Python学习小组上介绍的内容,现学现卖.多练习是好的学习方 ...

  8. Python装饰器学习

    Python装饰器学习(九步入门)   这是在Python学习小组上介绍的内容,现学现卖.多练习是好的学习方式. 第一步:最简单的函数,准备附加额外功能 ? 1 2 3 4 5 6 7 8 # -*- ...

  9. 自创最精简的python装饰器

    个人心血原创,欢迎转载,请注明作者和出处.否则依法追究法律责任!!!! author:headsen  chen date:2018-03-21  10:37:52 代码: 代码解析过程:1,def ...

随机推荐

  1. Python文字转换语音,让你的文字会「说话」,抠脚大汉秒变撒娇萌妹

    作者 | pk 哥 来源公众号 | Python知识圈(ID:PythonCircle) APP 也有文字转换为语音的功能,虽然听起来很别扭,但是基本能解决长辈们看不清文字或者眼睛疲劳,通过文字转换为 ...

  2. Project Euler 51: Prime digit replacements

    通过替换*3这样一个两位数的第一位,我们可以发现形成的九个数字有六个是质数,即13, 23,43,53,73,83.类似的,如果我们用同样的数字替换56**3这样一个五位数的第三位和第四位,会生成56 ...

  3. [转载]2.1 UiPath条件判断活动If的介绍和使用

    一.if的介绍 if语句是指编程语言(包括c语言.C#.Python.Java.汇编语言等)中用来判定所给定的条件是否满足,根据判定的结果(真或假)决定执行给出的两种操作之一. 二.if在UiPath ...

  4. Helm 3 发布 | 云原生生态周报 Vol. 27

    作者 | 墨封.元毅.冬岛.敖小剑.衷源 业界要闻 1.Helm 3 发布 美国时间 11 月 13 日,Helm 团队发布 Helm 3 第一个稳定版本.Helm 3 以 Helm 2 的核心特性为 ...

  5. 009-2010网络最热的 嵌入式学习|ARM|Linux|wince|ucos|经典资料与实例分析

    前段时间做了一个关于ARM9 2440资料的汇总帖,很高兴看到21ic和CSDN等论坛朋友们的支持和鼓励.当年学单片机的时候datasheet和学习资料基本都是在论坛上找到的,也遇到很多好心的高手朋友 ...

  6. html与css连接代码

    demo01.html: <!DOCTYPE html><html> <head>  <meta charset="utf-8">  ...

  7. java笔试面试第二天

    没想到第二次面试到了第二周,也是我在上海找工作的第二周,说实话,没有真本事找工作是真的难,虽然正在召开的十九大上,大大们纷纷表态国力正盛,经济稳步增长,就业压力逐渐缓解,但是社会终究是社会,要么靠实力 ...

  8. Typings移除Deprecated Warning

    使用TypeScript进行开发中,经常遇到如下的Deprecated Warning.虽然没有实际影响,但看多了,确实挺烦. 要想消除这些Warning,需要以下几个步骤: 步骤一,确认Warnin ...

  9. xposed实现个人收款免签支付

    想必很多程序员都有这样的烦恼,想做个人网站,但如何实现收款功能? 今天我就给大家分享一下我的实现方案:基于xposed逆向框架实现微信免签支付.支付宝免签支付 接下来给大家简单分享一下实现过程,这个过 ...

  10. [JQuery] JQuery学习笔记

    1.2019年10月20日14:43:48 学习HOW2J. 2.JQuery是一个javascript的框架,是对javascript的一种封装, 通过JQuery可以非常方便的操作html的元素 ...