一.字符编码
1、字符编码的发展史
阶段一:ASCII
一个Bytes代表一个字符(英文字符/键盘上的所有其他字符),1Bytes=8bit,8bit可以表示256(2**8)个字符。
阶段二:GBK
为了满足中文,中国人定制了GBK,2Bytes代表一个字符。
阶段三:Unicode(万国码)
Unicode编码系统为表达任意语言的任意字符而设计,规定所有的字符和符号最少由 16 位来表示(2个字节),即:2 **16 = 65536
阶段四:UTF-8
对Unicode编码的压缩和优化,ascii码中的内容用1个字节保存、欧洲的字符用2个字节保存,东亚的字符用3个字节保存。
注:
Unicode:简单粗暴,所有字符都是2Bytes。
优点:字符->数字的转换速度快
缺点:占用空间大
utf-8:精准,对不同的字符用不同的长度表示
优点:节省空间
缺点:字符->数字的转换速度慢,因为每次都需要计算出字符需要多长的Bytes才能够准确表示
内存中使用的编码是unicode:
用空间换时间(程序都需要加载到内存才能运行,因而内存应该是尽可能的保证快)
硬盘中或者网络传输用utf-8:
网络I/O延迟或磁盘I/O延迟要远大与utf-8的转换延迟,而且I/O应该是尽可能地节省带宽,保证数据传输的稳定性。
2、文本编辑器存取文件的原理(nodepad++,pycharm,word)
打开编辑器就启动了 一个进程,是在内存中的,所以在编辑器编写的内容也都是存放于内存中的,断电后数据丢失,因而需要保存到硬盘上。
点击保存按钮,就从内存中把数据刷到了硬盘上。在这一点上,我们编写一个py文件(没有执行),跟编写其他文件没有任何区别,都只是在编写一堆字符而已。
无论是何种编辑器,要防止文件出现乱码,核心法则就是,文件以什么编码保存的,就以什么编码方式打开。
3、Python解释器执行py文件的原理 (python test.py)
阶段一:python解释器启动,此时就相当于启动了一个文本编辑器
阶段二:python解释器相当于文本编辑器,去打开test.py文件,从硬盘上将test.py的文件内容读入到内存中
阶段三:python解释器解释执行刚刚加载到内存中test.py的代码
注:
(1)文件编码:# -*- coding:utf-8 -*-(在py文件中加此注释:告诉python解释器,用什么编码来执行源代码,并防止用py2时出错)
(2)Python解释器编码:(py3:utf-8;py2:ascii)
(3)#!/usr/bin/python(在py文件中加此注释:防止脚本在Linux上使用)
①必须是文件的第一行
②#!开头的,说明是脚本
③/path/to/script/interpreter是脚本解释器的全路径名
④有时不太清楚脚本解释器的具体全路径名;或者开发环境与运行环境的安装路径不同。为了保证兼容性,也可以写作:
#!/usr/bin/env python3
这样运行时会自动搜索脚本解释器的绝对路径
4、python2和python3的一些不同
(1)python2中默认使用ascii,python3中默认使用utf-8
(2)Python2中,str就是编码后的结果bytes,str=bytes,所以s只能decode。
(3)python3中的字符串与python2中的u'字符串',都是unicode,只能encode,所以无论如何打印都不会乱码,因为可以理解为从内存打印到内存,即内存->内存,unicode->unicode。
(4)python3中,str是unicode,当程序执行时,无需加u,str也会被以unicode形式保存新的内存空间中,str可以直接encode成任意编码格式,s.encode('utf-8'),s.encode('gbk')。
#unicode(str)-----encode---->utf-8(bytes)
#utf-8(bytes)-----decode---->unicode
(5)在windows终端编码为gbk,linux是UTF-8。
二.文件处理
文件处理
一、文件处理流程
1、打开文件,得到文件句柄并赋值给一个变量
2、通过句柄对文件进行操作
3、关闭文件
二、文件对象的方法
1、打开文件
①open(file, mode='r', encoding=None),结束操作文件后,需使用close(file)关闭文件
file:文件的相对或绝对路径
mode:文件打开模式
encoding:编码方式
②with open(file1, mode='r',encoding=None) as f1,open(file2, mode='r', encoding=None) as f2: #(可以同时打开多个文件)结束操作文件后,会自动关闭
#操作文件
1 f = open('a.txt', 'w', encoding='utf-8') 2 f.write('哈哈哈哈哈!') 3 f.close() 4 5 with open('a.txt', 'r',encoding='utf-8') as f1,open('b.txt', 'w', encoding='utf-8') as f2: 6 #文件操作 7 content = f1.read() 8 f2.write(content)
2、检测文件是否可读:
1 #fileObject.readable() 2 3 f = open('a.txt', 'a+', encoding='utf-8') 4 print(f.readable()) 5 f.close()
3、检测文件是否可写:
1 #fileObject.writable() 2 3 f = open('a.txt', 'r+',encoding='utf-8') 4 print(f.writable()) 5 f.close()
4、检测文件是否已关闭:
1 #fileObject.closed 2 3 f = open('a.txt', 'r+',encoding='utf-8') 4 f.close() 5 print(f.closed)
5、检测文件是否连接到一个终端设备:
#fileObject.isatty()
6、关闭文件
1 #fileObject.close() 2 3 f.write('啊啊啊') 4 print(f.read()) 5 f.close()
7、读文件
①从文件中读取指定字符数,不加参数默认读取全文:
1 #fileObject.read(size) 2 #size:从文件中读取的字符数 3 f = open('a.txt', 'r+', encoding='utf-8') 4 print(f.read(3)) 5 f.close()
②读取整行,包括 " " 字符:
1 #fileObject.readline() 2 3 f = open('a.txt', 'r+', encoding='utf-8') 4 print(f.readline()) 5 f.close()
③读取所有行并返回列表:
1 #fileObject.readlines()<br><br>f = open('a.txt', 'r+',encoding='utf-8') 2 print(f.readlines()) 3 f.close()
8、写文件
①将字符串写入文件,返回写入的字符数
1 fileObject.write( [ str ]) 2 #str:要写入文件的字符串 3 4 f = open('a.txt', 'r+',encoding='utf-8') 5 print(f.write('我就是我啊哈哈')) 6 f.seek(0) 7 print(f.read()) 8 f.close()
②向文件中写入一序列的字符串,换行需要制定换行符
1 #fileObject.writelines( [ str ]) 2 #str:要写入文件的字符串序列 3 4 f = open('a.txt', 'r+',encoding='utf-8') 5 print(f.writelines('我就是我 啊哈哈ha')) 6 f.seek(0) 7 print(f.read()) 8 f.close()
9、移动文件指针到指定位置:
1 #fileObject.seek(offset[, whence]) 2 #offset:偏移量,即需要移动的字节数 3 #whence:可选,默认值为 0。0:从文件开头开始算起,1:从当前位置开始算起,2:从文件末尾算起(1,2模式只允许在二进制b模式下使用) 4 5 f = open('a.txt', 'r+',encoding='utf-8') 6 f.writelines('我就是我 啊哈哈ha') 7 f.seek(3) 8 print(f.tell()) 9 print(f.read()) 10 f.close()
10、返回文件当前位置:
1 #fileObject.tell() 2 3 f = open('a.txt', 'br+') 4 f.seek(-1,2) 5 print(f.tell()) 6 print(f.read()) 7 f.close()
11、截断文件
1 #fileObject.truncate( [ size ]) 2 ''' 3 从文件的首行首字符开始截取,截取文件为size个字节;无size表示从当前位置起截取; 4 截取之后size后面的所有字符被删除。其中win下的换行代表2个字符大小。 5 ''' 6 f = open('a.txt', 'r+',encoding='utf-8') 7 f.truncate(15) 8 print(f.read()) 9 f.close()
12、刷新缓冲区
1 #fileObject.flush() 2 #即将缓冲区中的数据立刻写入文件,同时清空缓冲区 3 #一般情况,文件关闭后会自动刷新缓冲区,但有时你需要在关闭前刷新它,这时就可以使用 flush() 方法
13、返回一个整型的文件描述符,可用于底层操作系统的 I/O 操作
#fileObject.fileno()
14.上下文管理with语句
1 with open("/tmp /foo.txt") as file: 2 data = file.read()
with的基本思想是with所求值的对象必须有一个__enter__()方法,一个__exit__()方法。紧跟with后面的语句被求值后,返回对象的__enter__()方法被调用,这个方法的返回值将被赋值给as后面的变量。当with后面的代码块全部被执行完之后,将调用前面返回对象的__exit__()方法。
15.补充
模拟 tail -f access.log
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 # tail -f access.log 5 import time 6 with open('access.log','r',encoding='utf-8') as f: 7 f.seek(0,2) 8 while True: 9 line=f.readline().strip() 10 if line: 11 print('新增一行日志',line) 12 time.sleep(0.5)
函数
一、函数的分类
1、内置函数:
python本身自己定义的函数,可直接调用。
2、自定义函数:
自己根据需求,按照函数定义方法去自定函数。
二、定义函数
1、定义函数的语法
Python 定义函数使用 def 关键字,一般格式如下:
def 函数名(参数列表):
函数体
2、定义函数的三种形式
①无参数函数
②有参函数
③空函数:
1 #在一开始思考代码架构时,可以先把扩展功能写下来,后期完善<br>def insert(): 2 """插入功能""" 3 pass 4 def select(): 5 """查询功能""" 6 pass
注:三元表达式
1 x=10 2 y=2 3 # if x > y: 4 # print(x) 5 # else: 6 # print(y) 7 # 8 9 res=x if x > y else y print(res)
二、函数调用
三、参数传递
1、在 python 中,类型属于对象,变量是没有类型的:
a=[1,2,3]
a="Runoob"
以上代码中,[1,2,3] 是 List 类型,"Runoob" 是 String 类型,而变量 a 是没有类型,它仅仅是一个对象的引用(一个指针)。
2、可更改(mutable)与不可更改(immutable)对象
在 python 中,strings, tuples, 和 numbers 是不可更改的对象,而 list,dict 等则是可以修改的对象。
①不可变类型:
变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变a的值,相当于新生成了a。
②可变类型:
变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。
3、python 函数的参数传递
python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象
①不可变类型:
类似 c++ 的值传递,如 整数、字符串、元组。如fun(a),传递的只是a的值,没有影响a对象本身。
②可变类型:
类似 c++ 的引用传递,如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后fun外部的la也会受影响。
4、python参数传递实例
①python 传不可变对象实例:
1 def ChangeInt( a ): 2 a = 10 3 4 b = 2 5 ChangeInt(b) 6 print( b ) # 结果是 2
实例中有 int 对象 2,指向它的变量是 b,在传递给 ChangeInt 函数时,按传值的方式复制了变量 b,a 和 b 都指向了同一个 Int 对象,在 a=10 时,则新生成一个 int 值对象 10,并让 a 指向它。
②传可变对象实例:
可变对象在函数里修改了参数,那么在调用这个函数的函数里,原始的参数也被改变了。例如:
1 def changeme( mylist ): 2 '''修改传入的列表''' 3 mylist.append([1,2,3,4]); 4 print ("函数内取值: ", mylist) 5 return 6 7 # 调用changeme函数 8 mylist = [10,20,30]; 9 changeme( mylist ); 10 print ("函数外取值: ", mylist)
传入函数的和在末尾添加新内容的对象用的是同一个引用。故输出结果如下:
1 函数内取值: [10, 20, 30, [1, 2, 3, 4]] 2 函数外取值: [10, 20, 30, [1, 2, 3, 4]]
四、函数的参数
1、位置参数
1 def foo(x,y,z):#位置形参:必须被传值的参数 2 print(x,y,z) 3 4 foo(1,2,3) #位置实参:与形参一一对应
2、关键字参数
1 def foo(x,y,z): 2 print(x,y,z) 3 4 foo(z=3,x=1,y=2) 5 6 #关键字参数需要注意的问题: 7 # 1:关键字实参必须在位置实参后面 8 # 2: 不能重复对一个形参传值 9 10 # foo(1,z=3,y=2) #正确 11 # foo(x=1,2,z=3) #错误 12 # foo(1,x=1,y=2,z=3)#错误
3、默认参数
1 def register(name,age,sex='male'): #形参:默认参数 2 print(name,age,sex) 3 4 register('asb',age=40) 5 register('a1sb',39) 6 7 register('钢蛋',20,'female') 8 register('钢蛋',sex='female',age=19) 9 10 #默认参数需要注意的问题: 11 # 一:默认参数必须跟在非默认参数后 12 # def register(sex='male',name,age): #在定义阶段就会报错 13 # print(name,age,sex) 14 15 # 二:默认参数在定义阶段就已经赋值了,而且只在定义阶段赋值一次 16 # a=100000000 17 # def foo(x,y=a): 18 # print(x,y) 19 # a=0 #a在函数外的指向变化,对函数中的y值无影响 20 # foo(1) 21 22 #三:默认参数的值通常定义成不可变类型
4、可变长参数
①*args:
*会把溢出的按位置定义的实参都接收,以元组的形式赋值给args。
1 def foo(x,y,*args): 2 print(x,y) 3 print(args)<br> 4 foo(1,2,*[3,4,5]) 5 foo(1,2,3,4,5)
输出:
1 1 2 2 (3, 4, 5)<br><br>1 2 3 (3, 4, 5)
②**kwargs:
**会把溢出的按关键字定义的实参都接收,以字典的形式赋值给kwargs
1 def foo(name,age,**kwargs): 2 print(name,age)<br> for k in kwargs.keys():<br> print(kwargs[k]) 3 4 foo('egon',18,**{'sex':'male','height':'185'}) 5 #foo('egon',18,sex='male',height='185') 6 foo('egon',18,sex='male')
输出:
1 egon 18 2 male 3 185 4 egon 18 5 male
5、命名关键字参数
如下,*后定义的命名关键字参数必须被传值,且必须以关键字实参的形式传值
1 def foo(name,age,*,sex='male',height): 2 print(name,age) 3 print(sex) 4 print(height) 5 #*后定义的参数为命名关键字参数,这类参数,必须被传值,而且必须以关键字实参的形式去传值 6 foo('egon',17,height='185')
注:
五、匿名函数