迭代器、生成器与装饰器都是python中的非常常用的语法形式。但是初学的时候还是有点不好理解,但是还必须要掌握,这里试图简单阐述出它们的原理。
作用:
迭代器和生成器的作用简单点说就是可以节约大量的内存
1、迭代器是一种可以连续迭代的一个容器,
2、生成器是函数中包含yield语句的一类特殊的函数。
3、装饰器的作用就是为一个对象或者函数添加相关的功能,在程序设计中,可以灵活地设计出所需要的功能。
Iteration is the repetition of a process in order to generate a (possibly unbounded) sequence of outcomes. The sequence will approach some end point or end value. Each repetition of the process is a single iteration, and the outcome of each iteration is then the starting point of the next iteration.
迭代是重复反馈过程的活动,其目的通常是为了接近并到达所需的目标或结果。每一次对过程的重复被称为一次“迭代”,而每一次迭代得到的结果会被用来作为下一次迭代的初始值。
⽤简单的话讲,它就是从某个地⽅(⽐如⼀个列表)取出⼀个元素的过程。当我们使⽤⼀ 个循环来遍历某个东西时,这个过程本⾝就叫迭代。
Python中任意的对象,只要它定义了可以返回⼀个迭代器的__iter__⽅法,或者定义了 可以⽀持下标索引的__getitem__⽅法, 那么它就是⼀个可迭代对象。简单说,可迭代对象就是能提供迭代器的任意对象。
简单来说,迭代器就是实现了迭代器协议方法的对象或类。迭代器的协议方法主要是两个:
1、__iter__()
:返回对象本身,它是for语句使用迭代器的要求.
2、__next__()
:返回容器中下一个元素或数据。当容器中数据用尽时,应该引发StopIteration异常。
总之、任何类实现这两个方法,就可以称为一个迭代器了。同时,也就可以使用for循环来进行遍历了。
class MyIterator:
'''自定义类迭代器MyIterator'''
def __init__(self,x=2,xmax=1000): # 定义构造方法,初始化实例属性
self.__mul = x
self.__x = x
self.__xmax = xmax
def __iter__(self): # 定义迭代器协议方法,返回类自身
return self
def __next__(self): # 定义迭代器协议方法
if self.__x and self.__x != 1:
self.__mul *= self.__x
if self.__mul <= self.__xmax:
return self.__mul # 返回值
else:
raise StopIteration # 抛出StopIteration错误
else:
raise StopIteration
if __name__ == '__main__':
myiter = MyIterator() # 实例化迭代器
for i in myiter: # 遍历并输出值
print('迭代的数据元素为{}'.format(i))
可以看出,初始化迭代器使用了默认参数,遍历得到的序列是2的n次方的值,最大值不超过100。
注:从代码可以看出,如果需要产生很大范围的数的序列,采用列表或者元组等进行一次性生成,则必须占据大量的内存空间,对系统有着较大的压力,使用迭代器,每次调用时生成一个,显然节约了大量的内存空间。
来做个测试
我用for循环写了一个判断2的n次方的代码,范围是(2,100000000),我的辣鸡电脑跑出来的时间是21.21182918548584 s,用刚刚写的迭代器代码跑出来的时间仅仅为0.0s(保留20位小数仍然是0)。当测试数据开到1000000000000000000000的时候,迭代时间仍然是0,循环已经废掉了。能由此可见,效率问题,值得注意。
⽣成器也是⼀种迭代器,但是你只能对其迭代⼀次。这是因为它们并没有把所有的值存在 内存中,⽽是在运⾏时⽣成值。你通过遍历来使⽤它们,要么⽤⼀个“for”循环,要么将它们传递给任意可以进⾏迭代的函数和结构。⼤多数时候⽣成器是以函数来实现的。
def myYield(n):
while n > 0:
print('开始生成...')
yield n # yield语句,用于返回给调用者其后表达式的值
print('完成一次...')
n -= 1
if __name__ == '__main__':
for i in myYield(4):
print('遍历得到的值:',i)
结果:
开始生成...
遍历得到的值: 4
完成一次...
开始生成...
遍历得到的值: 3
完成一次...
开始生成...
遍历得到的值: 2
完成一次...
开始生成...
遍历得到的值: 1
完成一次...
当然,也可以使用手工遍历,调用__next__()方法。
my_yield = myYield(3)
a = my_yield.__next__()
print(a)
防止难理解,写个代码测试一下:
def myYield(n):
while n > 0:
rcv = yield n
n -= 1
if rcv is not None:
n = rcv
if __name__ == '__main__':
my_yield = myYield(3)
print(my_yield.__next__())
print(my_yield.__next__())
print('传给生成器一个值,重新初始化生成器')
print(my_yield.send(10))
print(my_yield.__next__())
说明:代码中首先定义了一个生成器函数,其中yield语句为“rcv = yield n”。rcv就可以接收调用者传来的值。如果调用时,提供了一个值,就会从这个值开始递减产生序列。如下图:
装饰器说简单点就是一种增加函数或者类的功能的方法,可以快速插入相同的功能。本质上来讲,它是一种代码的实现方式。
其实函数里面定义函数不是什么稀奇的东西,写个代码测试一下:
def hi():
print("now you are inside the hi() function")
def greet():
return "now you are in the greet() function"
def welcome():
return "now you are in the welcome() function"
print(greet())
print(welcome())
print("now you are back in the hi() function")
hi()
很容易是不是,那现在我们知道了可以在函数中定义另外的函数。也就是说:我们可以创建嵌套的函数。 但是你需要再多学⼀点,就是函数也能返回函数。
其实并不需要在⼀个函数⾥去执⾏另⼀个函数,我们也可以将其作为输出返回出来:
def hi(name='hello'):
def greet():
return "now you are in the greet() function"
def welcome():
return "now you are in the welcome() function"
if name == "hello":
return greet
else:
return welcome
print(greet())
print(welcome())
print("now you are back in the hi() function")
a = hi()
print(a)
# .greet at 0x00000286AB4B29D8>
#上⾯清晰地展示了`a`现在指向到hi()函数中的greet()函数
#现在试试这个
print(a())
# now you are in the greet() function
why?
当你把⼀对⼩括号放在后⾯,这个函数就会执⾏; 然⽽如果你不放括号在它后⾯,那它可以被到处传递,并且可以赋值给别的变量⽽不去执⾏它。
def hi():
return "hi python!"
def test(func):
print("I am doing some boring work before executing hi()")
print(func())
test(hi)
结果:
I am doing some boring work before executing hi()
hi python!
现在你已经具备所有必需知识,来进⼀步学习装饰器真正是什么了。装饰器让你在⼀个函 数的前后去执⾏代码。
装饰器的表示语法是使用一个特殊的符号“@”来实现的。装饰器装饰函数或者类就用“@装饰器名称”放在函数或者类的定义行之前即可。
注:我个人觉得如果概念不是很容易懂那就写写代码看一下,总会有收获的
def abc(fun):
def wrapper(*args, **kwargs):
print('开始运行。。。。。。')
fun(*args, **kwargs)
print('运行结束!')
return wrapper
@abc
def demo_decoration(x):
a = []
for i in range(x):
a.append(i)
print(a)
@abc
def hello(name):
print('Hello', name)
if __name__ == '__main__':
demo_decoration(5)
print()
hello('Jane')
上面的代码首先定义了一个装饰器函数(abc),它带有一个可以使用函数对象的参数。然后用它装饰了两个普通函数。最后就是进行函数的调用,你会发现,并没有调用abc,但是会使用这个函数的功能。
简单的看,这就是装饰器了,我们可以看一下它的运行结果:
当然,装饰器还可以用来装饰一个类,不过这里不过多阐述,感兴趣就去网上找个例子学习一下。如果想要更深入的了解装饰器,还可以去查阅一下闭包的概念,这样肯定会加深对装饰器的理解。
参考书目:
python的迭代器,生成器以及装饰器都是比较重要的概念,同时也都有很丰富的应用场景。不过刚开始接触python的时候,不是特别容易理解。做个简单的了解就行,用到的时候再去具体学习,千万不要被搞没积极性了!!!!!!
想学习python或者正在转行python相关的行业的朋友们可以进qq群798665505,群里有许多对python感兴趣的朋友,里面也有很多有趣的灵魂。同样你可以获得很多资料,大家一起学习。一起进步,身体和灵魂,总要有一个在路上。