深入浅出 Python Decorators
原文
- 基础知识
- 回到 Decorators
- Decorator
- 为带参数的函数进行装饰
- 通用 decorator
- Chaining Decorators
- 带有参数的 decorator
- 几个跟 Class 相关的常用 Decorator
- classmethod 和 staticmethod
- property
装饰器 属于 metaprogramming 的一种,是在编译时一段程序尝试去修改另外一段程序的部分内容。
基础知识
在 python 中,everything 都是 objects。
Names 只是 tags bound to these objects。
甚至 classes,functions 都是 objects。
例如:
a = math.sin
,则a
就用了同sin
一样的功能;
然后math.sin
甚至可以指向其他函数,例如math.sin = func
,则math.sin
就变成了func
函数的功能
而此时a
仍然具有sin
函数的功能
函数可以作为参数传递给其他函数,例如map
, filter
, reduce
.
这些接受函数作为参数的函数被称为 higher order functions.
函数也可以作为返回值被返回,例如在上一节中提到的 Closure。
回到 Decorators
functions 和 methods 都被称为 callable,因为他们都可以被执行。
实际上,任何 object,只要实现了__call__()
方法,都是一个 callable。
所以,Decorator 就是一个返回 callable 的 callable。
Decorator 使用函数作为参数,增加一些功能做成一个新的函数,然后返回它。
def make_pretty(func):def inner():print("I got decorated")func()return innerdef ordinary():print("I am ordinary")>>> ordinary()
I am ordinary>>> # let's decorate this ordinary function
>>> pretty = make_pretty(ordinary)
>>> pretty()
I got decorated
I am ordinary
在上面的例子中,make_pretty()
就是一个Decorator。
Decorator 就像一个 wrapper 一样。
Decorator 就好像把传入的函数 “decorate/装饰” 了一番,然后又吐了出来。
@Decorator
python 中提供了一个更简单的使用 decorator 的方法,就是@符号:
@make_pretty
def ordinary():print("I am ordinary")
就等同于
def ordinary():print("I am ordinary")ordinary = make_pretty(ordinary)
注意,下面的例子中,重新赋值后的 ordinary 已经不是 def 定义的ordinary 了,而是一个经过 decorator 修饰的 ordinary。
因此上面的例子中,@符号直接创造了经过修饰的 ordinary,省去了中间的形式。
为带参数的函数进行“装饰”
例子
def divide(a, b):return a/b
上面的函数显然有缺陷,在 b == 0 时会 raise ZeroDivisionError,因此我们可以对之进行“装饰”:
def smart_divide(func):def inner(a,b):print("I am going to divide",a,"and",b)if b == 0:print("Whoops! cannot divide")returnreturn func(a,b)return inner@smart_divide
def divide(a,b):return a/b
经过修饰后,divide
在当 b == 0 时会警告,变成了一个没有返回值的函数(返回 None);在b != 0 时返回正常的结果,又是一个有返回值的函数。
当使用者调用 divide(n / m)
时,实际上是在调用一个内部函数 inner(n / m)
。
而该内部函数使用了原始的、未被“修饰”的函数,即作为参数传入的 func
,即写在@smart_divide下面的那个形式。
通用 decorator
你会发现,实际上inner()
函数使用了和原始的被修饰函数同样的参数。根据这个原理,我们可以写出更通用的格式:
def works_for_all(func):def inner(*args, **kwargs):print("I can decorate any function")return func(*args, **kwargs)return inner
那么这个 decorator 可以“修饰”任何函数。
Chaining Decorators
被“修饰”的函数可以再次被“修饰”,就成了 decorator 嵌套:
def star(func):def inner(*args, **kwargs):print("*" * 30)func(*args, **kwargs)print("*" * 30)return innerdef percent(func):def inner(*args, **kwargs):print("%" * 30)func(*args, **kwargs)print("%" * 30)return inner@star
@percent
def printer(msg):print(msg)
printer("Hello")
输出结果是:
******************************
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Hello
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
******************************
注意,@star 和 @percent 的前后顺序很重要!不然就是不一样的结果。
带有参数的 decorator
有时候你会看到下面的形式:
@decorator(param)
def func():pass
不要怕,根据其原理,那么就相当于:
def func():passfunc = decorator(param)(func)
可见,decorator
本身就是一个返回 Decorator 的 Decorator 函数。其形式诸如:
def decorator(argument):def real_decorator(function):def wrapper(*args, **kwargs):funny_stuff()something_with_argument(argument)function(*args, **kwargs)more_funny_stuff()return wrapperreturn real_decorator
几个跟 Class 相关的常用 Decorator
1. @classmethod 和 @staticmethod
- 在类中,normal method 也称为 instance method,定义 instance method 时,需要默认给定一个 self 参数,代表了实例本身。
class Date(object):def __init__(self, day=0, month=0, year=0):self.day = dayself.month = monthself.year = year>>> date1 = Date(6, 11, 2017)
- 在类中,还有一类 method 称为 class method,定义 class method 时,需要默认给定一个 cls 参数,代表了类本身。
...@classmethoddef from_string(cls, date_as_string):day, month, year = map(int, date_as_string.split('-'))date1 = cls(day, month, year)return date1date2 = Date.from_string('11-09-2012')
因为在 python 中没有 重载/Overloading,所以不能用 date2 = Date('11-09-2012')
的形式定义另外一个构造函数,因此需要类提供新的方法来进行“构造”。
在上面的例子中,@classmethod 为该类引入了一个新方法 from_string
。
@classmethod 修饰符是必须的,否则,如果没有这个修饰符,即使你为 from_string
写了 cls
作为一参,它实际上仍然是意义上的 self
,并且你只能通过 = Date().from_string(...
的形式使用它。
- 在类中,还有一类 method 是 static method,它对应于 C++ 中的 static method,其实就是一个普通的函数,只不过被包含在了类中,此时”类”的作用仅仅是作为一个 naming space.
...@staticmethoddef is_date_valid(date_as_string):day, month, year = map(int, date_as_string.split('-'))return day <= 31 and month <= 12 and year <= 3999# usage:
is_date = Date.is_date_valid('11-09-2012')
同样,该方法不需要任何类的实例就可以直接使用。
当然,对于 class method 和 static method,你通过类的实例使用也是没问题的,即 is_date = Date().is_date_valid('11-09-2012')
也合法,但没人这样用,因为它使得 class method 和 static method 的含义变得模糊了。
2. @property
见下一节
深入浅出 Python Decorators相关推荐
- 回归素材(part10)--深入浅出python机器学习
学习笔记,仅供参考,有错必纠 文章目录 深入浅出python机器学习 线性回归 基本原理 使用 L 2 L_2 L<
- python getattr_深入浅出Python模块
引言 上周发表了<老胡讲Python>系列第一篇,得到了很多的关注.在第一篇中,大家表示对模块不是很明白,而模块的概念在Python中是十分重要的,于是今天带来<老胡讲Python& ...
- 《深入浅出Python量化交易实战》:散户也能学会的数字化交易策略
前言 您可能不知道,许多专业的交易机构已经采用设定程序完成自动化交易,通过机器语言,解密盘面的走势,从而实现持续盈利的目的. (文末送读者福利) 这并非什么秘密,他们正是借助了这样的数字化工具进行操作 ...
- 《深入浅出Python》与《Python网络数据采集》读后感
本学期在课程之外,自主计划学习Python语言以及爬虫知识.书籍方面,采用了O`Reilly的<深入浅出Python>与<Python网络数据采集>.前者用于Python语法的 ...
- 深入浅出python系列(三):逻辑判断语句
深入浅出python系列: 深入浅出python系列(一):基本数据类型 深入浅出python系列(二):运算符 [版权申明]未经博主同意,谢绝转载!(请尊重原创,博主保留追究权): 本博客的 ...
- 学习《深入浅出python量化交易交易实战》第一章(笔记)
1.学习<深入浅出python量化交易交易实战>第一章 记录学习过程中的代码和一些坑 1.1 基础(名词解释) 1.1.1 CAPM (Capital Asset Pricing Moda ...
- Python应用实战案例-深入浅出Python随机森林预测实战(附源码)
前言 组合算法也叫集成学习,在金融行业或非图像识别领域,效果有时甚至比深度学习还要好.能够理解基本原理并将代码用于实际的业务案例是本文的目标,本文将详细介绍如何利用Python实现集成学习中随机森林这 ...
- 深入浅出 python epub_《机器学习从认知到实践(第2辑)(套装共3册,Python+TensorFlow)》epub+mobi+azw3...
套装书目 · · · · · · <Python机器学习实践指南> <TensorFlow机器学习项目实战> <TensorFlow技术解析与实战> 分册简介 ...
- 原理+代码|深入浅出Python随机森林预测实战
点击上方"Python爬虫与数据挖掘",进行关注 回复"书籍"即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 寒梅最堪恨,长作去年花. 前言 组 ...
- 机器学习 python_送书 | 深入浅出Python机器学习
大家好,我是村长, 为了感谢您一直以来的关注与支持,给大家送了点福利! 以后每周三都会送免费送技术书!您有哪方面技术书籍的需求,也可以微信告诉我~~本周送的书籍如下,后台回复 送书 参与 书籍简介 ...
最新文章
- 面试题--特别是字节对齐
- 石川es6课程---9、面向对象-基础
- 5、Power Map—实例:填充地图
- java泛型的作用和实现原理_java泛型的作用及实现原理
- redis6持久化主从复制
- sql server 2008安装需要一直重启。但重启后又没有达到效果。
- C++ list,STL list
- 赚钱真的要抓住风口,抓住风口猪都能飞
- php 删除 session 文件,如何删除php中的session文件
- xv6 System Call
- cad插件加载bplot成功用不了_Batchplot批量打印命令无效,对照情况进行解决
- android百度经纬度转gps坐标,GPS经纬度怎么转百度经纬度
- 单路电压表c语言编程,基于ADC0809和AT89S52单片机的数字电压表的设计
- Tether市值十月下跌超过10亿美元
- Linux系统的基本使用指南(速成,帮助快速上手使用Linux系统)
- 计算广告(3)----搜索广告召回匹配
- 想自由查看自己网站每个页面流量情况?这个工具可以满足需求!
- 【分享-免费OCR工具 在线+移动端】免费在线图片多国文字识别
- 生于80年代需读的80本书
- Mysql优化——唯一索引和普通索引的选择