一,文件操做基本流程。
计算机系统分为:计算机硬件,操做系统,应用程序三部分。html
咱们用python或其余语言编写的应用程序若想要把数据永久保存下来,必需要保存于硬盘中,这就涉及到应用程序要操做硬件,众所周知,应用程序是没法直接操做硬件的,这就用到了操做系统。操做系统把复杂的硬件操做封装成简单的接口给用户/应用程序使用,其中文件就是操做系统提供给应用程序来操做硬盘虚拟概念,用户或应用程序经过操做文件,能够将本身的数据永久保存下来。python
有了文件的概念,咱们无需再去考虑操做硬盘的细节,只须要关注操做文件的流程:linux
#1. 打开文件,获得文件句柄并赋值给一个变量 f=open('a.txt','r',encoding='utf-8') #默认打开模式就为r #2. 经过句柄对文件进行操做 data=f.read() #3. 关闭文件 f.close()
关闭文件的注意事项:
打开一个文件包含两部分资源:操做系统级打开的文件+应用程序的变量。在操做完毕一个文件时,必须把与该文件的这两部分资源一个不落地回收,回收方法为: 一、f.close() #回收操做系统级打开的文件 二、del f #回收应用程序级的变量 其中del f必定要发生在f.close()以后,不然就会致使操做系统打开的文件尚未关闭,白白占用资源, 而python自动的垃圾回收机制决定了咱们无需考虑del f,这就要求咱们,在操做完毕文件后,必定要记住f.close() 虽然我这么说,可是不少同窗仍是会很不要脸地忘记f.close(),对于这些不长脑子的同窗,咱们推荐傻瓜式操做方式:使用with关键字来帮咱们管理上下文 with open('a.txt','w') as f: pass with open('a.txt','r') as read_f,open('b.txt','w') as write_f: data=read_f.read() write_f.write(data) 注意
二,文件编码
f=open(...)是由操做系统打开文件,那么若是咱们没有为open指定编码,那么打开文件的默认编码很明显是操做系统说了算了,操做系统会用本身的默认编码去打开文件,在windows下是gbk,在linux下是utf-8。vim
#这就用到了上节课讲的字符编码的知识:若要保证不乱码,文件以什么方式存的,就要以什么方式打开。 f=open('a.txt','r',encoding='utf-8')
三,文件的打开模式
文件句柄 = open(‘文件路径’,‘模式’)windows
#1. 打开文件的模式有(默认为文本模式): r ,只读模式【默认模式,文件必须存在,不存在则抛出异常】 w,只写模式【不可读;不存在则建立;存在则清空内容】 a, 只追加写模式【不可读;不存在则建立;存在则只追加内容】 #2. 对于非文本文件,咱们只能使用b模式,"b"表示以字节的方式操做(而全部文件也都是以字节的形式存储的,使用这种模式无需考虑文本文件的字符编码、图片文件的jgp格式、视频文件的avi格式) rb wb ab 注:以b方式打开时,读取到的内容是字节类型,写入时也须要提供字节类型,不能指定编码 #3,‘+’模式(就是增长了一个功能) r+, 读写【可读,可写】 w+,写读【可写,可读】 a+, 写读【可写,可读】 #4,以bytes类型操做的读写,写读,写读模式 r+b, 读写【可读,可写】 w+b,写读【可写,可读】 a+b, 写读【可写,可读】
四,文件操做方法。
4.1经常使用操做方法。
read(3):缓存
1. 文件打开方式为文本模式时,表明读取3个字符闭包
2. 文件打开方式为b模式时,表明读取3个字节app
其他的文件内光标移动都是以字节为单位的如:seek,tell,truncate编辑器
注意:函数
1. seek有三种移动方式0,1,2,其中1和2必须在b模式下进行,但不管哪一种模式,都是以bytes为单位移动的
2. truncate是截断文件,因此文件的打开方式必须可写,可是不能用w或w+等方式打开,由于那样直接清空文件了,因此truncate要在r+或a或a+等模式下测试效果。
五,文件的修改。
文件的数据是存放于硬盘上的,于是只存在覆盖、不存在修改这么一说,咱们平时看到的修改文件,都是模拟出来的效果,具体的说有两种实现方式:
方式一:将硬盘存放的该文件的内容所有加载到内存,在内存中是能够修改的,修改完毕后,再由内存覆盖到硬盘(word,vim,nodpad++等编辑器)
import os # 调用系统模块 with open('a.txt') as read_f,open('.a.txt.swap','w') as write_f: data=read_f.read() #所有读入内存,若是文件很大,会很卡 data=data.replace('alex','SB') #在内存中完成修改 write_f.write(data) #一次性写入新文件 os.remove('a.txt') #删除原文件 os.rename('.a.txt.swap','a.txt') #将新建的文件重命名为原文件
方式二:将硬盘存放的该文件的内容一行一行地读入内存,修改完毕就写入新文件,最后用新文件覆盖源文件
import os with open('a.txt') as read_f,open('.a.txt.swap','w') as write_f: for line in read_f: line=line.replace('alex','SB') write_f.write(line) os.remove('a.txt') os.rename('.a.txt.swap','a.txt')
python之函数初识
一,什么是函数?
如今有这么个状况:python中的len方法不让用了,你怎么办?
来测试一下‘hello word’ 的长度:
s1 = "hello world" length = 0 for i in s1: length = length+1 print(length)
OK,完事儿了,很是完美。可是主管又提出一个需求,要计算两外一个字符串的长度:‘hello china’,
因而你的代码就变成了这样:
s1 = "hello world" length = 0 for i in s1: length = length+1 print(length) s2 = "hello china" length = 0 for i in s2: length = length+1 print(length)
这样确实能够实现len方法的效果,可是总感受不是那么完美?为何呢?
首先,以前只要咱们执行len方法就能够直接拿到一个字符串的长度了,如今为了实现相同的功能咱们把相同的代码写了好多遍 —— 代码冗余
其次,以前咱们只写两句话读起来也很简单,一看就知道这两句代码是在计算长度,可是刚刚的代码却不那么容易读懂 —— 可读性差
因此,咱们就想能不能用一段代码,来实现相同的功能,好比,我们也写一个len()叫作my_len()能够代替len()的方法,既解决了代码冗余,有让其可读性好,用什么方法呢? 这就引出了我们今天讲的----函数。
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
函数能提升应用的模块性,和代码的重复利用率。你已经知道Python提供了许多内建函数,好比print(),len()等。但你也能够本身建立函数,这被叫作用户自定义函数。
二, 函数的定义与调用。
#函数定义 def mylen(): """计算s1的长度""" s1 = "hello world" length = 0 for i in s1: length = length+1 print(length) #函数调用 mylen()
上面就是我们写了一个函数,而且成功的调用了它。
定义:def 关键词开头,空格以后接函数名称和圆括号(),最后还有一个":"。 def 是固定的,不能变,他就是定义函数的关键字。 空格 为了将def关键字和函数名分开,必须空(四声),固然你能够空2格、3格或者你想空多少都行,但正常人仍是空1格。 函数名:函数名只能包含字符串、下划线和数字且不能以数字开头。虽然函数名能够随便起,但咱们给函数起名字仍是要尽可能简短,并能表达函数功能 括号:是必须加的,先别问为啥要有括号,总之加上括号就对了! 注释:每个函数都应该对功能和参数进行相应的说明,应该写在函数下面第一行。以加强代码的可读性。 调用:就是 函数名() 要记得加上括号。
三,函数的返回值。
我们用len()方法时,获得的结果会赋值给一个变量,而后获得结果:
str_len = len('hello,world') print(str_len)
可是我们写的这个函数,并不会获得这样的结果,如何让他和len函数同样,有返回值呢?
那就是在函数的最后加上一个return,return 后面写你须要的返回值就能够了。
#函数定义 def mylen(): """计算s1的长度""" s1 = "hello world" length = 0 for i in s1: length = length+1 return length #函数调用 str_len = mylen() print('str_len : %s'%str_len)
下面我们重点研究return关键字的做用:
return关键字的做用
return 是一个关键字,在pycharm里,你会看到它变成蓝色了。你必须一字不差的把这个单词给背下来。
这个词翻译过来就是“返回”,因此咱们管写在return后面的值叫“返回值”
要研究返回值,咱们还要知道返回值有几种状况:分别是没有返回值、返回一个值、返回多个值
没有返回值
不写return的状况下,会默认返回一个None:咱们写的第一个函数,就没有写return,这就是没有返回值的一种状况。
#函数定义 def mylen(): """计算s1的长度""" s1 = "hello world" length = 0 for i in s1: length = length+1 print(length) #函数调用 str_len = mylen() #由于没有返回值,此时的str_len为None print('str_len : %s'%str_len)
只写return,后面不写其余内容,也会返回None,有的同窗会奇怪,既然没有要返回的值,彻底能够不写return,为何还要写个return呢?这里咱们要说一下return的其余用法,就是一旦遇到return,结束整个函数。
def ret_demo(): print(111) return print(222) ret = ret_demo() print(ret)
return None:和上面状况同样,咱们通常不这么写。
返回一个值
刚刚咱们已经写过一个返回一个值的状况,只需在return后面写上要返回的内容便可。
#函数定义 def mylen(): """计算s1的长度""" s1 = "hello world" length = 0 for i in s1: length = length+1 return length #函数调用 str_len = mylen() print('str_len : %s'%str_len)r
返回多个值
能够返回任意多个、任意数据类型的值
def ret_demo1(): '''返回多个值''' return 1,2,3,4 def ret_demo2(): '''返回多个任意类型的值''' return 1,['a','b'],3,4 ret1 = ret_demo1() print(ret1) ret2 = ret_demo2() print(ret2) 返回多个值
返回的多个值会被组织成元组被返回,也能够用多个值来接收
def ret_demo2(): return 1,['a','b'],3,4 #返回多个值,用一个变量接收 ret2 = ret_demo2() print(ret2) #返回多个值,用多个变量接收 a,b,c,d = ret_demo2() print(a,b,c,d) #用多个值接收返回值:返回几个值,就用几个变量接收 a,b,c,d = ret_demo2() print(a,b,c,d) 多个返回值的接收
四,函数的参数。
如今,咱们已经把函数返回值相关的事情研究清楚了,咱们本身已经完成了一个能够返回字符串长度的函数。可是如今这个函数仍是不完美,以前咱们使用len函数的时候得是length = len("hello world"),这样我能够想计算谁就计算谁的长度。可是如今咱们写的这个函数,只能计算一个“hello world”的长度,换一个字符串好像就是不行了。这可怎么办?
#函数定义 def mylen(s1): """计算s1的长度""" length = 0 for i in s1: length = length+1 return length #函数调用 str_len = mylen("hello world") print('str_len : %s'%str_len)
咱们告诉mylen函数要计算的字符串是谁,这个过程就叫作 传递参数,简称传参,咱们调用函数时传递的这个“hello world”和定义函数时的s1就是参数。
实参与形参
参数还有分别:
咱们调用函数时传递的这个“hello world”被称为实际参数,由于这个是实际的要交给函数的内容,简称实参。
定义函数时的s1,只是一个变量的名字,被称为形式参数,由于在定义函数的时候它只是一个形式,表示这里有一个参数,简称形参。
传递多个参数
参数能够传递多个,多个参数之间用逗号分割。
def mymax(x,y): the_max = x if x > y else y return the_max ma = mymax(10,20) print(ma)
位置参数
站在实参角度
1.按照位置传值
def mymax(x,y): #此时x=10,y=20 the_max = x if x > y else y return the_max ma = mymax(10,20) print(ma)
2.按照关键字传值
def mymax(x,y): #此时x = 20,y = 10 print(x,y) the_max = x if x > y else y return the_max ma = mymax(y = 10,x = 20) print(ma)
3.位置、关键字形式混着用
def mymax(x,y): #此时x = 10,y = 20 print(x,y) the_max = x if x > y else y return the_max ma = mymax(10,y = 20) print(ma)
正确用法
问题一:位置参数必须在关键字参数的前面
问题二:对于一个形参只能赋值一次
站在形参角度
位置参数必须传值
def mymax(x,y): #此时x = 10,y = 20 print(x,y) the_max = x if x > y else y return the_max #调用mymax不传递参数 ma = mymax() print(ma) #结果 TypeError: mymax() missing 2 required positional arguments: 'x' and 'y'
默认参数
1.正常使用
使用方法
为何要有默认参数:将变化比较小的值设置成默认参数
2.默认参数的定义
def stu_info(name,sex = "male"): """打印学生信息函数,因为班中大部分学生都是男生, 因此设置默认参数sex的默认值为'male' """ print(name,sex) stu_info('alex') stu_info('eva','female')
3.参数陷阱:默认参数是一个可变数据类型
def defult_param(a,l = []): l.append(a) print(l) defult_param('alex') defult_param('egon')
动态参数
def trans_para(*args,**kwargs): print(args,type(args)) print(kwargs,type(kwargs)) trans_para("jinxin",12,[1,2,3,4],[3,4,],(1,4,7),{"a":"123","c":456},country="china") 动态参数,也叫不定长传参,就是你须要传给函数的参数不少,不定个数,那这种状况下,你就用*args,**kwargs接收,args是元祖形式,接收除去键值对之外的全部参数,kwargs接收的只是键值对的参数,并保存在字典中。
python之函数进阶
如今我有个问题,函数里面的变量,在函数外面能直接引用么?
def func1(): m = 1 print(m) print(m) #这行报的错 报错了: NameError: name 'm' is not defined
上面为何会报错呢?如今咱们来分析一下python内部的原理是怎么样:
咱们首先回忆一下Python代码运行的时候遇到函数是怎么作的,从Python解释器开始执行以后,就在内存中开辟里一个空间,每当遇到一个变量的时候,就把变量名和值之间对应的关系记录下来,可是当遇到函数定义的时候,解释器只是象征性的将函数名读如内存,表示知道这个函数存在了,至于函数内部的变量和逻辑,解释器根本不关心。
等执行到函数调用的时候,Python解释器会再开辟一块内存来储存这个函数里面的内容,这个时候,才关注函数里面有哪些变量,而函数中的变量回储存在新开辟出来的内存中,函数中的变量只能在函数内部使用,而且会随着函数执行完毕,这块内存中的全部内容也会被清空。
咱们给这个‘存放名字与值的关系’的空间起了一个名字-------命名空间。
代码在运行伊始,建立的存储“变量名与值的关系”的空间叫作全局命名空间;
在函数的运行中开辟的临时的空间叫作局部命名空间。
二,命名空间和做用域
在python之禅中提到过:命名空间是一种绝妙的理念,让咱们尽情的使用发挥吧!
命名空间一共分为三种:
全局命名空间
局部命名空间
内置命名空间
*内置命名空间中存放了python解释器为咱们提供的名字:input,print,str,list,tuple...它们都是咱们熟悉的,拿过来就能够用的方法。
三种命名空间之间的加载与取值顺序:
加载顺序:内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载)
取值顺序:
在局部调用:局部命名空间->全局命名空间->内置命名空间
在全局调用:全局命名空间->内置命名空间
综上所述,在找寻变量时,从小范围,一层一层到大范围去找寻。
做用域
做用域就是做用范围,按照生效范围能够分为全局做用域和局部做用域。
全局做用域:包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用、全局有效
局部做用域:局部名称空间,只能在局部范围内生效
globals和locals方法
print(globals()) print(locals())
def func(): a = 12 b = 20 print(locals()) print(globals()) func()
global关键字,nonlocal关键字。
global:
1,声明一个全局变量。
2,在局部做用域想要对全局做用域的全局变量进行修改时,须要用到 global(限于字符串,数字)。
def func(): global a a = 3 func() print(a) count = 1 def search(): global count count = 2 search() print(count)
ps:对可变数据类型(list,dict,set)能够直接引用不用经过global。
li = [1,2,3] dic = {'a':'b'} def change(): li.append('a') dic['q'] = 'g' print(dic) print(li) change() print(li) print(dic)
nonlocal:
1,不能修改全局变量。
2,在局部做用域中,对父级做用域(或者更外层做用域非全局做用域)的变量进行引用和修改,而且引用的哪层,从那层及如下此变量所有发生改 变。
def add_b(): b = 42 def do_global(): b = 10 print(b) def dd_nonlocal(): nonlocal b b = b + 20 print(b) dd_nonlocal() print(b) do_global() print(b) add_b()
三,函数的嵌套和做用域链
函数的嵌套调用
def max2(x,y): m = x if x>y else y return m def max4(a,b,c,d): res1 = max2(a,b) res2 = max2(res1,c) res3 = max2(res2,d) return res3 # max4(23,-7,31,11)
函数的嵌套定义
def f1(): print("in f1") def f2(): print("in f2") f2() f1() ########### def f1(): def f2(): def f3(): print("in f3") print("in f2") f3() print("in f1") f2() f1()
函数的做用域链:小范围做用域可使用大范围的变量,可是反之不行,他是单向的。
def f1(): a = 1 def f2(): def f3(): print(a) f3() f2() f1() ################ def f1(): a = 1 def f2(): a = 2 f2() print('a in f1 : ',a) f1()
四,函数名的本质。
函数名本质上就是函数的内存地址。
1.能够被引用
def func(): print('in func') f = func print(f)
2.能够被看成容器类型的元素
def f1(): print('f1') def f2(): print('f2') def f3(): print('f3') l = [f1,f2,f3] d = {'f1':f1,'f2':f2,'f3':f3} #调用 l[0]() d['f2']()
3.能够看成函数的参数和返回值
def f1(): print('f1') def func1(argv): argv() return argv f = func1(f1) f()
第一类对象(first-class object)指 1.可在运行期建立 2.可用做函数参数或返回值 3.可存入变量的实体。
*不明白?那就记住一句话,就当普通变量用
五,闭包
def func(): name = '太白金星' def inner(): print(name)
闭包函数:
内部函数包含对外部做用域而非全剧做用域变量的引用,该内部函数称为闭包函数
#函数内部定义的函数称为内部函数
因为有了做用域的关系,咱们就不能拿到函数内部的变量和函数了。若是咱们就是想拿怎么办呢?返回呀!
咱们都知道函数内的变量咱们要想在函数外部用,能够直接返回这个变量,那么若是咱们想在函数外部调用函数内部的函数呢?
是否是直接就把这个函数的名字返回就行了?
这才是闭包函数最经常使用的用法
def func(): name = 'eva' def inner(): print(name) return inner f = func() f()
判断闭包函数的方法__closure__
#输出的__closure__有cell元素 :是闭包函数 def func(): name = 'eva' def inner(): print(name) print(inner.__closure__) return inner f = func() f() #输出的__closure__为None :不是闭包函数 name = 'egon' def func2(): def inner(): print(name) print(inner.__closure__) return inner f2 = func2() f2()
def wrapper(): money = 1000 def func(): name = 'eva' def inner(): print(name,money) return inner return func f = wrapper() i = f() i()
from urllib.request import urlopen def index(): url = "http://www.xiaohua100.cn/index.html" def get(): return urlopen(url).read() return get xiaohua = index() content = xiaohua() print(content)
python之装饰器
一,什么是装饰器?
装饰器本质上就是一个python函数,他可让其余函数在不须要作任何代码变更的前提下,增长额外的功能,装饰器的返回值也是一个函数对象。
装饰器的应用场景:好比插入日志,性能测试,事务处理,缓存等等场景。
二,装饰器的造成过程。
如今我有一个需求,我想让你测试这个函数的执行时间,在不改变这个函数代码的状况下:
import time def func1(): print('in func1') def timer(func): def inner(): start = time.time() func() print(time.time() - start) return inner func1 = timer(func1) func1()
可是若是有多个函数,我都想让你测试他们的执行时间,你每次是否是都得func1 = timer(func1)?这样仍是有点麻烦,由于这些函数的函数名多是不相同,有func1,func2,graph,等等,因此更简单的方法,python给你提供了,那就是语法糖。
import time def timer(func): def inner(): start = time.time() func() print(time.time() - start) return inner @timer #==> func1 = timer(func1) def func1(): print('in func1') func1()
刚刚咱们讨论的装饰器都是装饰不带参数的函数,如今要装饰一个带参数的函数怎么办呢?
def timer(func): def inner(a): start = time.time() func(a) print(time.time() - start) return inner @timer def func1(a): print(a) func1(1) 装饰器——带参数的装饰器
import time def timer(func): def inner(*args,**kwargs): start = time.time() re = func(*args,**kwargs) print(time.time() - start) return re return inner @timer #==> func1 = timer(func1) def func1(a,b): print('in func1') @timer #==> func2 = timer(func2) def func2(a): print('in func2 and get a:%s'%(a)) return 'fun2 over' func1('aaaaaa','bbbbbb') print(func2('aaaaaa'))
上面的装饰器已经很是完美了,可是有咱们正常状况下查看函数信息的方法在此处都会失效:
def index(): '''这是一个主页信息''' print('from index') print(index.__doc__) #查看函数注释的方法 print(index.__name__) #查看函数名的方法
如何解决呢?
from functools import wraps def deco(func): @wraps(func) #加在最内层函数正上方 def wrapper(*args,**kwargs): return func(*args,**kwargs) return wrapper @deco def index(): '''哈哈哈哈''' print('from index') print(index.__doc__) print(index.__name__)
三,开放封闭原则。
1.对扩展是开放的
为何要对扩展开放呢?
咱们说,任何一个程序,不可能在设计之初就已经想好了全部的功能而且将来不作任何更新和修改。因此咱们必须容许代码扩展、添加新功能。
2.对修改是封闭的
为何要对修改封闭呢?
就像咱们刚刚提到的,由于咱们写的一个函数,颇有可能已经交付给其余人使用了,若是这个时候咱们对其进行了修改,颇有可能影响其余已经在使用该函数的用户。
装饰器完美的遵循了这个开放封闭原则。
四,装饰器的主要功能和固定结构。
def timer(func): def inner(*args,**kwargs): '''执行函数以前要作的''' re = func(*args,**kwargs) '''执行函数以后要作的''' return re return inner
from functools import wraps def deco(func): @wraps(func) #加在最内层函数正上方 def wrapper(*args,**kwargs): return func(*args,**kwargs) return wrapper
五,带参数的装饰器。
假如你有成千上万个函数使用了一个装饰器,如今你想把这些装饰器都取消掉,你要怎么作?
一个一个的取消掉? 没日没夜忙活3天。。。
过两天你领导想通了,再让你加上。。。
def outer(flag): def timer(func): def inner(*args,**kwargs): if flag: print('''执行函数以前要作的''') re = func(*args,**kwargs) if flag: print('''执行函数以后要作的''') return re return inner return timer @outer(False) def func(): print(111) func()
六,多个装饰器装饰一个函数。
def outer(flag): def timer(func): def inner(*args,**kwargs): if flag: print('''执行函数以前要作的''') re = func(*args,**kwargs) if flag: print('''执行函数以后要作的''') return re return inner return timer @outer(False) def func(): print(111) func() 复制代码 返回顶部 多个装饰器装饰同一个函数 有些时候,咱们也会用到多个装饰器装饰同一个函数的状况。 复制代码 def wrapper1(func): def inner(): print('wrapper1 ,before func') func() print('wrapper1 ,after func') return inner def wrapper2(func): def inner(): print('wrapper2 ,before func') func() print('wrapper2 ,after func') return inner @wrapper2 @wrapper1 def f(): print('in f') f()