Python开发3——字符编码、文件处理、函数
字符编码
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: #(可以同时打开多个文件)结束操作文件后,会自动关闭
#操作文件
f = open('a.txt', 'w', encoding='utf-8')
f.write('哈哈哈哈哈!')
f.close()
with open('a.txt', 'r',encoding='utf-8') as f1,open('b.txt', 'w', encoding='utf-8') as f2:
#文件操作
content = f1.read()
f2.write(content)

2、检测文件是否可读:
#fileObject.readable()
f = open('a.txt', 'a+', encoding='utf-8')
print(f.readable())
f.close()
3、检测文件是否可写:
#fileObject.writable()
f = open('a.txt', 'r+',encoding='utf-8')
print(f.writable())
f.close()
4、检测文件是否已关闭:
#fileObject.closed
f = open('a.txt', 'r+',encoding='utf-8')
f.close()
print(f.closed)
5、检测文件是否连接到一个终端设备:
#fileObject.isatty()
6、关闭文件
#fileObject.close()
f.write('啊啊啊')
print(f.read())
f.close()
7、读文件
①从文件中读取指定字符数,不加参数默认读取全文:
#fileObject.read(size)
#size:从文件中读取的字符数
f = open('a.txt', 'r+', encoding='utf-8')
print(f.read(3))
f.close()
②读取整行,包括 "\n" 字符:
#fileObject.readline()
f = open('a.txt', 'r+', encoding='utf-8')
print(f.readline())
f.close()
③读取所有行并返回列表:
#fileObject.readlines()
f = open('a.txt', 'r+',encoding='utf-8') print(f.readlines()) f.close()
8、写文件
①将字符串写入文件,返回写入的字符数
#fileObject.write( [ str ])
#str:要写入文件的字符串
f = open('a.txt', 'r+',encoding='utf-8')
print(f.write('我就是我啊哈哈'))
f.seek(0)
print(f.read())
f.close()
②向文件中写入一序列的字符串,换行需要制定换行符 \n
#fileObject.writelines( [ str ])
#str:要写入文件的字符串序列
f = open('a.txt', 'r+',encoding='utf-8')
print(f.writelines('我就是我\n啊哈哈ha'))
f.seek(0)
print(f.read())
f.close()
9、移动文件指针到指定位置:
#fileObject.seek(offset[, whence])
#offset:偏移量,即需要移动的字节数
#whence:可选,默认值为 0。0:从文件开头开始算起,1:从当前位置开始算起,2:从文件末尾算起(1,2模式只允许在二进制b模式下使用)
f = open('a.txt', 'r+',encoding='utf-8')
f.writelines('我就是我\n啊哈哈ha')
f.seek(3)
print(f.tell())
print(f.read())
f.close()
10、返回文件当前位置:
#fileObject.tell()
f = open('a.txt', 'br+')
f.seek(-1,2)
print(f.tell())
print(f.read())
f.close()
11、截断文件
#fileObject.truncate( [ size ])
'''
从文件的首行首字符开始截取,截取文件为size个字节;无size表示从当前位置起截取;
截取之后size后面的所有字符被删除。其中win下的换行代表2个字符大小。
'''
f = open('a.txt', 'r+',encoding='utf-8')
f.truncate(15)
print(f.read())
f.close()
12、刷新缓冲区
#fileObject.flush()
#即将缓冲区中的数据立刻写入文件,同时清空缓冲区
#一般情况,文件关闭后会自动刷新缓冲区,但有时你需要在关闭前刷新它,这时就可以使用 flush() 方法
13、返回一个整型的文件描述符,可用于底层操作系统的 I/O 操作
#fileObject.fileno()
函数
一、函数的分类
1、内置函数:
python本身自己定义的函数,可直接调用。
2、自定义函数:
自己根据需求,按照函数定义方法去自定函数。
二、定义函数
1、定义函数的语法
Python 定义函数使用 def 关键字,一般格式如下:
def 函数名(参数列表):
函数体
2、定义函数的三种形式
①无参数函数
②有参函数
③空函数:
#在一开始思考代码架构时,可以先把扩展功能写下来,后期完善
def insert(): """插入功能""" pass def select(): """查询功能""" pass
注:三元表达式
x=10 y=2 # if x > y: # print(x) # else: # print(y) # 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 传不可变对象实例:
def ChangeInt( a ):
a = 10
b = 2
ChangeInt(b)
print( b ) # 结果是 2
实例中有 int 对象 2,指向它的变量是 b,在传递给 ChangeInt 函数时,按传值的方式复制了变量 b,a 和 b 都指向了同一个 Int 对象,在 a=10 时,则新生成一个 int 值对象 10,并让 a 指向它。
②传可变对象实例:
可变对象在函数里修改了参数,那么在调用这个函数的函数里,原始的参数也被改变了。例如:
def changeme( mylist ):
'''修改传入的列表'''
mylist.append([1,2,3,4]);
print ("函数内取值: ", mylist)
return
# 调用changeme函数
mylist = [10,20,30];
changeme( mylist );
print ("函数外取值: ", mylist)
传入函数的和在末尾添加新内容的对象用的是同一个引用。故输出结果如下:
函数内取值: [10, 20, 30, [1, 2, 3, 4]] 函数外取值: [10, 20, 30, [1, 2, 3, 4]]
四、函数的参数
1、位置参数
def foo(x,y,z):#位置形参:必须被传值的参数
print(x,y,z)
foo(1,2,3) #位置实参:与形参一一对应
2、关键字参数
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) #错误
# foo(1,x=1,y=2,z=3)#错误
3、默认参数
def register(name,age,sex='male'): #形参:默认参数
print(name,age,sex)
register('asb',age=40)
register('a1sb',39)
register('钢蛋',20,'female')
register('钢蛋',sex='female',age=19)
#默认参数需要注意的问题:
# 一:默认参数必须跟在非默认参数后
# def register(sex='male',name,age): #在定义阶段就会报错
# print(name,age,sex)
# 二:默认参数在定义阶段就已经赋值了,而且只在定义阶段赋值一次
# a=100000000
# def foo(x,y=a):
# print(x,y)
# a=0 #a在函数外的指向变化,对函数中的y值无影响
# foo(1)
#三:默认参数的值通常定义成不可变类型
4、可变长参数
①*args:
*会把溢出的按位置定义的实参都接收,以元组的形式赋值给args。
def foo(x,y,*args):
print(x,y)
print(args)
foo(1,2,*[3,4,5])
foo(1,2,3,4,5)
输出:
1 2 (3, 4, 5)
1 2 (3, 4, 5)
②**kwargs:
**会把溢出的按关键字定义的实参都接收,以字典的形式赋值给kwargs
def foo(name,age,**kwargs):
print(name,age)
for k in kwargs.keys():
print(kwargs[k])
foo('egon',18,**{'sex':'male','height':'185'})
#foo('egon',18,sex='male',height='185')
foo('egon',18,sex='male')
输出:
egon 18 male 185 egon 18 male
5、命名关键字参数
如下,*后定义的命名关键字参数必须被传值,且必须以关键字实参的形式传值
def foo(name,age,*,sex='male',height):
print(name,age)
print(sex)
print(height)
#*后定义的参数为命名关键字参数,这类参数,必须被传值,而且必须以关键字实参的形式去传值
foo('egon',17,height='185')
注:
传值顺序:位置参数、默认参数、*args、命名关键字参数、**kwargs
五、匿名函数

浙公网安备 33010602011771号