一、文件处理
1、文件打开模式
打开文本的模式,默认添加t,需根据写入或读取编码情况添加encoding参数。
r 只读模式,默认模式,文件必须存在,不能存在则报异常。
w 只写模式,若文件不存在则创建,若文件已存在则清空内容,不可以读文件。
a 追加模式,文件不存在则创建,若文件已存在则在文件末尾追加,不可以读文件。
打开非文本的模式,使用“b”表示读取和写入需使用字节,不可指定编码。主要有rb、wb、ab三种模式。
2、操作文件方法
读取文件
with open(‘test.txt‘,‘r‘,encoding="UTF-8") as f:
print(f.read()) #读取文件全部内容
with open(‘test.txt‘, ‘r‘, encoding="UTF-8") as f:
print(f.readlines()) # 读取文件每行内容,存入列表
with open(‘test.txt‘, ‘r‘, encoding="UTF-8") as f:
print(f.readline()) # 读取文件一行内容
with open(‘test.txt‘,‘rb‘) as f:
print(f.read()) #字节读取模式读取文件全部内容
文件写入
with open(‘test1.txt‘,‘w‘,encoding="UTF-8") as f:
f.write("hello world!\n") #文本模式,需添加换行符
with open(‘test1.txt‘,‘w‘,encoding="UTF-8") as f:
f.writelines(["hello\n","world\n"]) #文本模式,需添加换行符
with open(‘test1.txt‘,‘wb‘) as f:
f.write("hello world".encode("utf-8")) #b模式需对字符先编码
with open("test1.txt",‘wb‘) as f:
f.writelines(["hello\n".encode("utf-8"),"world\n".encode("utf-8")]) #b模式需对字符串手动编码
其他操作
import time
f = open("test1.txt",‘w‘,encoding="UTF-8") #b模式没有encoding
print(f.writable()) #文件是否看可写
print(f.readable()) #文件是否可读
f.write("aa")
f.flush() #立刻将文件内容从内容刷入硬盘
time.sleep(5)
f.close() #文件关闭,无flush时,关闭文件内容才刷入硬盘
3.文件内光标的移动
1.read(3)
文件打开方式为文本时,代表读取三个字符。
文件打开方式为b时,代表读取三个字节。
2.除read外,其他文件光标移动均以字节为单位,入seek,tell,truncate
with open("test.txt",‘r‘,encoding="UTF-8") as f:
f.seek(4,0) #第一个参数表示移动的相对位置,第二个参数为0表示移动到文件开头,1表示就在当前位置,2表示移动到文件末尾
print(f.read())
print(f.tell()) #返回光标当前位置,执行为read()后为文件末尾
#truncate为截断文件,文件必须可写,不可使用w或w+模式,会清空文件,建议使用r+或者a或a+模式
with open("test.txt",‘r+‘,encoding="UTF-8") as f:
f.truncate(7) #截取前7个字节的内容。
4.文件的修改
方式一,将文件从硬盘读入内存,内存中修改完后,写入新文件后替换原文件。文件过大读入内存时会卡死。
import os
with open("test.txt",‘r‘) as read_f,open(".test.txt.swap",‘w‘) as write_f:
data = read_f.read()
data = data.replace("xxx","eee") #字符不可变,需重新赋值给data
write_f.write(data)
os.remove("test.txt")
os.rename(".test.txt.swap","test.txt")
方式二,将文件每行读入内存,按行修改,修改完后写入新文件,完成后替换原文件。
import os
with open("test.txt",‘r‘) as read_f,open(".test.txt.swap",‘w‘) as write_f:
for line in read_f:
if "xxx" in line:
line = line.replace("xxx","eee")
write_f.write(line)
os.remove("test.txt")
os.rename(".test.txt.swap","test.txt")
二、函数基础
使用函数的目的:解决代码组织结构不清晰、可读性差的问题;减少代码冗余;降低维护难度,提高可扩展性。
函数主要分为内置函数和自定义函数。
1.函数定义和调用
定义函数
#语法
def 函数名(参数1,参数2,参数3,...):
‘‘‘注释‘‘‘
函数体
return 返回的值
#函数名要能反映其意义
函数使用的原则为:先定义后使用
函数在定义阶段只检测语法,不执行代码,无法发现代码中的逻辑错误。
2.函数的参数
位置参数:按照从左到右顺序定义的参数。
位置形参:必选参数
位置实参:按照位置给形参传值
关键字参数:按照键值对形式定义的参数。
实参和形参位置不必一一对应
关键字实参必须在位置实参的右侧
对同一个形参不能重复传值
默认参数:形参在定义时已进行赋值
可已传值也可以不传,经常需要变的参数定义为位置形参,变化小的定义为默认形参
只在定义时赋值一次,且为不可变类型
默认参数定义在位置形参右侧
可变长参数:实参值个数不固定
使用*args接收位置实参,使用**kwargs接收关键字实参,*后的参数必须被传值,必须按照关键字实参的形式传递。
def func(*args,**kwargs):
print(args,kwargs)
func(3,4,5,66,a=33,b="asf",c=222) #前面的位置实参被args以元组方式接收,后面的关键字实参被kwargs以字典方式接收
def func(x,y,*args,a=1,b,**kwargs):
print(x,y)
print(args)
print(a)
print(b)
print(kwargs)
func(1,2,3,4,5,b=3,c=4,d=5)
三、函数对象、函数嵌套、名称空间与作用域、装饰器
1.函数对象的特点:
可以被引用
可以当做参数传递
返回值可以是函数
可以当做容器类型的元素
def func1():
print("from func1")
return func2 #返回func2
def func2():
print("from func2")
list = []
list.append(func1()) #返回func2作为列表元素
list[0]() #执行func2
2.函数的嵌套
def func1():
print("from func1")
def func2():
print("from func2")
def func3():
print("from func3")
func3()
func2()
func1()
3.名称空间和作用域
名称空间为内存中存放名字和值绑定关系的地方,如变量名和变量值的地址的对应关系。主要分为内置名称空间、全局名称空间和局部名称空间。
名称空间加载顺序为:
- python解释器先启动时加载内置名称空间
- 执行py文件时,加载全局名称空间,程序结束运行后释放空间
- 执行文件过程中如果调用函数,临时产生局部名称空间,函数调用结束后释放空间
名字的查找顺序和加载顺序相反,为先局部名称空间,再全局名称空间,最后内置名称空间。全局无法查看局部,局部可以查看全局。
#优先在func()局部名称空间中找max,如果没有在全局找,如果还没有在返回内置名称空间中的max
max = 3
def func():
max = 1
print(max)
func()
全局作用域:包括内置名称和全局名称空间的名字,全局存活,全局有效,globals()
局部作用域:局部名称空间的名字,临时存活,局部有效,locals()
xxx=2222
yyy="dsfsf"
print(globals())
print(locals()) #全局作用域中调用locals()相当于调用globals()
def func():
zzzzz=[1,2,3,4]
print(locals())
print(globals()) #仅比前面的globals多了func函数名字,无func函数中定义的变量名字
func()
函数的作用域关系在函数定义阶段已经固定,与调用位置无关。
xxx = "abc"
def outter():
def innner():
print("inner",xxx)
return innner
f = outter()
def bar():
x=123456
f() #f()实际上就是inner(),调用时局部作用域中无xxx,则去全局作用域中找,无法调用bar()中的xxx
bar()
4.闭包函数
闭包函数为定义在函数内部的函数,函数体代码保护对外部作用域(不是全局作用域)名字的引用,包在外面的函数通常将闭包函数用return返回,然后可以在任意使用。
z =1
def outter():
x = 1
y = 2
def inner():
print(x,y)
return inner
f =outter()
print(f.__closure__[0].cell_contents) #返回闭包函数中第一个引用外部名字的值
闭包函数主要作为用向函数传值。因为返回的函数对象包裹了一层作用域,无论在何处调用,优先使用自己外层的作用域。
#普通的调用方法,每次执行时需传入参数。
import requests
def get(url):
response = requests.get(url)
if response.status_code == 200:
print(len(response.text))
get("https://www.baidu.com")
#使用闭包函数后,参数由外部函数传入,方便执行
import requests
def outter(url)
def get():
response = requests.get(url)
if response.status_code == 200:
print(len(response.text))
return get
baidu = outter("https://www.baidu.com")
baidu()
5.装饰器
装饰器可以是任意调用对象,被装饰者可以是任意可调用函数。
装饰器原则为:不修改被装饰对象的源代码;不修改被装饰对象的调用方式。(即对修改封闭,对扩展开放)
装饰器目标为在满足原则的条件下,为被装饰对象添加新功能。主要通过外层函数为内层函数传递被装饰函数,然后在内层函数中执行被装饰函数。
无参数的装饰器:
import time
def index():
time.sleep(3)
print("welcome to index")
def outter(func):
def inner():
start = time.time()
func()
stop = time.time()
print("run time is %s"%(stop-start))
return inner
index = outter(index)
index()
被修饰函数有参数的情况
import time
def index(name):
time.sleep(3)
print("welcome %s to index" % name)
def outter(func):
def inner(*args,**kwargs):
start = time.time()
func(*args,**kwargs)
stop = time.time()
print("run time is %s" %(stop-start))
return inner
index = outter(index)
index("xxx")
有参数装饰器,装饰器外层做多只需要两层,最内层传入被装饰函数的参数。外一层传入被装饰函数名,返回内层函数。最外层传入内层函数需要引入的其他参数,返回中间层的函数名。
def auth(driver=‘file‘):
def auth2(func):
def wrapper(*args,**kwargs):
name = input("input user:")
password = input("input password")
if driver == "file":
if name=="xxx" and password=="123":
print("login success")
return func(*args,**kwargs)
elif driver == "ldap":
print("ldap")
return wrapper
return auth2
@auth(driver="file")
def foo(name):
print("welcome "+name)
foo("xxx")
装饰器语法
import time
def outter(func):
def inner(*args,**kwargs):
start = time.time()
func(*args,**kwargs)
stop = time.time()
print("run time is %s" %(stop-start))
return inner
@outter #相当于index=outter(index),装饰器函数必须在被修饰函数上方定义
def index(name):
time.sleep(3)
print("welcome %s to index" % name)
#index = outter(index)
index("xxx")
装饰器补充:wraps
from functools import wraps
def deco(func):
@wraps(func) #将传入被装饰函数的信息赋给内层函数,入帮助文档等。
def wrapper(*args,**kwargs):
return(func(*args,**kwargs))
return wrapper
@deco
def index():
"原始index的帮助文档"
print("from index")
print(index.__doc__)