字符编码使用
1. 文本编辑器如何存取文件
文本编辑器相当一个运行在内存中的进程,所以文件内容在编辑未存储时都是在内存中的,尚未存储在硬盘之中,在没有保存之前,所编辑的任何文本都只是一堆字符,没有任何逻辑上的意义,当存储文件的时候需要以一定的编码格式存储于硬盘之中,当进行文件读取的时候也需要以同样的编码格式进行读取到内存之中进行操作,如果存储文件的编码和读取文件的编码不一致则会引起读取过程中的乱码导致文件操作失败。
P.S. --> Python解释器执行py文件的原理。
Step1. Python启动解释器(相当于文本编辑器)
Step2. 解释器从硬盘上将目标文件加载到内存中
Step3. 解释器执行代码得到结果(Python解释去具有文件读取和代码执行功能)
2. 字符编码的使用 --> 文件一什么编码方式保存的,就以什么编码方式打开
1. 在内存中文本是以Unicode二进制形式存在的
2. 保存文件时以文本编辑器指定的编码(比如UTF-8)encode后保存的硬盘中
3. 读取文件时文本编辑器同样需要以相同的编码格式将文件从硬盘decode后读取到内存中
4. 被读取到内存中的文件重新以Unicode二进制形式存在进行编辑
3. py程序的执行
-*- coding:utf-8 -*-
1. 当Python解释器读取py程序的第一行内容,即上一行所示内容,来确定用使用什么编码格式将py程序文件读入内存之中,也就是说这行决定了py解释器使用的编码格式,如果py文件中没有此项内容,那边使用编辑器默认的编码格式,Python2中是ASCII码,Python3中是UTF-8.
2. 当py编辑器将代码加载进入内存后就全不都是Unicode编码的二进制,代码执行过程中根据实际需要开辟新的内存空间,使用完毕后,会根据垃圾回收机制实现内存空间的释放。
P.S. 内存中文本的编码使用Unicode,不代表内存中全都是Unicode编码的二进制。在程序执行之前可以说全部都是Unicode编码的二进制,而在程序执行过程中会跟进程序的执行效果可以在内存中存放任意编码格式的数据。
4. Python2与Python3中字符串的区别
1. Python2中有两种字符串类型:
---> str类型:如果解释器执行到生成字符串的代码则会在内存中开辟新的空间,然后将字符串按照文件头指定的编码格式encode,所以在Python2中str=bytes是Unicode编码之后的结果
---> Unicode类型:同上左后所述,字符串以Unicode的格式编码存放到新的空间,只能进行encode操作。
2. Python3中也有两种字符串类型
---> str类型:str即unicode,可以encode为任意编码形式
---> bytes类型: 也可以encode为任意编码形式
1 s = ‘测试‘ 2 s1 = s.encode(‘utf-8‘) 3 s2 = s.encode(‘gbk‘) 4 5 print(s) 6 print(s1) 7 print(s2) 8 9 print(type(s)) 10 print(type(s1)) 11 print(type(s2))
文件处理
1. 文件处理流程
打开文件 -> 得到文件句柄 -> 复制给变量 -> 通过句柄对文件进行操作 -> 关闭文件
1 f = open(‘employee_info‘) # 打开问价 2 data_firstline = f.readline() # 读取文件第一行 3 data = f.read() # 读取文件全部内容 4 print(data_firstline) 5 print(data) 6 f.close() # 关闭文件 7 print(f.closed) #验证文件是否关闭成功返回布尔值
2.字符编码在文件处理中的问题
其实在字符编码章节中就提到过用什么字符编码保存的文件就需要用相同的字符编码打开,否则会产生乱码
比如:文件是以GBK方式保存的那么打开的时候使用UTF-8就会产生乱码的错误(Windows默认是GBK,Linux默认是UTF-8)
1 f=open(‘employee_info‘,encoding=‘utf-8‘)
3.文件打开模式
f=open(‘employee_info‘,‘模式‘)
通常解释器调取文件,我们需要在代码中指定文件路径和以何等方式打开文件。
打开文件的模式有:
r -> 只读,文件默认模式,没啥说的 -> r+ -> 可读可写 -> rb或r+b
w -> 只写,不可读,文件不存在时自动创建,若文件存在则会以新内容覆盖-> w+ -> 可读可写 -> wb 或 w+b
x -> 只写,不可读,文件不存在时自动创建,若文件存在报错-> x+ -> 可读可写 -> xb 或 w+b
a -> 追加,可读可写,文件不存在时自动创建,若文件存在只追加内容-> a+ -> 可读可写 -> ab 或 a+b
P.S. 以字节方式打开时,读取到的内容是自己类型,写入时也需要提供字节类型,不能指定编码
4. flush文件内置函数
为啥使用flush?
1. 文件操作是由解释器将文件从硬盘读出解码后加载到内存中去的
2. 由于文件在尚未保存之前都是在内存中的,如过断电的话所有修改为保存的文件信息都会丢失
3. 用flush的话会将内存中数据强制写进到硬盘中,减少断电带来的数据丢失问题,通常配合定时操作使用,定时刷文件进硬盘
1 import sys,time 2 for i in range(10): 3 sys.stdout.write(‘#‘) 4 sys.stdout.flush() 5 time.sleep(0.2)
5. 文件光标移动
1. read() -> 括号中加数字代表读取几个字符 2. seek() -> 可以指定光标移动的其实和结束位置,seek(0,0)即回到文件开始位置
1 # import time 2 with open(‘test‘,‘r‘, encoding= ‘utf-8‘) as f: 3 f.seek(0,2) 4 while True: 5 line = f.readline().strip() 6 if line: 7 print(‘new line add: ‘, line) 8 time.sleep(0.5)
6.上下文管理
1 with open(‘employee_info‘,‘r‘) as read_f,open(‘b.txt‘,‘w‘) as write_f: 2 data=read_f.read() 3 write_f.write(data)
7. 文件的修改
1 import os 2 with open(‘employee_info,‘r‘,encoding=‘utf-8‘) as read_f, 3 open(‘.employee_info.swap‘,‘w‘,encoding=‘utf-8‘) as write_f: 4 for line in read_f: 5 if line.startswith(‘hello‘): 6 line=‘byebye\n‘ 7 write_f.write(line) 8 9 os.remove(‘employee_info‘) # 将原文件删除 10 os.rename(‘.employee_info.swap‘,‘employee_info‘) # 将临时文件以原文件名称表示
Python函数
1. 什么是python函数
计算机编程中的函数是逻辑结构化和过程化的一种编程方法
1 def py_func(x): # def定义函数的关键字 / py_func是函数名 / 括号中的x为参数 2 "function description" # 函数文档描述,通常写在函数名下边一行 3 x = x + 1 # 函数代码块,执行具体功能 4 return x # 返回值
2. 为什么使用函数
1. 不使用函数的代码:
1. 代码重复过多,一个劲的copy and paste不符合高端程序员的气质
2. 如果日后需要修改发邮件的这段代码,比如加入群发功能,那你就需要在所有用到这段代码的地方都修改一遍
3. 不利于代码的维护和扩展
2. 如果使用函数
1. 代码重复利用度高,节省代码行数
2. 保持一致性,利于代码的维护和扩展
3. 代码简洁,可读性强
3. 定义函数的三种形式
1. 无参数函数:如果函数的功能仅仅只是执行一些操作而已,就定义成无参函数,无参函数通常都有返回值
1 def print_star(): 2 print(‘#‘*6)
2. 定义有参函数:函数的功能的执行依赖于外部传入的参数,有参函数通常都有返回值
1 def my_max(x,y): 2 res=x if x >y else y 3 return res
3. 空函数:用于软件功能的架构,在函数为具体实现之前
1 def insert(): 2 excute part 3 pass 4 def select(): 5 excute part 6 pass 7 def delete(): 8 excute part 9 pass 10 def update(): 11 excute part 12 pass
4. 三元表达式
1 res = x if x > y else y 如果x>y为True那么返回值为x否则为y
5. 并非真正函数的函数
Python有些函数运行完并不返回任何东西,这类函数也可以称作为过程,但是Python的函数就是函数
1 def test(): 2 print(‘this is test‘) 3 return # 没有返回值的return语句只起到结束函数的作用 4 print(‘this is not test‘) # 此语句的执行被跳过了 5 x = test() 6 print(x) # 返回值为None 7 由此可见,所有的函数都返回了东西,当不需要返回值的时候就返回none。需要注意。
6.函数调用
1.按照有参和无参可以将函数调用分两种
1. 定义时无参,调用时也无需传入参数
2. 定义时有参,调用时也必须有参数
2.按照函数的调用形式和出现的位置,分三种
1. 调用函数的语句形式 func()
2. 调用函数的表达式形式 res = func()
3. 把函数调用当中另外一个函数的参数 res = func(func(),args...)
7. 函数参数
函数被定义以后,是通过它的参数来获得一系列可以操作的值。这些参数的值并不因为函数而改变,在函数内为参数赋予新值不会改变外部任何变量的值
1 def args_ch(n): 2 n = ‘this is test‘ 3 name = ‘this is not test‘ 4 args_ch(name) 5 print(name) # name的值没有发生改变 6 字符串,数字以及元组是不可改变,只能用新的值覆盖。但是如果用列表做参数就不一样了。 7 def lst_ch(n): 8 n[0] = ‘this is a test‘ 9 name = [1,2,3,4] 10 lst_ch(name) 11 print(name) # [‘this is a test‘,2,3,4] 12 由于是两个变量引用了同一个列表,如果要避免这种状况,需要复制一个单独的副本操作,从而不会应到到原来的列表
从大的角度去看,函数的参数分两种:形参(变量名),实参(值)
形参(定义阶段):形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。
函数调用结束返回主调用函数后则不能再使用该形参变量
实参(调用阶段):实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,
以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值
详细的区分函数的参数分为五种:
1 1. 位置参数 2 def foo(x,y,z):#位置形参:必须被传值的参数 3 print(x,y,z) 4 foo(1,2,3) 5 foo(1,2,3) #位置实参数:与形参一一对应 6 7 2. 关键字参数(key=value) 8 def foo(x,y,z): 9 print(x,y,z) 10 foo(z=3,x=1,y=2) 11 关键字参数需要注意的问题: 12 1:关键字实参必须在位置实参后面 13 2: 不能重复对一个形参数传值 14 foo(1,z=3,y=2) #正确 15 foo(x=1,2,z=3) #错误 16 foo(1,x=1,y=2,z=3)#错误,会导致x被重复赋值 17 18 3. 默认参数 19 def register(name,age,sex=‘male‘): #形参:默认参数 20 print(name,age,sex) 21 register(‘asb‘,age=40) #正确 22 register(‘a1sb‘,39) #正确 23 register(‘钢蛋‘,20,‘female‘) #正确 24 register(‘钢蛋‘,sex=‘female‘,age=19) #正确 25 默认参数需要注意的问题: 26 1. 默认参数必须跟在非默认参数后 27 def register(sex=‘male‘,name,age): #错误 28 def register(name,age,sex=‘male‘): #正确 29 print(name,age,sex) 30 2. 默认参数在定义阶段就已经赋值了,而且只在定义阶段赋值一次 31 3. 默认参数的值通常定义成不可变类型 32 33 4. 可变长参数(*args,**kwargs) 34 1. *args 35 def foo(x,y,*args): # *会把溢出的按位置定义的实参都接收,以元组的形式赋值给args 36 print(x,y) # output:1 2 37 print(args) # output:(3, 4, 5) 38 foo(1,2,3,4,5) 39 40 def add(*args): # 可以灵活给函数添加参数 41 res=0 42 for i in args: 43 res+=i 44 return res 45 print(add(1,2,3,4)) 46 print(add(1,2)) 47 48 2. **kwargs 49 def foo(x, y, **kwargs): # **会把溢出的按关键字定义的实参都接收,以字典的形式赋值给kwargs 50 print(x, y) # output:1 2 51 print(kwargs) # output:{‘a‘: 1, ‘age‘: 18, ‘name‘: ‘egon‘} 52 foo(1,2,a=1,name=‘egon‘,age=18) 53 54 def foo(name,age,**kwargs): 55 print(name,age) 56 if ‘sex‘ in kwargs: 57 print(kwargs[‘sex‘]) 58 if ‘height‘ in kwargs: 59 print(kwargs[‘height‘]) 60 61 foo(‘egon‘,18,sex=‘male‘,height=‘185‘) 62 foo(‘egon‘,18,sex=‘male‘) 63 64 5. 命名关键字参数 65 def foo(name,age,*,sex=‘male‘,height): # *后定义的参数为命名关键字参数,这类参数,必须被传值,而且必须以关键字实参的形式去传值 66 print(name,age) 67 print(sex) 68 print(height) 69 foo(‘egon‘,17,height=‘185‘,sex=‘female‘)