美文网首页
7、装饰器、生成器、报错、文件对象

7、装饰器、生成器、报错、文件对象

作者: 甜西瓜不太甜 | 来源:发表于2018-03-19 19:42 被阅读31次

    Lesson_7


    【3】装饰器和生成器

    生成器

    我们知道通过列表生成式,我们可以直接创建列表。但是了会受到内存的限制,列表容量肯定是受限制的。而且,创建一个包含100元个元素的列表,不仅占用内存空间,如果我们仅仅需要访问前面几个元素,那后面绝大多素元素占用的空间白白浪费了。

    所以,如果列表元素可以按照某种算法推算出来的话,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节约大量的空间。在python中,这一种一边循环一边计算的的机制,称为生成器(generator)。

    第一类:生成器函数:还是使用 def 定义函数,但是,使用yield而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次从它离开的地方继续执行。

    如下案例加以说明:

    # 使用next()生成斐波那契数列
    def Fib(max):
        n, a, b = 0, 0, 1
        while n < max:
            yield b
            a, b = b, a + b
            n += 1
        return '亲!没有数据了...'
    # 调用方法,生成出10个数来
    f=Fib(10)
    
    
    
    # 使用一个循环捕获最后return 返回的值,保存在异常StopIteration的value中
    list1 = []
    while  True:
        try:
            x = next(f)
            list1.append(x)
        except StopIteration as e:
            print("生成器最后的返回值是:",e.value)
            break
    print(list1)
    

    第二类:生成器表达式:类似于列表推导,只不过是把一对大括号[]变换为一对小括号()。但是,生成器表达式是按需产生一个生成器结果对象,要想拿到每一个元素,就需要循环遍历。

    如下案例加以说明:

    generator1 = [ i*i for i in range(10)]
    generator2 = ( i*i for i in range(10))
    print(generator1)
    print(generator2)
    
    for i in generator2:
        print(i)
    
    #[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    #<generator object <genexpr> at 0x10452a0a0>
    

    装饰器

    内衣可以遮羞,但是到了寒冷的季节它无法抵御严寒,于是聪明的人类发明了棉衣棉裤,给我们提供了保暖的功效,装饰器就像棉衣棉裤一样,在不影响内衣的作用下,还能给我们提供另一种功效.

    概念:是一个闭包,把一个函数当做参数,返回一个替代版的函数,本质上就是一个返回函数的函数

    简单的装饰器

    #简单的装饰器
    def func1():
        print("上海好啊!!!")
    
    def outer(func):
        def inner():
            print("*******************")
            func()
        return inner
    #f是函数func1的加强版本
    f = outer(func1)()
    

    复杂一点的装饰器

    
    def outer(func):
        def inner(age):
            if age < 0:
                age = 0
            func(age)
        return inner
    
    #使用@符号将装饰器应用到函数
    #@python2.4支持使用@符号
    @outer   #相当于say = outer(say)
    def say(age):
        print("he is %d years old" % (age))
    
    
    say(-10)
    

    通用一点的装饰器

    
    def outer(func):
        def inner(*args, **kwargs):
            #添加修改的功能
            print("&&&&&&&&&&&&&")
            return func(*args, **kwargs)
        return inner
    
    
    
    @outer #say = outer(say)
    def say(name, age): #函数的参数力理论上是无限制的,但实际上最好不要超过6、7个
        print("my name is %s, I am %d years old" % (name, age))
        return "aaaa"
    
    
    say("tom", 18)
    

    偏函数

    functools,用于高阶函数:指那些作用于函数或者返回其它函数的函数,通常只要是可以被当做函数调用的对象就是这个模块的目标。

    在Python 2.7 中具备如下方法,

    cmp_to_key,将一个比较函数转换关键字函数;
    
    partial,针对函数起作用,并且是部分的;
    
    reduce,与python内置的reduce函数功能一样;
    
    total_ordering,在类装饰器中按照缺失顺序,填充方法;
    
    update_wrapper,更新一个包裹(wrapper)函数,使其看起来更像被包裹(wrapped)的函数;
    
    wraps,可用作一个装饰器,简化调用update_wrapper的过程;
    

    偏函数的实现:

    import functools
    
    print(int("1010", base = 2)) #设置成2进制
    
    def int2(str, base = 2):
        return int(str, base)
    print(int2("1011"))
    
    
    #partial把一个参数固定住,形成一个新的函数
    int3 = functools.partial(int, base = 2)
    print(int3("111"))
    
    #那么现在int3默认就是返回2进制的
    

    第十一章


    【1】你不可能总是对的

    我们是人,不是神,所以我们经常会犯错,就算你是个经验丰富的程序员,也不能保证你写的代码百分之百的没有问题。

    另外作为一个合格的程序员,再编程的时候你要记住一点,就是永远都不要相信你的用户。要把他们想象成熊孩子,把他们想象成黑客,这样你才能写出安全稳定的程序。

    我们看例子:

    var = float(input('请输入一个数字:'))
    print(var)
    
    #请输入一个数字:q
    #ValueError: could not convert string to float: 'q'
    

    上面这个例子就报错了ValueError异常,那么python会抛出那些异常了

    <image src='images/错误代码1.png' width='500' >
    <image src='images/错误代码2.png' width='500' >
    <image src='images/错误代码3.png' width='500' >

    1、AssertionError:断言语句(assert)失败

    assert 关键字 在前面的章节里面讲过了,在测试程序的时候使用

    它在条件不成立的情况下抛出 AssertionError

    var = float(input('请输入一个数字'))
    assert var<0
    print(var)
    
    #请输入一个数字100
    #AssertionError
    

    2、AttributeError:尝试访问位置的对象属性

    当试图访问的对象属性不存在时抛出异常:

    list1 = []
    list1.shanghai
    
    #AttributeError: 'list' object has no attribute 'china'
    

    3、IndexError:索引超出范围

    list1 = [1,2,3]
    list1[3]
    
    #IndexError: list index out of range
    

    4、KeyError:字典中没有这个键

    list1 = {1:2,3:4}
    list1[6]
    
    #KeyError: 6
    

    5、TypeError:不同类型间的无效操作

    
    1 + '1'
    
    #TypeError: unsupported operand type(s) for +: 'int' and 'str'
    

    ZeroDivsionError:除数为零

    
    5 / 0
    
    ZeroDivisionError: division by zero
    

    【2】try-except语句

    格式如下:

    try:
        检测范围
    except Exception [as reason]:
        出现异常的代码
        
    

    举个例子:

    
    
    
    try:
        var = int(input('请输入一个数字:'))
        print(var)
    except ValueError:
        print('输入错误')
        
    #请输入一个数字:q
    #输入错误   
        
        
    #当然也可以这样写,错误信息会更加准确    
    #except ValueError as reason:
    #    print('输入错误,错误原因:'+ str(reason))
    
    

    针对不同的异常设置多个except

    
    try:
        var = int(input('请输入一个数字:'))
        rel = var + '1'
        print(rel)
    except ValueError as reason:
        print('输入错误,错误原因:'+ str(reason))
    except TypeError as reason:
        print('输入错误,错误原因:' + str(reason))
        
        
    #请输入一个数字:1
    #输入错误,错误原因:unsupported operand type(s) for +: 'int' and 'str'    
    

    捕获所有异常

    
    try:
        var = int(input('请输入一个数字:'))
        rel = var + '1'
        print(rel)
    except:
        print('报错了')
        
    #请输入一个数字:q
    #报错了
    
    

    【3】try-finally语句

    这里我们使用打开文件作为例子,因为文件打开了不管报不报错都需要关闭。

    文件操作在后续内容会讲到

    try:
        f = open('我是一个不存在的文件.txt') #打开文件
        print(f.read())
    except:
        print('出错了')  #在没有finally的时候报错了就会被终止
    finally:
        #f.close()   #关闭文件,这里给大家看的,注释去掉会报错
        print('关闭文件成功')  
    

    在try没有报错的情况下,会跳到finally里面执行代码。

    try报错了,会执行except,在执行finally。

    finally就是确保无论如何都要被执行的。

    【4】raise语句

    它的作用是随时随地抛出一个异常,可以带参数。

    raise ZeroDivisionError
    
    #raise TypeError('类型错误')
    
    

    【5】丰富的else语句

    这里的else说的不是if-else那个玩意。

    不过if-else也可以抛出异常,我们已经玩过了,比如说是不是大于某个数。

    例子:

    try:
        int('abc')
    except ValueError as reason:
        print('出错了,错误原因是:' + str(reason))
    else:
        print('没有问题')
    
    #出错了,错误原因是:invalid literal for int() with base 10: 'abc'
    

    上面的这个例子else中代码没有执行,因为else是在try中没有问题的情况下执行的。

    【6】简洁的with语句

    我们上面讲过了finally,在文件读取的时候可以用它来关闭文件,想想又要打开又要关闭,太烦人,那么我们的with就可以上场了,在你忘记关闭文件的时候它会自动帮你关上。

    
    try:
        with open('我是一个不存在的文件.txt') as f:
            print(f.read())
    except OSError as reason:
        print('挂啦!原因是:' + str(reason))
        
    

    这样写是不是方便多了,也不怕忘记关闭文件。

    第十二章


    【1】文件恒久远,一个永流传

    大多数的程序都是遵循,输入->处理->输出的模型,首先接受输入数据,然后按照要求进行处理,最后输出结果。可能以后你的需求就不止这些了,你可能需要你的程序可以去自动的分析系统的日志,然后分析结果在保存作为一个新的日志,这时候就需要用到文件了。

    或者说你在IDLE中写程序,突然一个不对劲,电脑蓝屏了,在开机,你的代码都没了,但是在pycharm中为什么就不会了,因为必须要新建一个文件,然后你写的时候自动存储在文件里,文件是写在硬盘上的。

    在你编写代码的时候,操作系统为了更快的做出响应,会把当前的数据全部保存在内存中,因为内存和CPU之间的数据传输是最快的,比硬盘和CPU快多了。但是内存的不足就是一断电就玩完了。

    文件的格式我们也见过很多,windows 的.exe .txt还有我们python 的.py等等,这些都是文件。
    、、

    字符串类型和字节类型

    字符串类型向字节类型转化称之为编码 encode

    字节类型向字符串类型转化称之为解码 decode

    <font color='red'>注意编解码格式一定要保持一致,如果是程序会报错,如果是编辑器查看,直接乱码</font>

    常用的字符集都是什么意思

    ascii  
        这玩意就是美国搞的一套标准,用的是一个字节,用了其中的0-127表示了所有的老外用的东西
    ansi 
        这玩意用两个字节,叫做扩展的ascii码,128-0xffff
    gbk  
        扩展的国标,在gb2312的基础上又多了好多的繁体字xxx,兼容gb2312 
    gb2312 
        这玩意是中国搞了一套自己编解码(韩国搞了一套自己的、日本也搞了一套自己的)
        对应的中国的ansi 
    utf-8   
        互联网兴起了,迫切需要统一的编码,utf-8就在unicode的基础上规定了存储和读取的方式,他存储的时候是变化的,如果存储英文字母,其使用的是1个字节,如果用来存储汉子,占用3个字节
    unicode
        是一套国际标准,称之为万国码,也是两个字节
        并没有真正的执行起来,而且也没有规定怎么存储和读取
    
    

    <font color='red'>注意:以后你要用的话,应该都是utf-8无bom的格式,如果碰到了gbk,你要自己会转化相应的格式</font>

    【2】打开文件

    在python中,使用open()这个函数来打开文件返回文件对象:

    open(file,mode = 'r',buffering = -1,encoding = None,errors = None,newline = None,closefd = True,opener = None)

    open()这个函数有很多参数,但作为初学者来说,只需要知道第一个和第二个参数就可以了。

    file:              要打开的文件名,需加路径(除非是在当前目录)。唯一强制参数
    mode:              文件打开的模式
    buffering:         设置buffer(取值为0,1,>1)
    encoding:          返回数据的编码(一般为UTF8或GBK)
    errors:            报错级别(一般为strict,ignore)
    newline:           用于区分换行符(只对文本模式有效,可以取的值有None,'\n','\r','','\r\n')
    closefd:           传入的file参数类型(缺省为True)
    

    mode对照表:

    打开模式 执行操作
    r 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。
    rb 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。
    r+ 打开一个文件用于读写。文件指针将会放在文件的开头。
    rb+ 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。
    w 打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
    wb 以二进制格式打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
    w+ 打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
    wb+ 以二进制格式打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
    a 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
    ab 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
    a+ 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。
    ab+ 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。

    例子:

    path = r"C:\Users\xlg\Desktop\Python-1704\day07\5-文件读写\file1.txt"
    #ignore  忽略错误
    #f = open(path, "r", encoding="utf-8", errors="ignore")
    f = open(path, "r", encoding="utf-8")
    
    

    【3】文件对象的方法

    打开文件并获取文件对象以后,就可以利用文件对象的一些方法对文件进行读取或修改等操作。

    文件对象方法 执行操作
    close() 关闭文件
    read(size =-1) 从文件读取size个字符,当未给定或者给定负值的时候,读取剩余的所有的字符,然后作为字符返回
    reading() 从文件中读取一整行字符
    write() 将字符串str写入文件
    writelines(seq) 向文件写入字符串序列seq,seq应该是一个返回字符串的可迭代对象
    seek(offset,from) 在文件中移入文件指针,从from(0代表文件起始位置,1代表当前位置,2代表文件末尾)偏移offset个字节
    tell() 返回当前在文件中的位置

    【4】文件的关闭

    close()方法用于关闭文件。如果是C语言的话,我在这里一定会强调一万次关闭的,如果你不关闭的话,别人想要读写就会无法完成 。不关闭文件会导致(other)无法再次已写的方式打开,以前是连只读的方式都不行。而python拥有垃圾回收机制,会在文件对象的引用此计数降至零的时候自动关闭文件。

    但是并不代表可以不关闭文件,如果你对文件进行写入操作的话,那么应该在完成写入之后关闭文件。因为python可能会缓存你写入的数据,如果中途发生类似断电之类的事故,那些缓存的数据根本就不会写入到文件中。所以,为了安全起见,要养成使用完文件后立即关闭的好习惯。

    【5】文件的读取和定位

    文件的读取方法很多,可以使用文件对象read()和readline()方法,也可以直接list(f)或者直接使用迭代来读取。

    read()方法是按字节来的去,如果不设置字节数,那么会全部读取。tell()方法会告诉你当前文件的指针位置。

    
    f = open(r'/Users/ruidong/PycharmProjects/project/demo.txt')
    print(f.read())
    print(f.tell())
    f.close()
    

    刚刚提到文件指针是个什么玩意?你可以认为它是一个书签,起到定位的作用。使用seek()方法可以调整文件指针的位置。seek(offset,from)方法有两个参数。

    也就是文件读取了多少以后,会生成指针,只能向后读,不能再读取已度去过的,除非使用seek()重新调整指针。

    
    from  表示从(0代表当前文件起始位置,1代表当前位置,2代表文件末尾)偏移 offset字节。
    

    因此,将文件指针设置到文件起始位置,使用seek(0,0)即可:

    
    f = open(r'/Users/ruidong/PycharmProjects/project/demo.txt')
    print(f.read())
    print(f.tell())
    f.seek(0,0)
    print('\n********************\n')
    print(f.read())
    f.close()
    

    readline()方法用于在文件中读取一整行,就是从文件指针的位置向后读取,直到遇到换行符(\n)结束。

    f = open(r'/Users/ruidong/PycharmProjects/project/demo.txt')
    print(f.readline())
    print(f.readline())
    f.close()
    

    此前介绍过列表强大,说什么都可以往里面放,这不,也可以把整个文件的内容放到列表中:

    
    f = open(r'/Users/ruidong/PycharmProjects/project/demo.txt')
    lines = list(f)
    for each_line in lines:
        print(each_line
    f.close()
    

    这样写是没有问题的,但是了感觉像是非要用酒精烧开水,水能烧的开,但是效率不高。文件本来就是可以迭代的。

    
    f = open(r'/Users/ruidong/PycharmProjects/project/demo.txt')
    for each_line in f:
        print(each_line)
    f.close()
    

    【6】文件的写入

    如果需要写入文件,请确保之前的打开模式有‘w’或者‘a’或者多带上‘+’,否者在写入的时候回出错:

    open 没有 ‘w’那些可写入的操作符或报错:

    import os
    os.system('touch wdemo.txt')  #在当前文件夹下新建一个wdemo.txt文件
    f = open(r'/Users/ruidong/PycharmProjects/project/wdemo.txt')
    f.write('这是一个神奇的地方')
    f.close()
    
    #io.UnsupportedOperation: not writable
    
    

    使用‘r+’读写模式,但是要注意‘r+’或者是‘w’会把原来的文件内容给删除。

    f = open(r'/Users/ruidong/PycharmProjects/project/wdemo.txt','r+')
    f.write('这是一个神奇的地方')
    f.close()
    
    

    如果是追加的话,要不然会造成血淋淋的教训,那就要使用‘a’操作符打开:

    
    f = open(r'/Users/ruidong/PycharmProjects/project/wdemo.txt','a+')
    f.write('\n这是一个美丽的地方')
    f.close()
    
    

    将序列单行写入

    writelines() 方法用于向文件中写入一序列的字符串。
    这一序列字符串可以是由迭代对象产生的,如一个字符串列表。
    换行需要制定换行符 \n。

    f = open("wdemo.txt", "w")
    
    seq = ['千锋教育\n','python']
    f.writelines(seq)
    
    

    刷新缓冲区域

    文件在写入的时候斌没有直接写入,而是在内存中,只有我们执行f.close()关闭文件以后,它才会写入。

    如果想不关闭文件直接写入,那么使用f.flush(),它的作用是立即将内存上的数据写入硬盘。

    f = open('wdemo.txt','w')
    f.write('niahoa')
    f.flush()
    
    

    相关文章

      网友评论

          本文标题:7、装饰器、生成器、报错、文件对象

          本文链接:https://www.haomeiwen.com/subject/fjzpqftx.html