python基础第四篇

来源:互联网 发布:上瘾网络剧第十六集 编辑:程序博客网 时间:2024/06/15 23:52

python基础 (四)

真心觉得python这门语言是业界良心:

  • 生成器
  • 迭代器
  • 装饰器

一、生成器

首先来看一下列表生成式:

num_list=[i**2 for i in range(5)]print(num_list)#输出#[0, 1, 4, 9, 16]

列表生成式可以让我们很方便的生成一个列表,但是若是创建一个含有100万的元素的列表,其中有些元素经常用,有些元素几百年才用一回,这样就会浪费很大的存储空间。那么生成器就可以用来解决这种困惑。
列表元素可以按照某种算法推算出来,而不是一下子就创建好,这样一边计算一边循环。将上面列表生成式稍微改一下就成了一个简单的生成器。

num_g=(i**2 for i in range(5))print(num_g)#输出#<generator object <genexpr> at 0x7f277b807620>

那么怎么提取元素呢,通过next()函数获取generator的下一个值:

next(num_g)#输出 0next(num_g)#输出 1next(num_g)#输出 4

每次调用next()函数就会计算下一个返回值,直到最后一个元素,没有更多元素时,抛出StopIteration的错误。我们一般通过for循环来调用:

for i in num_g:    print(i)#输出#0#1#4#9#16

generator另一种构建方式是用yield,这里有斐波那契数列作为例子。

#斐波那契数列:#1, 1, 2, 3, 5, 8, 13, 21, 34, ..def fib(max):    n,a,b=0,0,1    while n<max:        yield b        a,b=b,a+b        n+=1    return "done"#当取生成器元素发生错误时,返回donef=fib(5)for i in f:    print(i)

输出:

11235

生成器内含一个next()方法,每次调用时执行到yield结束,再执行时从上次结束的yield处开始。

f=fib(5)print(f.__next__())print(f.__next__())print("做个其他事再去排数列")print(f.__next__())

输出:

11做个其他事再去排数列2

上面这个例子还是很神奇的,函数执行到yield就跳出,这时竟然还能够另外执行主程序中的其他命令。

二、 迭代器

给定一个list或tuple,可以通过for循环来遍历,那么这种遍历成为迭代(Iteration)。可迭代的对象(Iterable)有:

  1. 集合数据类型,如list、tuple、dict、set、str等
  2. generator生成器

    可以用isinstance()判断是否是一个可迭代对象(Iterable)。

from collections import Iterableisinstance([],Iterable)isinstance({},Iterable)isinstance("afsdg",Iterable)isinstance((x for x in range(12)),Iterable)isinstance(100,Iterable)

输出:
输出:

TrueTrueTrueTrueFalse

可以被next()函数调用并不断返回下一个值的对象称为迭代器
可以用isinstance()判断是否是一个迭代器对象(Iterator)

from collections import Iteratorisinstance([],Iterator)isinstance({},Iterator)isinstance("afsdg",Iterator)isinstance((x for x in range(12)),Iterator)

输出:
输出:

FalseFalseFalseTrue

所以生成器是迭代对象,而list,tuple,dict,str虽然是Iterable,但不是Iterator。

总之:

  1. 凡是可作用于for循环的对象都是Iterable类型;
  2. 凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
  3. 集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象

三、装饰器

装饰器是什么?下面通过一个例子来说明。自己构建一个教学网站,那么首先有主页,再通过主页可以进入教学视频专区和论坛学术交流专区。

def home():    print("欢迎来到我的网站!")def edu_zone():    print("已进入课程专区")def bbs():    print("已进入论坛专区")

建立了这个也不够,必须对学员进行用户认证才行,为了学员的方便,应当在每个版块都能实现用户认证,那么先写出用户认证的方法:

global user_logindef login():    _username = "王柯南"    _password = "666666"    user_login = False    if not user_login:        username = input("用户名:")        password = input("密码:")        if username == _username and _password == password:            print("登录成功")            user_login = True        else:            print("用户名或者密码错误")    else:        print("您已经登录了")

那么为了让每个版块都具有用户验证的功能,可以在每个版块中加入login函数

def home():    login()    print("欢迎来到我的网站!")def edu_zone():    login()    print("已进入课程专区")def bbs():    login()    print("已进入论坛专区")

但是这样的话违反了软件开发中的一个原则“开放-封闭”原则,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,那么很low的改进一下:

global user_logindef login(func):    _username = "王柯南"    _password = "666666"    user_login = False    if not user_login:        username = input("用户名:")        password = input("密码:")        if username == _username and _password == password:            print("登录成功")            user_login = True            func()        else:            print("用户名或者密码错误")    else:        print("您已经登录了")def home():    print("欢迎来到我的网站!")def edu_zone():    print("已进入课程专区")def bbs():    print("已进入论坛专区")login(home)login(edu_zone)login(bbs)

这里虽然没有改变原有的功能代码,但是改变了调用方式,倘若版块增多,增加调用也是很繁琐的事情,那么有什么能既不改变功能代码,又不改变调用方式,一劳永逸的方法呢?

#只要能做到以下三个等式#home()==login(home)#edu_zone()==login(edu_zone)#bbs()==login(bbs)#可以利用嵌套函数global user_logindef auth(func):    def login():        _username = "王柯南"        _password = "666666"        user_login = False        if not user_login:            username = input("用户名:")            password = input("密码:")            if username == _username and _password == password:                print("登录成功")                user_login = True                func()            else:                print("用户名或者密码错误")        else:            print("您已经登录了")    return logindef home():    print("欢迎来到我的网站!")def edu_zone():    print("已进入课程专区")def bbs():    print("已进入论坛专区")# home=auth(home)==login 由于是嵌套函数auth会把home传递给loginhome = auth(home)edu_zone = auth(edu_zone)bbs = auth(bbs)home()edu_zone()bbs()

那么就实现了既不改变功能代码,又不改变调用方式,再优化下代码。

#只要能做到以下三个等式#home()==login(home)#edu_zone()==login(edu_zone)#bbs()==login(bbs)#可以利用嵌套函数global user_logindef auth(func):    def login():        _username = "王柯南"        _password = "666666"        user_login = False        if not user_login:            username = input("用户名:")            password = input("密码:")            if username == _username and _password == password:                print("登录成功")                user_login = True                func()            else:                print("用户名或者密码错误")        else:            print("您已经登录了")    return logindef home():    print("欢迎来到我的网站!")def edu_zone():    print("已进入课程专区")def bbs():    print("已进入论坛专区")@auth#home = auth(home)home()@auth#edu_zone = auth(edu_zone)edu_zone()@auth#bbs = auth(bbs)bbs()

那么这就是装饰器了。但是又有问题了,如果我们的功能函数现在具有了形参,那么装饰器该如何改变?

#现在home函数中新增了name形参,而edu_zone和bbs函数还是保持原样def home(name):    print("欢迎%s来到我的网站!"%name)def edu_zone():    print("已进入课程专区")def bbs():    print("已进入论坛专区")#只要能做到以下三个等式#home(name)==login(home,name)#edu_zone()==login(edu_zone)#bbs()==login(bbs)global user_logindef auth(func):    def login(*args):        _username = "王柯南"        _password = "666666"        user_login = False        if not user_login:            username = input("用户名:")            password = input("密码:")            if username == _username and _password == password:                print("登录成功")                user_login = True                func(args)            else:                print("用户名或者密码错误")        else:            print("您已经登录了")    return login@auth#home = auth(home)==login嵌套函数将home传递给login#home(name)==login(name)home("xzx")@auth#edu_zone = auth(edu_zone)edu_zone()@auth#bbs = auth(bbs)bbs()

最后还有一个问题,该登录方式只允许用户使用,内部人员使用要用其他登录方式,那又该怎么改进呢?

#用auth_type代表登录人员的类型#若是auth函数新增加了别的形参,装饰器@auth就失去了功能#但是auth_type又必须传入给login函数去判断#那就应该再增加一个嵌套函数用来传auth_type#只要能做到等式#home(name)==login(auth_type,home,name)global user_logindef auth_login(auth_type):    def auth(func):        def login(*args):            if auth_type == "user":                _username = "王柯南"                _password = "666666"                user_login = False                if not user_login:                    username = input("用户名:")                    password = input("密码:")                    if username == _username and _password == password:                        print("登录成功")                        user_login = True                        func(*args)                    else:                        print("用户名或者密码错误")                else:                    print("您已经登录了")            else:                print("您是内部工作人员,请更换登录系统")        return login    return auth@auth_login("user")#auth_login("user")==auth 参数user传递给了auth#home=auth(home)==login 参数user和home都传递给了login#@auth_login("user")=>home=auth_login("user")(home)def home(name):    print("欢迎%s来到我的网站!"%name)@auth_login("staff")def edu_zone():    print("已进入课程专区")@auth_login("user")def bbs():    print("已进入论坛专区")home("xzx")edu_zone()bbs()

输出:

用户名:王柯南密码:666666登录成功欢迎xzx来到我的网站!您是内部工作人员,请更换登录系统用户名:王柯南密码:666666登录成功已进入论坛专区
原创粉丝点击