一、字符编码
1、什么是字符编码
把字符转换成计算机可识别的机器码(0,1)的过程,称之为字符编码。
2、字符编码的类型
1)现代计算机起源于美国,最早诞生也是基于英文考虑的ASCII
ASCII:一个Bytes(字节)代表一个字符(英文字符、键盘上的所有其它字符),1Bytes=8bit,8bit可以表示为2的8次方种变化,即可以表示256个字符。
ASCII最初只用了后攻位,127个数字,已经完全能够代表键盘上所有的字符了(英文字符/键盘的所有其他字符),后期将拉丁文也编码进了ASCII表,占用了最高位。
2)为了满足中文,中国人定制了GBK
GBK:2Bytes代表一个字符
为了满足需求,各国家分别定制了自己的编码。日文编码Shift_JIS,韩文编码Euc-kr。
3)各国编码遵循自己的标准,当在多语言混合的文本中,就会出现冲突,显示乱码。于是产生了unicode万国码。
unicode:至少用2Bytes代表一个字符,2**16-1=65535,可代表655535个字符,因而兼容万国语言。
由于至少使用2字节代表一个字符,对于英文文本来说,多占用了一倍的存储空间,于是产生了utf-8。
4)utf-8:对文本进行判断,中文使用3Bytes,英文字符只有1Bytes。
ps:unicode与uft-8比较:
unicode:简单粗暴,所有字符都是2Bytes,优点是字符->数字的转换速度快,缺点是占用空间大。(内存使用unicode速度快)
utf-8:精准,对不同的字符用不同的长度表示,优点是节省空间,缺点是:字符->数字的转换速度慢,因为每次都需要计算出字符需要多长的Bytes才能够准确表示。(硬盘使用utf-8节省空间)
3、字符编码的使用
以文本编辑器举例,不管时打开读取还是修改都是在内存中打开。
读取文件时,是decode的过程:把硬盘中utf-8格式的文本-》decode(翻译)-》内存unicode格式
保存文件时,是encode的过程:把内存中unicode格式的文本-》encode(翻译)-》硬盘中utf-8格式
4、python3与2中编码的区别
python3中所有的字符串都会被识别成unicode 字符编码。
python2中所有的字符串就是编码后的结果bytes字节。
二、文件处理
1、打开文件的两种方式:
1)open函数打开文件后需要close关闭
f = open('a.txt','r',encodeing='utf-8')
data = f.read()
print(data)
f.close()
2)with open打开文件后不需要关闭,使用with命令换行会自动缩进,缩进里的代码都是对文件的操作,退出缩进会自动关闭文件。
with open('a.txt','r',encoding='utf-8') as f:
data = f.read()
print(data)
2、文件操作模式:
open与with参数都一样。
参数一:a.txt,文件名,相对路径或绝对路径均可。
参数二:'r',操作模式,
r 只读,默认,文件不存在则报错,存在则读取,。
w 只写,不可读,文件不存在则创建,存在则写入(会先清空再写入),。
x 只写,不可读,文件不存在则创建,存在则报错。
a 追加,可读,不存在则创建 ,存在则只追加内容。
"+"表示可以同时读写某个文件
r+ 读写
w+ 写读
x+ 写读
a+ 写读
"b"表示以字节的方式操作
rb 或 r+b
wb 或 w+b
xb 或 x+b
ab 或 a+b
注:以b方式打开时,读取到的内容是了节类型,写入时也需要提供字节类型。
参数三:encodeing='utf-8',指定字符编码。
3、文件读取操作
1)读取文件,以读r的方式打开文件,有则清空,无则报错
f1 = open('a.txt',encoding='utf-8')
data = f1.read()
print(data)
2)读取文件,输出两次时,默认第二次输出为空。
因为读取是光标逐行读取的,第一次读取后光标会走到文件最后。
如果第二次想要打印出文件内容,需要使用seek将光标重新定位一文件开始位置。
f1 = open('a.txt','r', encoding='utf-8')
print(f1) #查看读取属性
print(f1.read())
f1.seek(0)
print(f1.read())
3)判断文件是否可读 (true false)
f1 = open('a.txt','r', encoding='utf-8')
data = f1.readable()
print(data)
f1.close()
4)逐行读取文件(不能把文件赋值),默认会打印换行符,使用end=''替换print自带的换行符为空
f1 = open('a.txt','r', encoding='utf-8')
print(f1.readline())
print(f1.readline(),end='')
print(f1.readline())
f1.close()
5)以列表形式显示文件
f1 = open('a.txt','r', encoding='utf-8')
print(f1.readlines())
f1.close()
4、文件写入操作
1)写文件,以写w的方式打开文件,有则清空,无则创建
逻辑为先清空内容,再写入,不重建文件,且不会修改文件创建时间,只更新修改时间
f1 = open('a.txt','w', encoding='utf-8')
2)判断文件是否可写 (true false)
f1 = open('a.txt','w', encoding='utf-8')
print(f1.writable())
3)写入文件内容
f1 = open('a.txt','w', encoding='utf-8')
f1.write('111
222
333')
f1.write('
444
555
666')
f1.close
4)以列表格式写入文件内容
f1 = open('a.txt','w', encoding='utf-8')
f1.writelines(['111','222','333'])
f1.close
5)追加文件内容
f1 = open('a.txt','a', encoding='utf-8')
f1.write('777
888
999')
f1.close)
6)模拟文件修改,判断修改文件,循环文件,判断,逐条写入文件2,遇到匹配进行修改并写入修改后的内容,最后使用os模块覆盖原文件
import os #导入os模块
read_f = open('a.txt','r', encoding='utf-8')
write_f = open('a.txt.swap','w', encoding='utf-8')
for line in read_f.readlines(): #循环显示文件列表
if line.startswith('111'): #判断如果以‘111’开头
line='999
' #修改111为999
write_f.write(line) #读取一条写入到.swap文件,如匹配判断条件,则写入修改后的内容
read_f.close()
write_f.close()
#覆盖原文件
os.remove('a.txt') #删除原文件
os.rename('a.txt.swap','a.txt') #重命名文件a.txt.swap为a.txt
5、bytes模式操作文件
以bytest模式操作文件时,读取时显示为二进制,并且只能写入二进制。
1)以bytes模式读取文件,显示二进制
with open('a.txt','rb') as f:
print(f.read())
2)以bytes模式写入文件,需要加encode
with open('a.txt','wb') as f:
f.write('牛牛牛'.encode('utf-8'))
3)bytes模式常用环境
文本的方式读不了二进制文件,硬盘上存储的都是二进制数据,除了文本之外,其它的都需要以二进制方式打开如.jpg格式。
with open('zly.jpg','rb') as read_f,open('zly_new.jpg','wb') as write_f:
data = read_f.read()
write_f.write(data)
三、补充
1、三元表达式
三元表达式(精简),条件成立写左边x,不成立写右边y
正常写法:
x = 10
y = 2
if x > y:
print(x)
else:
print(y)
三元表达式:result = 值1 条件 值2,如果条件成立,那么将 “值1” 赋值给result变量,否则,将“值2”赋值给result变量
result = x if x > y else y
print(result)
2、文件内光标移动*
注意:read(3)代表读取3个字符,其余的文件内光标移动都是以字节为单位如seek,tell,read,truncate
1)read()
with open('a.txt','r',encoding='utf-8') as f:
print(f.read(3))
2)seek() 参数一是位移值指从开始第第几个字符,参数二是起始位置包含0、1、2三个值,0表示文件起始位置,1表示当前位置,2表示文件结尾位置(1和2常用于rb模式)
with open('a.txt','r',encoding='utf-8') as f:
f.seek(0) #将光标移动到文件起始位置。
f.seek(3) #默认情况,是以文件起始位置作为开始,往后移动3个bytes,#当前光标在第三个字节后,打印就会打印第三个字节后的内容
f.seek(2,1) #1 代表以当前光标所在的位置为开始,往后移动2个 bytes
f.seek(-1,2) # 2表以文件结尾位置为开始,往回移动1个 bytes,
都算一个bytes
3)tell() ,显示当前所在的字节位置,打印3
with open('a.txt','r',encoding='utf-8') as f:
f.seek(3)
print(f.tell())
4)truncate() 截断,truncate内指定的数字代表字节,指保留从开始到指定数字。写入操作,打开文件时需要用r+ 。
a.txt 你瞅啥 #一个汉字代表三个字节,打印前6个字节,最终结果显示 你瞅
with open('a.txt','r+',encoding='utf-8') as f:
f.truncate(6)
3、for循环返回值
对for循环执行成功后的返回值提示,如遇到break则不会执行。
with open('a.txt','r',encoding='utf-8') as f:
for i in f:
print(i)
#break
else:
print("执行成功!")
四、函数
1、函数的特点
1)可读性高
2)统一管理且维护成本低
3)有组织有结构,一次定义多次调用
2、函数的分类
1)内置函数
内置函数是内置在python中的,可以直接调用。
如:sum、max、min、len等。
b = sum([1,2])
print(b)
2)自定义函数
为什么要定义函数?:先定义后使用,如果没有定义而直接使用,就相当于引用了一个不存在的变量名
def foo():
print('from foo')
print(foo)
函数的使用包含两个阶段:定义阶段和使用阶段
语法
def 函数名(参数1,参数2,...):
"""文档注释"""
函数体
return 值
x=len('hello')
print(x)
函数的定义主要有如下要点:
def:表示函数的关键字
函数名:函数的名称,日后根据函数名调用函数
函数体:函数中进行一系列的逻辑计算,如:发送邮件、计算出 [11,22,38,888,2]中的最大数等...
参数:为函数体提供数据
返回值:当函数执行完毕后,可以给调用者返回数据。
自定义函数例:
def print_star(): #定义函数
print('*'*6) #函数体
def print_msg():
print('hello world')
调用:
print_star() #调用函数
print_star()
print_msg() #调用函数
print_star()
print_star()
结果:
******
******
hello world
******
******
3、定义函数的形式以及调用函数
1)无参,如果函数的功能仅仅只是执行一些操作而已,就定义成无参函数,无参函数通常都有返回值,
def print_star():
print('#'*6)
2)有参函数:函数的功能的执行依赖于外部传入的参数,有参函数通常都有返回值
def my_max(x,y):
res=x if x >y else y
return res
3)调用函数,按照有参和无参可以将函数调用分两种
def foo():
print('from foo')
def bar(name):
print('bar===>',name)
foo() #定义时无参,调用时也无需传入参数
bar('egon') #定义时有参,调用时也必须有参数
4)按照函数的调用形式和出现的位置分三种
(1)调用函数的语句形式
def foo():
print('from foo')
foo()
(2)调用函数的表达式形式,xy传参乘以10000000
def my_max(x,y):
res=x if x >y else y
return res
res=my_max(1,2)*10000000
print(res)
(3)把函数调用当中另外一个函数的参数
def my_max(x,y):
res=x if x >y else y
return res
res=my_max(my_max(10,20),30)
print(res)
4、函数的返回值
1)三种情况返回值都为None:
没有return
return 什么都不写
return None
2)return 一个值 函数调用返回的结果就是这个值
def foo():
print('from foo')
x=1
return x
res=foo()
print(res)
3)return 值1,值2,值3,... 返回结果:(值1,值2,值3,...)
def foo():
print('from foo')
x=1
return 1,[2,3],(4,5),{}
res=foo()
print(res) #打印结果:(1,[2,3],(4,5),{})
a,b,c,d=foo()
print(d)
4)序列的解压
t=(1,2,3)
a,b,c=t
print(a) #打印1
print(b) #打印2
print(c) #打印3
只要第一个值,其它值使用_下划线占位
t=(1,2,3)
a,_,_=t
print(a) #只打印a的值1
只要开头和结尾的值,中间使用*_占位中间所有参数
t=(1,2,3,4,5,6)
a,*_,c=t
print(a,c) #只打印开头和结尾的值,执行结果打印 1 6
5、函数的参数
1)形参(变量名),实参(值)。
x和y为形参(变量名),1和2为实参(值),最后执行结果打印1 2 。
#定义阶段
def foo(x,y): #x=1,y=2
print(x)
print(y)
#调用阶段
foo(1,2)
详细的区分函数的参数分为五种:
位置参数,关键字参数,默认参数,可变长参数(*args,**kwargs),命名关键字参数
2)位置参数
def foo(x,y,z):#位置形参:必须被传值的参数
print(x,y,z)
foo(1,2,3) #位置实参数:与形参一一对应
3)关键字参数:key=value
def foo(x,y,z):
print(x,y,z)
foo(z=3,x=1,y=2)
关键字参数需要注意的问题:
1:关键字实参必须在位置实参后面
2: 不能重复对一个形参数传值
foo(1,z=3,y=2) #正确
foo(x=1,2,z=3) #错误
4)默认参数
def register(name,age,sex='male'): #形参:默认参数
print(name,age,sex)
register('asb',age=40)
默认参数需要注意的问题:
(1)默认参数必须跟在非默认参数后,否则在定义阶段就会报错
def register(sex='male',name,age): #在定义阶段就会报错
print(name,age,sex)
(2):默认参数在定义阶段就已经赋值了,而且只在定义阶段赋值一次,最终foo(1)结果为100000000。
a=100000000
def foo(x,y=a):
print(x,y)
a=0
foo(1)
(3)默认参数的值通常定义成不可变类型(如元组)。
5)可变长参数
(1)*args,*会把溢出的按位置定义的实参都接收,以元组的形式赋值给args
def foo(x,y,*args):
print(x,y)
print(args)
foo(1,2,3,4,5)
循环计算溢出参数:
def add(*args):
res=0
for i in args:
res+=i
return res
print(add(1,2,3,4))
print(add(1,2))
(2)**kwargs,**会把溢出的按关键字定义的实参都接收,以字典的形式赋值给kwargs
def foo(x, y, **kwargs):
print(x, y)
print(kwargs)
foo(1,2,a=1,name='egon',age=18)
判断如果溢出参数中有if的条件,则打印实参,最后调用函数。
def foo(name,age,**kwargs):
print(name,age)
if 'sex' in kwargs:
print(kwargs['sex'])
if 'height' in kwargs:
print(kwargs['height'])
foo('egon',18,sex='male',height='185')
foo('egon',18,sex='male')
6)命名关键字参数,*后定义的参数为命名关键字参数,这类参数,必须被传值,而且必须以关键字实参的形式去传值
def foo(name,age,*,sex='male',height):
print(name,age)
print(sex)
print(height)
foo('egon',17,height='185')
7) 补充:函数定义阶段到底干了什么事情:只检测函数体的语法,并不会执行
def bar():
x
if 1 >2:
print('====>')
#bar()