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

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()

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,186评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,858评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,620评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,888评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,009评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,149评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,204评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,956评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,385评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,698评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,863评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,544评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,185评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,899评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,141评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,684评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,750评论 2 351

推荐阅读更多精彩内容

  • 一、基础知识:1、JVM、JRE和JDK的区别:JVM(Java Virtual Machine):java虚拟机...
    杀小贼阅读 2,373评论 0 4
  • 定义类并创建实例 在Python中,类通过 class 关键字定义。以 Person 为例,定义一个Person类...
    绩重KF阅读 3,933评论 0 13
  • 在暑期孩子读《论语》。我随手翻阅,竟被书中几句话所吸引,直觉告诉我这是一本教人为人处世的书。 没想到就是这随手...
    梓柔阅读 442评论 0 3
  • 想不起是什么时候遗忘,记不起是什么时候铭刻。眼前的苹果树,是否还是你心中的那棵?唇口轻吐的葡萄,分不清是什么样的味...
    东野沫沫阅读 92评论 0 0
  • 周秦本来想拒绝蒙婷婷让她当信使的托咐,但一时想不出理由,即使想出来了,照从前的惯例,蒙婷婷又会说服她照着办。与其费...
    橘子系列阅读 501评论 4 11