python中的那些“神器”
“武林至尊,宝刀屠龙,号令天下,莫敢不从,倚天不出,谁与争锋”,这是神器。不过今天要说的python中的“神器”就没有这么厉害了,这里要说的“神器”其实就是名称里面带了个“器”的,如下:
- 列表解析器
- 迭代器
- 生成器
- 装饰器
列表解析器
现在遇到了这样一个问题需要解决:“有一个数字的列表,要求对该列表中的奇数乘以2,返回处理完成后的列表(不改变原来列表的顺序,仅对列表中的奇数乘以2)”,比较传统的方法可能会是这样的:
def double_odd_number_list(odd_number_list):
ret_value = []
for number in odd_number_list:
if number % 2:
ret_value.append(number * 2)
else:
ret_value.append(number)
return ret_value
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
测试数据:
if __name__ == '__main__':
test_odd_number_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 24, 13, 28]
print double_odd_number_list(test_odd_number_list)
- 1
- 2
- 3
测试结果:
这样做对于新手来说比较容易理解,但代码不够精简,我们来看看列表解析器怎样完成上面的工作:
print [(number*2) if number % 2 else number
for number in test_odd_number_list]
- 1
- 2
代码说明:
- for number in test_odd_number_list迭代test_odd_number_list,对于test_odd_number_list中的每一个元素,如果为奇数(if分支)则往结果列表中放入number*2,否则放入number(else分支)
test_odd_number_list还是上面定义的,测试结果如下:
上面讲的可能还满足不了你全部的需求,比如下面的情况:
生成器表达式
列表解析器在生成的列表数据量很大时会占用很大的内存,它会一次性生成全部的数据保存到列表中并返回,无论是计算时间上还是内存消耗上,当数据量达到一定量级时都是无法接受的。一个改进方法就是使用生成器表达式,生成器表达式在语法上与列表解析唯一的区别就是讲[]换成了()。它会返回一个生成器,一次只计算一个值(延迟计算),如下图:
迭代器
迭代器的详细内容可以参照我的另外一篇博客《python的迭代器》
生成器
谈到生成器,不得不谈到python的一个关键字yield,python中关于生成器的定义是:“A function which returns an iterator”,该函数与普通还是除了包含yield关键字外没有任何区别。yield关键字的作用是挂起函数的执行,下次调用时所有环境恢复到挂起时的状态从挂起的地方继续执行,一般都是放到循环里。我们来看一个求阶乘的例子:
有几点需要作出说明:
- 一个生成器函数中可以有多个yield函数,像上例
- 函数执行的顺序跟普通函数一致,可以理解成yield就是一个return,但return后该函数就挂起在该点,下次调用该函数时继续从该点开始执行。例如factorial(2),函数会直接执行到while循环(因为n!=0),第一次循环到yield时ret *= i,计算的结果是1,返回1并挂起,此时i=1,ret等于1,再一次调用时从yield的下一行执行,i变成2,小于等于传入的n=2,继续循环(没有从函数的头部执行),再到yield时ret=2,返回2并挂起,依次类推
- 通常比较少用,我第一次在代码中看到是ceilometer(openstack一个子项目)中
装饰器
装饰器,装点门面用,此处的门面就是函数,用来装饰函数或者方法,在python中我们习惯性的把绑定到实例上的叫方法,未绑定的叫函数,也就是说在类里面第一个参数为self的就是方法,在模块中的就是函数。python中的装饰器有两种:带参数的装饰器,不带参数的装饰器
不带参数的装饰器
我们先从语法上相对简单的不带参数的装饰器讲起。我们在评估性能时,可能会精确到某个具体的函数执行一次需要花费的时间,新手最新想到的应该是写一个脚本,调用前和调用后分别获取一下当前时间,两者之差就是该函数执行所消耗的时间,代码可能是这样的:
def test(ret_value, sleep_time):
time.sleep(sleep_time)
return ret_value
if __name__ == '__main__':
start = datetime.datetime.utcnow()
test((1, 2, 3, 4, 5, 6), 3)
end = datetime.datetime.utcnow()
print (end - start).total_seconds()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
代码容易理解,但如果有很多个函数都需要做这种测试呢?是不是就需要重复写很多次的:
start = datetime.datetime.utcnow()
end = datetime.datetime.utcnow()
print (end - start).total_seconds()
- 1
- 2
- 3
如果你想成为一个优秀的程序员,那么,尽你所能去避免做重复的事情,让你写的每一行代码发挥最大的价值,下面来看一个使用装饰器的例子:
import datetime
import time
__author__ = 'Administrator'
def time_counter(func):
def doc_func(*args, **kwargs):
start = datetime.datetime.utcnow()
ret = func(*args, **kwargs)
end = datetime.datetime.utcnow()
return ret, start, end, (end - start).total_seconds()
return doc_func
@time_counter
def test(ret_value, sleep_time):
time.sleep(sleep_time)
return ret_value
if __name__ == '__main__':
print test((1, 2, 3, 4, 5, 6), 3)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
time_counter是一个装饰器,它跟普通函数的区别在于:
- 参数为函数对象(time_counter的参数func)
- 在函数里面定义了一个新的函数(time_counter中的doc_func),且该函数(time_counter中的doc_func)的参数列表与第1步中的函数对象(time_counter的参数func)的参数列表一致
- 函数最后返回了新定义的函数对象(time_counter中的doc_func)
@time_counter def func(*args, **kwargs):等价于func = time_counter(func)
在任何需要计算执行时间的函数上使用该装饰器即可,如下:
@time_counter
def test(ret_value, sleep_time):
time.sleep(sleep_time)
return ret_value
- 1
- 2
- 3
- 4
当执行test函数时,会先将test函数对象作为参数传递到time_counter装饰器,也就是形式参数func,然后依次执行定义的doc_func中的全部操作,其中调用func的地方(ret = func(*args, **kwargs))会调用test函数,下面是上述代码的执行结果:
带参数的装饰器
上面的装饰器,在使用时不需要传递任何参数,但有时这还不足以满足我们的需求,假设我们在一套测试框架中,测试用例可能有多种级别,完全测试时我们需要执行所有等级的测试用例,如果某次发布仅仅是修改了其中的一小块功能,对于未修改的部分,我们仅需要测试基本功能即可,例如级别大于等于2的。我们来看一下使用带参数的装饰器模拟实现该功能:
import datetime
import time
__author__ = 'Administrator'
def skip_unit_test(func):
print 'skip function:%s' % func.func_name
def unit_test_filter(level):
def new_decorator(func):
def final_func(*args, **kwargs):
if level >= 2:
start = datetime.datetime.utcnow()
ret = func(*args, **kwargs)
end = datetime.datetime.utcnow()
print ret, start, end, (end - start).total_seconds()
else:
skip_unit_test(func)
return final_func
return new_decorator
@unit_test_filter(0)
def test_level_zero(ret_value, sleep_time):
time.sleep(sleep_time)
return ret_value
@unit_test_filter(1)
def test_level_one(ret_value, sleep_time):
time.sleep(sleep_time)
return ret_value
@unit_test_filter(2)
def test_level_two(ret_value, sleep_time):
time.sleep(sleep_time)
return ret_value
@unit_test_filter(3)
def test_level_three(ret_value, sleep_time):
time.sleep(sleep_time)
return ret_value
if __name__ == '__main__':
test_level_zero((1, 2, 3, 4, 5, 6), 3)
test_level_one((1, 2, 3, 4, 5, 6), 3)
test_level_two((1, 2, 3, 4, 5, 6), 3)
test_level_three((1, 2, 3, 4, 5, 6), 3)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
看起来比较复杂,我们来总结一下带参数装饰器的特性:
- 是一个函数,有一个或者多个参数,返回一个定义的子函数对象
- 函数体中定义一个子函数,子函数的参数是函数对象,同“不带参数装饰器”中的func,子函数仍然返回定义的孙子函数对象
- 子函数中再定义一个孙子函数,孙子函数的参数列表与子函数参数func的参数列表一致,并在其中做一些处理,且最终会调用到被装饰的函数(单次装饰的函数可能不会被调用)
- 在使用时需要按照装饰器函数的参数列表来传递参数,如例子中的:
@unit_test_filter(0)等
下面附上上述例子的执行结果:
python中的那些“神器”的更多相关文章
- Python中两大神器&exec() &eval()
一.神器1 -- 内置函数eval eval是python中的内置函数,它的作用是将字符串变为所对应的表达式,也相当于一个功能代码加双引号变为字符串,而eval又将字符串转为相应的功能,它在使用过程中 ...
- Python中的可视化神器:pyecharts
pyecharts是一款将python与echarts结合的强大的数据可视化工具,本文将为你阐述pyecharts的使用细则 前言 我们都知道python上的一款可视化工具matplotlib,而前些 ...
- Python中的可视化神器!你知道是啥吗?没错就是pyecharts!
pyecharts是一款将python与echarts结合的强大的数据可视化工具,本文将为你阐述pyecharts的使用细则 前言 我们都知道python上的一款可视化工具matplotlib,而前些 ...
- python中的画图神器——turtle模块
turtle库的基础命令介绍(1)画布画布cancas是绘图区域,可以设置它的大小和初始位置 turtle.screensize(1000,600,'red') 大小的设置 turtle.setup( ...
- sqlalchemy python中的mysql数据库神器
在介绍sqlalchemy之前,我们先了解一下ORM. ORM 全称 Object Relational Mapping, 翻译过来叫对象关系映射.也就是说ORM 将数据库中的表与面向对象语言中的类建 ...
- 一句python,一句R︱python中的字符串操作、中文乱码
先学了R,最近刚刚上手python,所以想着将python和R结合起来互相对比来更好理解python.最好就是一句python,对应写一句R. pandas可谓如雷贯耳,数据处理神器. 以下符号: = ...
- 正则表达式与Python中re模块的使用
正则表达式与Python中re模块的使用 最近做了点爬虫,正则表达式使用的非常多,用Python做的话会用到re模块. 本文总结一下正则表达式与re模块的基础与使用. 另外,给大家介绍一个在线测试正则 ...
- 一句python,一句R︱python中的字符串操作、中文乱码、NaN情况
一句python,一句R︱python中的字符串操作.中文乱码.NaN情况 先学了R,最近刚刚上手Python,所以想着将python和R结合起来互相对比来更好理解python.最好就是一句pytho ...
- [转]Python中的str与unicode处理方法
早上被python的编码搞得抓耳挠腮,在搜资料的时候感觉这篇博文很不错,所以收藏在此. python2.x中处理中文,是一件头疼的事情.网上写这方面的文章,测次不齐,而且都会有点错误,所以在这里打算自 ...
随机推荐
- 【Cocos2d-X游戏实战开发】捕鱼达人之游戏场景的创建(六)
本系列学习教程使用的是cocos2d-x-2.1.4(最新版为cocos2d-x-2.1.5) 博主发现前两个系列的学习教程被严重抄袭,在这里呼吁大家请尊重开发者的劳动成果, 转载的时候请务必注 ...
- Ubuntu 配置Tomcat环境
1.下载Tomcat http://tomcat.apache.org/,下载Tomcat 8(由于目前最新eclipse不支持tomcat 9) 将下载的apache-tomcat-8.0.35.t ...
- Hibernate PO对象的状态
Hibernate的PO对象有三种状态:临时状态(又称临时态).持久状态(又称为持久态)和脱管状态(又称为脱管态.游离态).处理持久态的对象也称为PO,临时对象和脱管对象也称为VO. 1.临时态: 简 ...
- js校验
判空 function check(s) { return (s == null || typeof (s) == "undefined" || s == "" ...
- gradient杂谈
工作中难免遇到某些小项目中没有设计的情况,这对于PS基础薄弱的我来说非常恐怖.无奈之下,只好自己自学UI方面的知识,但对于某些能用CSS实现的背景样式等,还是尽可能地用已经掌握的知识去实现.本文主要分 ...
- MVC 错误处理1
实例1. /// <summary> /// 错误处理 /// 404 处理 /// </summary> protected void Application_Error(o ...
- Git应用于Android项目的入门知识:我的理解
Git应用于Android项目的基本知识. 常常将git,repo和gerrit三种工具配合起来使用,使Android开发中的部分工作自动化.并适应敏捷项目管理的需要. repo是Go ...
- ORA-00937:不是单组分组函数_Oracle
Demo: SELECT USER_ID, USER_NAME, USER_SEX, MAX(USER_AGE), SUM(USER_MONEY) AS USER_MONEY USER_TEL, US ...
- 7、Khala设备资源的申请和释放
在实际业务中,我们每次登录后,可能需要在服务端维护一些设备相关的资源信息,而不同设备所需维护的资源信息又不尽相同.Khala提供了设备资源的维护储存功能,在此我们通过一个具体的业务中对其进行展示. 一 ...
- Linux中Firefox——Firebug插件安装及使用
Firebug的安装方法即打开方式同httpfox Firebug使用指南: Firebug可以随时编辑页面:在HTML标签中,点击窗口上方的"inspect"命令,然后再选择页面 ...