什么是装饰器?
装饰器实际就是函数。我们也知道他们接受函数对象,但他们是怎样处理函数的哪?一般说来,当你包装一个函数的时候,你最终会调用这个函数。最棒的是我们能在包装的环境下的合适时机调用它。我们在执行函数之前,可以运行些预备代码,如post-morrem分析,也可以在执行代码之后做一些清理工作。所以,当你看见一个装饰器函数的时候,很可能在里面找到这样一些代码,它定义了某个函数并在定义内的某处嵌入了对目标函数的调用或者至少是一些引用。你可以在装饰器中置入通用的代码来降低程序复杂度。可以用装饰器来:
- 引入日志
- 增加计时逻辑来检测性能
- 给函数加入事务的能力
使用函数装饰器的例子:
1 #!/usr/bin/env python
2
3 from time import ctime,sleep
4
5 def tsfunc(func):
6 def wrapperdfunc():
7 print '[%s] %s() called' % (ctime(),func.__name__) ##嵌入对目标函数的调用
8 return func()
9 return wrapperdfunc
10
11 @tsfunc
12 def foo():
13 pass
14
15 foo()
16 sleep(4)
17
18 for i in range(2):
19 sleep(1)
20 foo()
运行脚本,输出如下:
[Sun Jun 28 15:50:48 2015] foo() called
[Sun Jun 28 15:50:53 2015] foo() called
[Sun Jun 28 15:50:54 2015] foo() called
2 函数式编程
lambda [arg1[,arg2,,….argN]]:expression
lambda 生成一个匿名函数。
lambda表达式返回一个可调用的函数对象。
例子如下:
>>> a=lambda x,y=2:x+y
>>> a(5)
7
>>> a(8)
10
a 引用了lambda 生成的函数对象
3.闭包
如果在一个内部函数里,对在外部作用域(但不是全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)。定义在外部函数内但是由 内部函数引用或者使用的变量被称为“自由变量”。闭包是函数式编程中的一个重要概念。
为什么想要用闭包?
闭包对于安装计算、隐藏状态、和在函数对象和作用域中随意切换是有用的。闭包在GUI或者在很多API支持回调函数的事件驱动编程中是很有用处的。以绝对相同的方式,应用于获取数据库行和处理数据。回调就是函数,闭包也是函数,但是他们能携带一些额外的作用域。
简单闭包例子:
>>> def counter(start_=0):
... count=[start_]
... def incr():
... count[0]+=1
... return count[0]
... return incr
...
>>> count=counter(5) #函数的引用
>>> print count() #函数的调用
6
4.递归
如果函数包含了对自身的调用,该函数就是递归的。“如果一个新的调用能在相同过程中较早调用结束之前开始,那么该过程就是递归”。
5.列表解析
语法:[expr for inter_var in iterable]
拓展版本:[expr for inter_var in iterable if cond_expr]
作用:动态创建一个新的列表
举例:
>>> [x**2 for x in range(5)]
[0, 1, 4, 9, 16]
6.生成器
生成器是什么?
参考:http://stackoverflow.com/questions/1756096/understanding-generators-in-python
生成器是一个函数,它返回一个你可以调用next()方法的对象,这样每次你调用它,他都返回一些值,直到抛出StopIteration异常,这也意味着所有的值都生成了,这样的对象叫做interator(迭代器)
正常函数使用return返回单个值,然后,有个另类叫“yield”,在函数的任何位置使用了yield,此函数就变成了
生成器,看这样的一个例子:
>>> def simaplegen():
... yield 1
... yield '2--->end'
...
>>> myg=simaplegen()
>>> myg.next()
1
>>> myg.next()
'2--->end'
>>> myg.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
使用for循环而不是手动迭代穿过一个生成器总是要简洁漂亮的多:
>>> for i in simaplegen():
... print i
...
1
2--->end
为什么会有“生成器”?
1. 以某种方式返回一个值并返回一个可以调用next()方法的对象
2. 协同程序。
使用生成器最好的地方就是当你迭代穿越一个巨大的数据集合,而重复迭代这个数据集合是很麻烦的事情,比如一个巨大的磁盘文件,或者一个复杂的数据库查询,对于每行的数据,你希望执行元素的操作以及处理,但当正指向和迭代过它的时候,你“不想失去你的地盘”。
- 生成器表达式
生成器表达式在python2.4被引入,他与列表解析非常相似,而且它们的基本语法基本相同;不过他并不真正的创建列表,而是返回一个生成器,这个生成器在每次计算出一个条目后,把这个条目”产生(yield)”出来。生成器表达式使用了“延迟计算(lazy evaluation)”,所以它在使用内存上更有效。
示例1:统计文件字符数
sum(len(word) for line in open('/etc/passwd','r') for word in line.split())
示例2:文件 passwd 有1760321 行,找出这个文件中最长的那行,这里将展示如何改进代码。
[stack@network1 python-code]$ wc -l passwd
1760321 passwd
程序 v1:
import time
def find_longest():
f=open('/home/stack/python-code/passwd','r')
longest=0
while True:
linelen=len(f.readline().strip())
if not linelen:break
if linelen >longest:
longest=linelen
f.close()
print "%s%s" % ("max_line: ","time_used")
print longest,
def use_time():
t1=time.time()
find_longest()
t2=time.time()
print (t2-t1)*1000
if __name__ == '__main__':
use_time()
运行后结果如下:
max_line: time_used
579 1975.77905655
如果读取到了所有行,应该尽快释放文件资源。如果这是一个很多进程都要使用到的日志文件,我们不能拿着他的距并一直不放。
程序v2:
import time
def find_longest():
f=open('/home/stack/python-code/passwd','r')
longest=0
alline=f.readlines()
f.close()
for line in alline:
linelen=len(line.strip())
if linelen >longest:
longest=linelen
print "%s%s" % ("max_line: ","time_used")
print longest,
def use_time():
t1=time.time()
find_longest()
t2=time.time()
print (t2-t1)*1000
if __name__ == '__main__':
use_time()
运行后结果如下:
[stack@network1 python-code]$ python max_line2.py
max_line: time_used
579 1281.77714348
[stack@network1 python-code]$ python max_line2.py
max_line: time_used
579 1239.51101303
[stack@network1 python-code]$ python max_line2.py
max_line: time_used
579 1260.23101807
列表解析允许我们简化代码,而且可以在得到行的集合之前做一定的处理,这里我们调用strip()方法处理行内容
程序v3:
import time
def find_longest():
f=open('/home/stack/python-code/passwd','r')
longest=0
alline=[line.strip() for line in f.readlines()]
f.close()
for line in alline:
linelen=len(line)
if linelen >longest:
longest=linelen
print "%s%s" % ("max_line: ","time_used")
print longest,
def use_time():
t1=time.time()
find_longest()
t2=time.time()
print (t2-t1)*1000
if __name__ == '__main__':
use_time()
运行后结果:
max_line: time_used
579 1655.53808212
[stack@network1 python-code]$ python max_line3.py
max_line: time_used
579 1702.42190361
[stack@network1 python-code]$ python max_line3.py
max_line: time_used
579 1641.0939693
程序4:
上面的代码在处理大文件时候都有问题,因为readlines()会读取文件的所有行。而我们知道,文件本身就是他自己的迭代器,无需调用readlines()函数。所以,
import time
def find_longest():
f=open('/home/stack/python-code/passwd','r')
alllines=[len(x.strip())for x in f]
f.close()
print "%s%s" % ("max_line: ","time_used")
print max(alllines),
def uptime():
t1=time.time()
find_longest()
t2=time.time()
print (t2-t1)*1000
if __name__== '__main__':
uptime()
运行结果:
[stack@network1 python-code]$ py max_line4.py
max_line: time_used
579 1077.85201073
[stack@network1 python-code]$ py max_line4.py
max_line: time_used
579 1054.66294289
[stack@network1 python-code]$ py max_line4.py
max_line: time_used
579 1048.1159687
上面代码唯一的问题是,一行一行迭代f的时候,列表解析文件所有行都读到了内存中才生成列表。为了不占用过多内从,我们使用生成器表达式替换列表解析,然后把它移到max()函数中,如下:
程序5:
def find_longest():
f=open('/home/stack/python-code/passwd','r')
longest=max(len(x.strip())for x in f)
f.close()
print "%s%s" % ("max_line: ","time_used")
print longest,
def uptime():
t1=time.time()
find_longest()
t2=time.time()
print (t2-t1)*1000
if __name__== '__main__':
uptime()
运行结果:
[stack@network1 python-code]$ python max_line5.py
max_line: time_used
579 1107.99098015
[stack@network1 python-code]$ python max_line5.py
max_line: time_used
579 1120.49412727
[stack@network1 python-code]$ python max_line5.py
max_line: time_used
579 1176.82313919
*最后,我们可是去掉文件打开模式(默认为读取),然后让python去处理打开的文件。
代码如下:
return max(len(x.strip()) for x in open('/home/stack/python-code/passwd'))