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装饰器的代码 ...
随机推荐
- c#-day01学习笔记
C#语言基础 .net之父--------安德斯/海尔斯伯格 .net是一个平台,一个集合,一个环境 .net出现的背景 .net的核心功能:能够在任何的时间,任何的地点,使用任何的设备,访问网络 . ...
- MySQL GROUP_CONCAT长度限制引发的一场灾难
GROUP_CONCAT函数是对查处的分组数据对于分组列相同的数据合并成一列用逗号隔开的函数. 但是该函数的长度有个默认限制,默认是1024个字符,超过就会截断,从而导致用count统计GROUP_C ...
- Java Knowledge series 4
JVM & Bytecode Has-a or Is-a relationship(inheritance or composition) 如果想利用新类内部一个现有类的特性,而不想使用它的接 ...
- http头部如何对缓存的控制
文章自于我的个人博客 使用缓存的目的就是在于减少计算,IO,网络等时间,可以快速的返回,特别是流量比较大的时候,可以节约很多服务器带宽和压力. 一个请求从缓存的方面来说,有三个过程. 本地检查缓存是否 ...
- Asp.Net实现伪静态(通过URLRewriter)
一.起因 最近一个项目要实现伪静态,之前没接触过,故一切从零开始,开始网上查资料,方法大概有三种,但是我都试了好几个,都失败了.望有建议的博友给点建议,这里我实现了一种方式,是通过微软URLRewri ...
- 自定义 sql Split函数 / 自定义mp_helptext查看存储
1. 分割函数: --Split 表函数将一个字符串按指定分隔符进行分割,返回一个表. create function split( ),--待分割字符串 )--分割符 ))) as begin ) ...
- win10下各种问题的解决办法
本来申请这个博客是为了写一些Java学习笔记的,但是鉴于我半年内无数次重装系统的惨痛经历,所以把win10系统的一些问题总结一下. 此账号密码:1994llz. 1.win10取消开机密码: http ...
- TP5.1:依赖注入、绑定一个类到容器里、绑定一个闭包到容器中
依赖注入 1.在application中创建一个文件夹,名字为commom,commom文件夹中创建被注入文件夹,在被注入文件夹中创建一个名为demo.php的文件 2.在demo.php中输入: 3 ...
- 如何使用Win32API绘制树
一.这个已经有几年时间了,刚开始学习charlie的<windows程序设计>的时候做的.现在看来,代码很乱,虽然后来还整理过几次,现在这方面没什么兴趣了,有兴趣的可自由下载. 二.绘制二 ...
- UVA 11983 Weird Advertisement
题意:求矩形覆盖k次以上的区域总面积. 因为k≤10,可以在线段树上维护覆盖次数为0,...,k, ≥k的长度数量. 然后就是一个离散化以后扫描线的问题了. 离散化用的是半开半闭区间,以方便表示没有被 ...