1.迭代器
顾名思义,迭代器就是用于迭代操作(for 循环)的对象,它像列表一样可以迭代获取其中的每一个元素,任何实现了 next 方法的(对象)都可以称为迭代器。
它与列表的区别在于,构建迭代器的时候,不像列表把所有元素一次性加载到内存,而是以一种延迟计算(lazy evaluation)方式返回元素,这正是它的优点
话不多说,我们来看一个例子
class Fib(object):
def __int__(_self,n):
self.n = n
self.cur = 1
self.prev = 0
def __iter__(self):
return self
def __next__(self):
if self.n > 0
// python里面这种赋值超爽有木有
self.cur,self.prev = self.cur + self.prev,self.cur
self.n -= 1
return self.cur
else:
raise stopIteration()
f = Fib(10)
print([i for i in f])
#[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
上面以斐波那契数列为例来实现一个迭代器:
Fib类实现了魔术方法,在每回迭代的时候会调用next方法
2.魔术方法
咱们由浅入深举三个例子把
class student(object):
def __init__(self, name):
self.name = name
def __call__(self):
print 'my name is {0}'.format(self.name)
aa = student('aa')
aa() 会调用call()方法
output: 'My name is aa'
class A():
def __init__(self):
print "call __init__"
self.value = [1,2,3,4,5,6]
def __len__(self):
print "call __len__"
return len(self.value)
def __getitem__(self, index):
print "call __getitem__"
return self.value[index]
aa = A()
print (len(aa)) ======== 6
print aa[2] ======== 3 这里调用了getItem方法 取下标为2的值
看一个稍微复杂一点的
class ListMetaclass(type):
def __new__(cls, name, bases, attrs):
attrs['add'] = lambda self, value: self.append(value)
return type.__new__(cls, name, bases, attrs)
class MyList(list, metaclass=ListMetaclass):
pass
ld = MyList()
ld.add('ni')
ld ========= ['ni']
这个涉及到了元类,跟js里面的原型有相似之处,但比原型好理解些。
简单解释一下:
Mylist继承了list是一个列表类,具有append方法,然后她后面又跟了个metaclass也就是元类,所有继承该元类的类都拥有add方法,是一个lambda表达式的函数self.append(value),所以知道为什么能有append了吧。
今天不深究,下回有时间我会搞一期元类和魔术方法的专题。
3.生成器
生成器算得上是Python语言中最吸引人的特性之一,生成器其实是一种特殊的迭代器,不过这种迭代器更加优雅。它不需要再像上面的类一样写iter()和next()方法了,只需要一个yiled关键字。
from itertools import islice
def fib():
prev, curr = 0, 1
while True:
yield curr
prev, curr = curr, curr + prev
>>> f = fib()
>>> list(islice(f, 0, 10))
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
itertools是一个很有用的工具类,大家自行google
生成器都有一个send方法
def count(n):
x = 0
while x < n:
value = yield x
if value is not None:
print 'Received value: %s' %value
x += 1
gen = count(5)
print (gen.__next__()) # print 0
print (gen.send('Hello') ) # Received value: Hello, then print 1
注意用的python3版本的要调用next方法 打印需要加括号
来一个综合一点的例子
def consumer():
last = ''
while True:
//receival是生成器send过来的值
receival = yield last
if receival is not None:
print ('Consume %s' % receival)
last = receival
def producer(gen, n):
//这一步启动生成器很关键
gen.__next__()
x = 0
while x < n:
x += 1
print ('Produce %s' % x)
print (gen.send(x))
gen.close()
gen = consumer()
producer(gen, 5)
output:
Produce 1
Consume 1
1
Produce 2
Consume 2
2
...
结束循环时,用生成器的close方法关闭她。
4.装饰器
搞过java开发的人应该知道,aop面向切面织入方法。玩过angular的也应该知道,依赖注入也是装饰器的一种,很幸运2者我都接触过。
import time
def performance(f):
@functools.wraps(decorated)
def fn(*args, **kw):
t1 = time.time()
r = f(*args, **kw)
t2 = time.time()
print 'call %s() in %fs' % (f.__name__, (t2 - t1))
return r
return fn
@performance
def factorial(n):
return reduce(lambda x,y: x*y, range(1, n+1))
print factorial(10)
说明2点,@functools.wraps(decorated)是保证factorial函数被装饰后名字不变,
另外reduce在python3中需要引入。
下面介绍一下装饰器传参的用法
import json
import functools
def json_output(indent=None, sort_keys=False):
//想想这里为什么会多一层函数 以前的外层装饰器参数是被修饰的函数
def actual_decorator(func):
@functools.wraps(func)
def inner(*args, **kwargs):
result = func(*args, **kwargs)
return json.dumps(result, indent=indent, sort_keys=sort_keys)
return inner
return actual_decorator
@json_output(18, sort_keys=True)
def f():
return {'status': 'done','aa':'bb'}
print (f())
output:
{
"aa":"bb",
"status":"done"
}
写到这里chrome居然崩溃了。。。
上面的意思是序列化一个json,缩进18,按键排序。
好了,今天说了iterator,generator,decrator,还有魔术方法,下回会跟大家分享爬虫或者python实用库,尽情期待吧,如果觉得写得比较有条理,点波关注哟。