迭代器是Python提供的 用于访问集合
,是一种 可以记住遍历位置的对象
,会从第一个元素开始访问,直到结束。可以通过内置的 iter()函数
来获取对应的 迭代器对象
,然后直接循环遍历这个迭代器对象;或者通过另外一个内置的 next()函数
,返回 容器的下一个元素
,不过如果超过结尾会报 stopiteration异常
,使用代码示例如下:
import sysa = [1, 2, 3, 4, 5]it1 = iter(a)# 直接遍历迭代器对象for x in it1: print(x, end='\t')else: print()# 每调用一次next向后访问一个元素,超过元素会报stopiteration异常it2 = iter(a)print(next(it2), end='\t')print(next(it2), end='\t')print(next(it2), end='\t')print(next(it2), end='\t')print(next(it2), end='\t')print()# 带异常捕获方法it3 = iter(a)while True: try: print(next(it3), end='\t') except stopiteration: sys.exit()
运行结果如下:
1 2 3 4 5 1 2 3 4 5 1 2 3 4 5
另外有一点要进行区分:iterable
和 iterator
,前者只实现了 iter函数
,而后者同时实现了 iter和next函数
。比如List只是一个iterable而不是iterator,所以只支持iter(),不支持next(),需要调用iter()函数获得一个iterator对象。如果调用下type(it1),会发现数据类型是: <class 'List_iterator'>
,这是Python为List提供的默认迭代器对象。我们也可以自己来实现一个iterator,代码示例如下:
class MyIterator(): def __init__(self, names): self.names = names self.index = 0 def __iter__(self): return self def __next__(self): if self.index >= len(self.names): raise stopiteration("已到达末尾") else: self.index += 1 return self.names[self.index - 1]iterator = MyIterator([1, 2, 3, 4, 5])for i in iterator: print(i, end='\t')
运行结果如下:
1 2 3 4 5
2、生成器叫「生成器函数」会更贴切一些,一种特别的函数,用 yIEld关键字
来返回一个生成器对象,本质上还是迭代器,只是更加简洁,yIEld对应的值在函数调用时候不会立即返回,只有去调用 next()函数
的时候才会返回,而使用for xxx in xxx的时候其实调用的还是 next()函数
,最简单的生成器代码示例如下:
def func(n): yIEld n * nif __name__ == '__main__': print(func(10)) print(next(func(10))) for i in func(10): print(i)
运行结果如下:
<generator object func at 0x0000015D06436308>100100
可以看到返回的对象类型是 generator
,相比起迭代器,生成器显得更加优雅简洁,比如最经典的实现斐波那契数列的例子:
def func(n): a, b = 0, 1 while n > 0: n -= 1 yIEld b a, b = b, a + bfor i in func(10): print(i, end="\t")
运行结果如下:
1 1 2 3 5 8 13 21 34 55
3、装饰器本质上也是「函数」,作用是:帮助其他函数在不改动代码的情况下增加额外的功能,装饰器函数的返回值也是一个函数。
① 一步步了解装饰器装饰器对于很多初学者来说有点难以理解,举个简单的奶茶例子慢慢引入吧(因为手边刚好有一杯一点点奶茶,另外函数名不要用中文,这里用中文只是想让读者更容易理解,还有命名习惯:类名驼峰命名,函数名下划线分割命名!)
import timedef 波霸奶茶(): time.sleep(1) print("制作一杯波霸奶茶")if __name__ == '__main__': 波霸奶茶()
运行结果如下:
制作一杯波霸奶茶
现在笔者想知道制作一杯波霸奶茶花费的时间,可以改动下波霸奶茶这个函数:
def 波霸奶茶(): start = time.clock() time.sleep(2) print("制作一杯波霸奶茶") end = time.clock() print("耗时", end - start)if __name__ == '__main__': 波霸奶茶()
运行结果如下:
制作一杯波霸奶茶耗时 1.004335880279541
这个时候问题来了,除了波霸奶茶还有四季奶绿这款奶茶:
def 四季奶绿(): time.sleep(2) print("制作一杯四季奶绿")
而我也想知道四季奶绿的制作时间,需要把统计时间那部分代码粘贴复制一下,有点繁琐,如果还有一款格雷三兄弟,也是要复制下,好繁琐啊。有没有什么方法能简化这个过程呢?答案肯定是有的:「Python支持函数作为参数
」,我们可以把计时部分剥离成一个单独的函数,然后把需要查看制作时间的奶茶函数传入即可,所以有了下面这样的代码:
def 波霸奶茶(): time.sleep(1) print("制作一杯波霸奶茶") def 四季奶绿(): time.sleep(2)print("制作一杯四季奶绿")def 计时(func): start = time.time() func() end = time.time()print("耗时", end - start)if __name__ == '__main__': 计时(波霸奶茶) 计时(四季奶绿)
运行结果如下:
制作一杯波霸奶茶耗时 1.0002198219299316制作一杯四季奶绿耗时 2.0016701221466064
可以,这个时候问题又来了,上面的代码意味着:所有调用到制作奶茶方法的地方都要改成计时(奶茶),如果奶茶有N多种的话,每个调用制作奶茶的函数都要改成这样的形式,有没有更简单的方法啊?答案肯定是有的,Python支持返回一个函数。我们要做的是通过一个内嵌的包装函数,为传入的函数附加功能,然后返回这个函数,具体的代码如下:
def 计时(func): def decorator(): start = time.time() func() end = time.time() print("耗时", end - start)return decoratorif __name__ == '__main__': 波霸奶茶 = 计时(波霸奶茶) 波霸奶茶() 四季奶绿 = 计时(四季奶绿) 四季奶绿()
运行结果如下:
制作一杯波霸奶茶耗时 1.0033059120178223制作一杯四季奶绿耗时 2.0044848918914795
可以,没毛病,而且只有在我们需要查询某种奶茶的制作时间时才需要这样写,平常的函数还是正常使用。嗯,你以为到这里就完了,对于装饰器函数,Python还为我们提供了一枚语法糖,语法糖可以理解成一种便捷的写法吧,在Python中通过一个@ 就可以简化我们上面的代码,具体代码如下:
def 计时(func): def decorator(): start = time.time() func() end = time.time() print("耗时", end - start)return decorator@计时def 波霸奶茶(): time.sleep(1)print("制作一杯波霸奶茶")@计时def 四季奶绿(): time.sleep(2)print("制作一杯四季奶绿")if __name__ == '__main__': 波霸奶茶() 四季奶绿()
一样的运行结果,更加精简的代码,相信读者都体验到了语法糖的便利,但是要注意一点:大部分的语法糖只是减少我们写繁琐代码的时间,让我们把更多的时间花在逻辑流程上,代码写少了不一定就会带来性能上的提升,底层的代码可能还是那些东西!
② 带参数的装饰器
上面演示的是无参数的装饰器的用法,有时我们可能需要传入一些参数,需要在 原闭包的基础上再加一层闭包
,具体流程与代码示例如下:
import timedef 计时(配料="珍珠"): def decorator(func): def inner(): print("加入配料:%s" % 配料 ) start = time.time() func() end = time.time() print("耗时", end - start) return func return inner return decorator@计时(配料='波霸')def 波霸奶茶(): time.sleep(1) print("制作一杯波霸奶茶")@计时(配料='椰果')def 四季奶绿(): time.sleep(2) print("制作一杯四季奶绿")if __name__ == '__main__': 波霸奶茶() print() 四季奶绿()
运行结果如下:
加入配料:波霸制作一杯波霸奶茶耗时 1.0022242069244385加入配料:椰果制作一杯四季奶绿耗时 2.0034420490264893
③ 多个装饰器的执行顺序
一个函数可以搭配多个修饰器使用,执行的顺序:「从下往上,就近原则,靠近函数定义的先执行
」。验证代码示例如下:
def func_a(func): def decorator(): func() print("Call func_a")return decoratordef func_b(func): def decorator(): func() print("Call func_b")return decoratordef func_c(func): def decorator(): func() print("Call func_c")return decorator@func_a@func_b@func_cdef func_t():passif __name__ == '__main__': func_t()
运行结果如下:
Call func_cCall func_bCall func_a
④ 四种不同类型的装饰器
Python中有四种不同类型的装饰器,分别是:「函数装饰函数」「函数装饰类」「类装饰函数」
「类装饰类」, 和类有关的装饰器可以等后面学完类和对象再回头看,不用死记,用到的时候
照葫芦画瓢改改就好。另外类装饰函数或类主要依赖类的 __call__
函数,当使用@形式将装饰器
附加到函数上时,就会调用该函数。
def func_func(func): def decorator(a, b): print("函数装饰的函数名:", func.__name__) result = func(a, b) return resultreturn decorator@func_funcdef func_add(a, b):return a + bif __name__ == '__main__': print(func_add(1, 2))
运行结果如下:
函数装饰的函数名: func_add3
「函数装饰类」,使用代码示例如下:def func_class(cls): def decorator(name): print("函数装饰的类:", cls.__name__, name) return cls(name)return decorator@func_classclass A: def __init__(self, n): self.n = n def show(self): print("a = " + self.n)a = A('123')a.show()
运行结果如下:
函数装饰的类: A 123a = 123
「类装饰函数」,使用代码示例如下:class class_func: def __init__(self, _func): self._func = _func def __call__(self, name): print("类装饰的函数名:", self._func.__name__, name) return self._func(name)@class_funcdef func(a): return aif __name__ == '__main__': print(func('123'))
运行结果如下:
类装饰的函数名: func 123123
「类装饰类」,使用代码示例如下:class class_class: def __init__(self, _cls): self._cls = _cls def __call__(self, name): print("类装饰的类的类名:", self._cls.__name__, name) return self._cls(name)@class_classclass A: def __init__(self, a): self.a = a def show(self): print('self.a = ', self.a)if __name__ == '__main__': a = A('123') a.show()
运行结果如下:
类装饰的类的类名: A 123self.a = 123
总结 以上是内存溢出为你收集整理的Python小白到老司机,快跟我上车!基础篇(十四)全部内容,希望文章能够帮你解决Python小白到老司机,快跟我上车!基础篇(十四)所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)