Python小白到老司机,快跟我上车!基础篇(十四)

Python小白到老司机,快跟我上车!基础篇(十四),第1张

概述5.2函数(下)1、迭代器迭代器是Python提供的用于访问集合,是一种可以记住遍历位置的对象,会从第一个元素开始访问,直到结束。可以通过内置的iter()函数来获取对应的迭代器对象,然后直接循环遍历这个迭代器对象;或者通过另外一个内置的next()函数,返回容器的下一个元素,不 5.2 函数(下)1、迭代器

迭代器是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

另外有一点要进行区分:iterableiterator,前者只实现了 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小白到老司机,快跟我上车!基础篇(十四)所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1189138.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-03
下一篇 2022-06-03

发表评论

登录后才能评论

评论列表(0条)

保存