Python生成器、装饰器
## 生成器
- 生成器是用来创建Python序列的一个对象
- 通常生成器是为迭代器产生数据的
- 例如range()函数就是一个生成器
- 每次迭代生成器时,它都会记录上一次调用的位置,并返回下一个值,这使程序不需要创建和存储完整的序列
## 生成器函数
- 生成器函数与普通函数类似,但它的返回值使用yield语句,而不是return
def my_range(start=0, last=10, step=1):
number = start
while number < last:
yield number
number += step my_range # 是一个普通函数
# <function my_range at 0x7efe3dbf2e18> my_range() # 返回一个生成器对象
# <generator object my_range at 0x7efe3daac360> list(my_range(1, 10))
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
## 装饰器
- 装饰器的作用在于在不改变原有代码结构的前提下,对原有代码的功能进行补充扩展
- 装饰器的本质上是接受函数为参数的高阶函数,它把一个函数作为参数输入并且返回一个功能拓展后的新函数
# 装饰器函数,为函数添加两条语句
def deco(fn):
def new_func(*args): # 内部函数的参数需要与传入的fn的参数相同
print("执行函数:{0}".format(fn.__name__))
result = fn(*args)
print("函数执行结果:{0}".format(result))
return result
return new_func @deco # 使用@装饰函数名,使用装饰器之后,add实际上已经指向了doco函数返回的新函数
def add(*args):
print("我是核心代码,可不能改动我")
result = 0
for n in args:
result += n
return result add(1, 2, 3, 4)
"""
执行结果:
执行函数:add
我是核心代码,可不能改动我
函数执行结果:10
"""
- 一个函数可以有多个装饰器
- 最靠近函数的装饰器会先执行,然后一次向上执行装饰器
def count_param(fn):
def new_func(*args):
amount = len(args)
fn(*args)
print("参数个数为:{0}".format(amount))
return amount
return new_func @count_param
@deco
def add(*args):
print("我是核心代码,可不能改动我")
result = 0
for n in args:
result += n
return result add(1, 2, 3, 4)
"""
执行结果:
执行函数:add
我是核心代码,可不能改动我
函数执行结果:10
参数个数为:4
"""
- 如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数
import time def log(now_time):
def deco(fn):
def new_func(*args, **kwargs):
print(now_time)
return fn(*args, **kwargs)
return new_func
return deco @log(time.asctime(time.localtime(time.time())))
def add(*args):
print("我是核心代码,可不能改动我")
result = 0
for n in args:
result += n
return result add(1, 2, 3, 4)
"""
执行结果:
函数开始时间:Sun Jul 1 15:30:14 2018
我是核心代码,可不能改动我
"""
- 此时打印add函数的__name__属性发现:
print("核心函数名:{0}".format(add.__name__))
"""
输出:
核心函数名:new_func
"""
- 这表明虽然装饰器表面上并没有改变核心函数的内容,但实际上还是对核心函数的属性进行了修改,所以还需要将核心函数的__name__属性复制到新函数
import time def log(now_time):
def deco(fn):
def new_func(*args, **kwargs):
# 将原函数的__name__属性复制到新函数
new_func.__name__ = fn.__name__
print(now_time)
return fn(*args, **kwargs)
return new_func
return deco @log(time.asctime(time.localtime(time.time())))
def add(*args):
print("我是核心代码,可不能改动我")
result = 0
for n in args:
result += n
return result add(1, 2, 3, 4)
print("核心函数名:{0}".format(add.__name__))
"""
执行结果:
Sun Jul 1 15:43:00 2018
我是核心代码,可不能改动我
核心函数名:add
"""
- 在functools里面有一个专门的函数处理这个问题
import time
import functools def log(now_time):
def deco(fn):
@functools.wraps(fn) # 在新的函数上添加装饰器,修改新函数的__name__属性
def new_func(*args, **kwargs):
print(now_time)
return fn(*args, **kwargs)
return new_func
return deco @log(time.asctime(time.localtime(time.time())))
def add(*args):
print("我是核心代码,可不能改动我")
result = 0
for n in args:
result += n
return result add(1, 2, 3, 4)
print("核心函数名:{0}".format(add.__name__))
”“”
执行结果:
Sun Jul 1 15:48:10 2018
我是核心代码,可不能改动我
核心函数名:add
“”“
- 类装饰器
class Test(object):
def __init__(self, fn):
self.fn = fn # 重写__call__函数,使实例能够像函数一样调用
def __call__(self, *args, **kwargs):
print("这是基于类的修饰")
return self.fn(*args, **kwargs) @Test
def core_func(a, b):
return a + b print(core_func(2, 3))
"""
输出:
这是基于类的修饰
5
"""
- 类装饰器带参数
import datetime
import functools class Test(object):
def __init__(self, log):
self.log = log # 重写__call__函数,使实例能够向函数一样调用
def __call__(self, fn):
@functools.wraps(fn) # 同样在这里使用functools.wraps(),将原函数__name__属性复制到新函数
def wrapper(*args, **kwargs):
print(self.log)
print("执行函数:%s" % fn.__name__)
return fn(*args, **kwargs)
return wrapper @Test(datetime.datetime.now())
def core_func(a, b):
return a + b @Test(datetime.datetime.now())
def say_hi():
print("Hi") print(core_func(2, 3))
print(core_func.__name__) # 输出:core_func
say_hi()
print(say_hi.__name__) # 输出:say_hi
"""
输出:
2018-07-02 10:55:27.258637
执行函数:core_func
5
core_func
2018-07-02 10:55:27.258696
执行函数:say_hi
Hi
say_hi
"""
本文参考:
[美]Bill Lubanovic 《Python语言及其应用》
https://www.liaoxuefeng.com 廖雪峰的官方网站
Python生成器、装饰器的更多相关文章
- Python学习---装饰器/迭代器/生成器的学习【all】
Python学习---装饰器的学习1210 Python学习---生成器的学习1210 Python学习---迭代器学习1210
- Python之装饰器、迭代器和生成器
在学习python的时候,三大“名器”对没有其他语言编程经验的人来说,应该算是一个小难点,本次博客就博主自己对装饰器.迭代器和生成器理解进行解释. 为什么要使用装饰器 什么是装饰器?“装饰”从字面意思 ...
- Python基础-迭代器&生成器&装饰器
本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 1.列表生成式,迭代器&生成器 列表生成式 我现在有个需求,看 ...
- Python 迭代器&生成器,装饰器,递归,算法基础:二分查找、二维数组转换,正则表达式,作业:计算器开发
本节大纲 迭代器&生成器 装饰器 基本装饰器 多参数装饰器 递归 算法基础:二分查找.二维数组转换 正则表达式 常用模块学习 作业:计算器开发 实现加减乘除及拓号优先级解析 用户输入 1 - ...
- 迭代器/生成器/装饰器 /Json & pickle 数据序列化
本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 1.列表生成式,迭代器&生成器 列表生成式 孩子,我现在有个需 ...
- Python各式装饰器
Python装饰器,分两部分,一是装饰器本身的定义,一是被装饰器对象的定义. 一.函数式装饰器:装饰器本身是一个函数. 1.装饰函数:被装饰对象是一个函数 [1]装饰器无参数: a.被装饰对象无参数: ...
- Python札记 -- 装饰器补充
本随笔是对Python札记 -- 装饰器的一些补充. 使用装饰器的时候,被装饰函数的一些属性会丢失,比如如下代码: #!/usr/bin/env python def deco(func): def ...
- python基础——装饰器
python基础——装饰器 由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数. >>> def now(): ... print('2015-3-25 ...
- 【转】详解Python的装饰器
原文链接:http://python.jobbole.com/86717/ Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现 ...
- 两个实用的Python的装饰器
两个实用的Python的装饰器 超时函数 这个函数的作用在于可以给任意可能会hang住的函数添加超时功能,这个功能在编写外部API调用 .网络爬虫.数据库查询的时候特别有用 timeout装饰器的代码 ...
随机推荐
- AngularJS directive 动态 template
app.directive('testwindow', function() { return { restrict : 'E', template: '<ng-include src=&quo ...
- 【防火墙】DMZ
DMZ是英文“demilitarized zone”的缩写,中文名称为“隔离区”,也称“非军事化区”.它是为了解决安装防火墙后外部网络的访问用户不能访问内部网络服务器的问题,而设立的一个非安全系统与安 ...
- Hosted Services+Quartz实现定时任务调度
背景 之前.net core使用quartz.net时,总感觉非常变扭,百度和谷歌了N久都没解决以下问题,造成代码丑陋,非常不优雅: 1.项目启动时,要立刻恢复执行quartz.net中的任务 2.q ...
- python面试题——爬虫相关
1.接触过几种爬虫模块 urllib.requests这两种爬虫模块. 2.robots协议是什么? 它就是一个防君子不防小人的协议,网站有一些数据不想被爬虫程序爬取,可以编写robots协议文件,明 ...
- 从零开始的全栈工程师——js篇(正则表达式)
正则 就是一条规则 用来检验字符串的格式 目标就是字符串 只要是通过表单提交的数据 都是字符串1.正则定义var reg = new RegExp( )var reg = /格式/ <--简写 ...
- SpringMVC快速入门
导入开发包 前6个是Spring的核心功能包[IOC],第7个是关于web的包,第8个是SpringMVC包 org.springframework.context-3.0.5.RELEASE.jar ...
- check_mk 之 Check Parameters
配置检测参数有几下方法 1. Creating manual checks instead of inventorized checks (using the variable checks). 2. ...
- EasyUI手风琴 Tab卡使用
--案例项目代码,初始化手风琴,定义打开Tab的方法. $(result).each(function () { //m_pi_jscode,pi_jscode if (m_pi_id != this ...
- 双网卡(一外一内)都启用,将内网卡默认网关去除即可正常连接Internet
- ERROR 3077 (HY000): To have multiple channels, repository cannot be of type FILE; Please check the repository configuration and convert them to TABLE.
在5.7.16搭建多源复制时,出现如下错误: mysql> change master to master_host='192.168.56.156',master_user='repl', ...