文件操作:   

打开文件的方法:

 

第一种:打开文件执行完命令后,需要关闭文件,否则会一直占用内存空间

f=open('/data/1.txt','r+')    #后面的r+ 表示打开文件的模式是读写

#命令 

f.close     #关闭文件 

 

第二种:这种会自动关闭文件,不用我们手动关闭,这种写法被称为python中的语法糖。

with open('/data/1.txt','r+') as f:

    #命令  

 

##################

打开文件的模式:

r : 只读模式,默认如果不加模式就是只读模式   

r+: 读写模式,读,写,追加,如果文件不存在会报错。   

w:只写模式  ,会覆盖文件内容,如果文件不存在会创建

w+: 写读模式 ,会覆盖文件内容,如果文件不存在会创建

a:追加模式  ,如果文件不存在会创建

a+:和a的意思一样     

b :二进制(字节)模式处理文件。 当需要处理二进制文件时,需要加一个b,比如rb,wb,ab, 需要注意的是b的方式在打开或写入时不能指定编码格式,只能打开后加.decode('utf-8')进行解码,  用wb方式写入时需要将字符串转化为字节

 

###########################################################

 

小例子:编码错误



#!/usr/bin/env python
# encoding:utf-8

f = open('歌词','r')
data = f.read()
f.close()

print(data) 

#执行结果:
UnicodeDecodeError: 'gbk' codec can't decode byte 0x80 in position 22: illegal multibyte sequence  

#分析
当时编辑 '歌词' 这个文件时,我的编辑器的编码是utf-8 , 所以 '歌词' 这个文件编码就是utf-8, 现在用open()函数打开,open()函数会去找系统的默认编码,windows的系统一般是gbk编码格式的,所以会报错,而mac默认编码就是utf-8,打开就不会报错了,这里的解决办法是在打开文件时,指定编码格式

# 指定编码格式
f = open('歌词','r',encoding='utf-8')
data = f.read()
f.close()

print(data)



 

小例子: 二进制模式读取文件



#错误示例:
f = open('666.txt','rb',encoding='utf-8')
data = f.read()
f.close()
print(data)  

#执行结果
ValueError: binary mode doesn't take an encoding argument  
# 二进制模式处理文件时,不能用encoding 指定编码  

#正确示例:
f = open('666.txt','rb')
data = f.read()
f.close()
print(data) 

#执行结果:
b'66666\r\n2312313'    
# 注意windows 中的换行符是  \r\n  而linux中是\n  开头的b表示字节

#特别注意:当666.txt 这个文件里有中文,这个时候print (data) 会出现 xe4\xb8 这种16进制的,无法看到中文,这个时候需要用.decode()解码,print(data.decode())




 

小例子:二进制模式写文件



#错误示例

txt1='''
又一年花如绣,山中雪埋红豆。
曾是谁把盏问,可饮一杯否。
'''
f=open(txt1.log,'wb')
f.write(txt1)
f.close()

#执行结果    
TypeError: a bytes-like object is required, not 'str' 
#字符串不能用b写入,必须转化成字节  

#正确示例  

f=open('txt1.log','wb')
f.write(txt1.encode(encoding='utf-8'))
f.close()
#分析:因为用b写文件必须转成字节格式,所以用encode()编码,encode()里面可以指定编码格式,我这里是utf8,特别注意,前面说过b模式不能指定编码格式,说的是用open()函数打开的时候不能指定,我在打开后指定的
#bytes() 函数也可以转换成字节,bytes(txt1,encoding='utf-8')



 

#字符串  ---------- encode() -----------> 字节   ,编码过程 

#字节   ---------- decode() -----------> 字符串   ,解码过程 

 

 

下面来看用with处理文件的小例子:  



txt1='''
又一年花如绣,山中雪埋红豆。
曾是谁把盏问,可饮一杯否。
'''

with open('123.txt','a') as f:
    f.write(txt1)


with open('123.txt','r') as f:
    a=f.read()

with open('123.txt','r') as f:
    b=f.read(9)

print(a)
print(b)  

#执行结果:
又一年花如绣,山中雪埋红豆。
曾是谁把盏问,可饮一杯否。


又一年花如绣,山



上面这段代码会把txt1中的内容追加到123.txt这个文件中。  然后用read()读出全部赋值给a并打印出来,也可以指定读取的字符长度,赋值给b打印出来。但是:如果文件大的话不要用read()这种方法,可能不能全部读出来

特别注意:文件操作中除了read()方法 是读取的字符,其他方法都是读取的字节,在utf-8编码中,一个汉字占3个字节

 

除了用read读之外还好有其他方式,下面来介绍:



with open('123.txt','r') as f:
    line1=f.readline()
    
print (line1)



line1的结果: 又一年花如绣,山中雪埋红豆。

说明readline()只读了一行。 如果要读全部内容那就用循环去一行一行的读呗,如下方法:



with open('123.txt','r') as f:
    while True:
        line1=f.readline()
        if len(line1) == 0:
            break
        print (line1)



readline()用这种循环的方法就把全部内容都读了出来!

   

 



with open('123.txt','r') as f:

    line2=f.readlines()
    

print (line2)



line2的结果:['又一年花如绣,山中雪埋红豆。\n', '曾是谁把盏问,可饮一杯否。\n']

说明readlines() 全读出来了,但读出来的是一个列表。  当文件很大的时候不建议用这种 ,可能会出现卡住的情况

   

 

小例子:write写文件的时候只能写字符串  , writelines 可以写列表,但是列表中的元素必须是字符串



f = open('1.txt','w',encoding='utf-8')
#用write写的时候只能写字符串
f.write('11111111111\n')
#如果不加换行符,会写在一行里
f.write('2222222222222\n')
#用writelines 可以写列表,但是列表中的元素必须是字符串
f.writelines(['1\n','2\n'])
f.close()



 

 获取真正的换行符



# 前面的例子说过,二进制模式rb读取文件时,可以看到windows系统的换行符是 \r\n   
# 假如不用二进制模式打开,用默认的文本模式打开看到换行符不是  \r\n    

f = open('1.txt','r')
data = f.readlines()
f.close()
print(data)  

#执行结果: 
['11111111111\n', '2222222222222\n', '1\n', '2\n']    

# 分析,因为python 会处理来自不同系统的文件,所以python内部做了转换,统一把换行符转成 \n ,如果要显示真实的换行符 可以在打开文件时加  newline=''   

f = open('1.txt','r',newline='')
data = f.readlines()
f.close()
print(data) 

# 执行结果:
['11111111111\r\n', '2222222222222\r\n', '1\r\n', '2\r\n']



 

 

文件游标    



with open('333.txt','w') as f:
    f.write(txt3)
with open('333.txt','r') as f:
    print(f.tell())
    print (f.readline().strip()) #strip表示去掉换行符和空格
    print(f.readline().strip())
    print(f.tell())
    f.seek(0)
    print(f.readline().strip())  

#执行结果:
0
121212121233
qwertyu
23
121212121233



说明:tell() 方法会显示当前的指针(游标)位置,第一次肯定是0,然后读了两行,那指针位置就是在两行之后,然后用seek(0)方法把指针位置调整到0,seek()方法控制指针的位置。再次读取一行,还是读取的第一行,因为指针在哪,就从哪里开始读。   

 

 seek()方法的高级用法



seek() 方法的作用就是控制指针的位置
seek() 方法其实有三种模式,分别是  0 , 1 , 2  我下面会举例说明

第一种 0模式,从头开始(默认的模式)


text = '''123333456789
qwertyuio
我是好人
666'''

f = open('seek.log','w',encoding='utf-8')
f.write(text)
f.close()

f = open('seek.log','r',encoding='utf-8')
print(f.tell())
f.seek(5)
print(f.tell())
f.seek(6,0)
print(f.tell())
print(f.read())
f.close()  

#执行结果:
0
5
6
456789
qwertyuio
我是好人
666  

#分析: 第一个f.tell() 肯定是0, 因为文件开头指针肯定是0, 然后f.seek(5)把指针从开头往后移动了5个字节, 那现在的f.tell()就是5, 然后又f.seek(6,0)从头开始移动6个字节, 现在的f.tell() 指针位置就是6,  最后f.read()的结果就是把指针后面的全部读取, 指针在6, 所以把第6个字节后面的全部读取  
#这种模式就是0模式, 可以写成 f.seek(5,0),  因为0可以省略, 一般就写 f.seek(5) 就行了   


第二种,   1模式,相对路径

f = open('seek.log','rb')
print(f.tell())
f.seek(5)
print(f.tell())
f.seek(6,1)
print(f.tell())
print(f.read().decode())
f.close()

#执行结果:
0
5
11
9
qwertyuio
我是好人
666  

#分析:   第一个f.tell() 肯定是0, 因为文件开头指针肯定是0, 然后f.seek(5)这是第一个seek(), 把指针从开头往后移动了5个字节, 那现在的f.tell()就是5,  然后又f.seek(6,1)从当前指针的位置, 也就是第5个字节的位置又移动6个字节, 现在的f.tell() 指针位置就是11,  最后f.read()的结果就是把指针后面的全部读取, 指针在11, 所以把第11个字节后面的全部读取  

#特别注意,因为seek()操作的是字节,字节既是二进制模式,除了默认的0模式可以不用b打开,其他两种模式都得用b打开


第三种,  2模式,  倒序  
 
f = open('seek.log','rb')
f.seek(-10,2)
print(f.tell())
print(f.read().decode())
f.close()  

# 执行结果:
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xa5 in position 0: invalid start byte     

#分析:  因为倒数第10个字节在 好  字上,一个汉字占3个字节,好 恰好占了倒数 9,倒数10, 倒数11这三个字节,  不能把汉字拆开,所以报错  

f = open('seek.log','rb')
f.seek(-11,2)
print(f.tell())
print(f.read().decode())
f.close() 

#执行结果: 
31
好人
666   

#分析:倒数第11个字节,  也就是从头开始的指针是31,  把倒数第11个字节后的或者说是正序第31个字节后的全部读取, 需要注意换行符是 \r\n 占了两个字节  
#特别注意,因为seek()操作的是字节,字节既是二进制模式,除了默认的0模式可以不用b打开,其他两种模式都得用b打开




 

 

文件截取  truncate()    



text = '''
我们是共产主义接班人
'''
with open('test.log','w') as f:
    f.write(text)

with open('test.log','r+') as f:
   f.truncate(6)  

#查看test.log,发现文件内容是  我们 
#分析,在utf-8的编码中一个汉字占3个字节,除了read()是字符,其他方法都是字节。   
# 注意:文件截取 truncate(6) 必须是可写的模式打开,但不能是w,因为w直接重新创建文件了,可以是 r+  或者 a+



 

再来看文件操作的最后一个例子:   



txt2='''请欣赏一首现代诗
黑夜给了我黑色的眼睛
我却用它寻找光明
'''

with open('new.txt','w') as f:
    f.write(txt2)


with open('new.txt','r') as f:
    first_line=f.readline() #读取第一行内容,指针会移动到第一行的后面,再读的时候就会去第一行后面开始读
    print('first_line:',first_line)
    print('分割线'.center(50,'-'))   #表示以'分割线'为中心,用-补齐50个长度
    data=f.read() #读取剩下的内容,
    print (data)  

# 执行结果:
first_line: 请欣赏一首现代诗

-----------------------分割线------------------------
黑夜给了我黑色的眼睛
我却用它寻找光明



 

##########################

其他常用文件操作:

 f.name   #打印文件名字  

f.flush()   #把文件内容从内存刷到硬盘   

f.closed   #文件如果关闭则返回True   

f.encoding   #查看使用open()打开文件的编码, 二进制模式的没有此方法

############################   

集合: 

集合是一个无序的,不重复的数据类型。



list1=[1,2,3,4,5,6,7,7,7,8,9]
list1=set(list1)   #集合会去重

print (list1,type(list1))



结果是:{1, 2, 3, 4, 5, 6, 7, 8, 9} <class 'set'>   

结果看上去像排序了的,其实是无序的,数据多了就会看出是无序的。有点像字典,但类型是集合。   

 

 

集合的方法:

1,增加

list1.add('a')  #增加一个元素,可以重复添加相同的值,但是没用,集合去重的

list1.update(['b','c','d'])  # 增加多个元素

 

2, 删除元素 

list1.remove('a')  #删除元素a,直接写要删除的元素名称就可以 ,但元素不存在时报错  

list1.discard('a')  #删除元素a,直接写要删除的元素名称就可以 ,元素不存在时不报错 

list1.pop()   #随机删除一个元素,因为集合是无序的

 

3,判断成员身份



list1=[1,2,3,4,5,6,7,7,7,8,9]
list1=set(list1)

print (2 in list1)   #正确就返回True
print (2 not in list1)   #正确就返回True



 

 

 

并集   



list1=[1,2,3,4,5,6,7,7,7,8,9]
list1=set(list1)

list2=[1,'a',5,'b',9]
list2=set(list2)

#方法一:
list3=list1|list2
print (list3)

#方法二:
list3=list1.union(list2)
print (list3)



返回结果: {1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b'}  把两个集合的所有元素合并,然后去掉重复的

 

 

交集    



list1=[1,2,3,4,5,6,7,7,7,8,9]
list1=set(list1)

list2=[1,'a',5,'b',9]
list2=set(list2)

#方法一:
list3=list1 & list2
print (list3)

#方法二:
list3=list1.intersection(list2)
print (list3)



返回结果:{1, 5, 9}  把两个集合的公共的部分取出来    

 

 

差集 



list1=[1,2,3,4,5,6,7,7,7,8,9]
list1=set(list1)

list2=[1,'a',5,'b',9]
list2=set(list2)

#方法一:
list3=list1 - list2
print (list3)

#方法二:
list3=list1.difference(list2)  #求list1对list2的差集,就是把list1有的,但list2没有的取出来
print (list3)



返回结果:{2, 3, 4, 6, 7, 8} 求list1对list2的差集,就是把list1有的,但list2没有的取出来    

 

 

子集与父集 



list1=[1,2,3,4,5,6,7,7,7,8,9]
list1=set(list1)

list2=[1,5,9]
list2=set(list2)

print (list2.issubset(list1))  #判断list2是否是list1的子集,也就是说list2的元素是否list1都有,如果是就返回True
print (list1.issuperset(list2))  #判断list1是否是list2的父集,也就是说list2的元素是否list1都有,如果是就返回True



 

 

###############################    

 

函数  

函数的作用:

1,减少代码重复性 

2,使程序变得可扩展

3,使程序变得易维护  

 

定义函数

1,



def func1():  #用def这个关键字去定义函数,func1 是函数名
    print ("hello,world")  #函数里面的内容

func1()  #用函数名加括号的方式去调用这个函数



 

2,



def func1():
    print ("this is func1")
    return 0   #返回一个0,注意return代表函数结束,即使后面还有命令也不会执行。

def func2():
    print ("this is func2")
    return 1,"哈哈",[1,2,3],{1:'a'} #看上去返回一堆东西,把return赋值给一个变量后,实际上打印出来的是一个元组,用元组包了起来

def func3(a,b): #这个函数有参数,叫做形参
    res=a**b    
    return res  #返回res的值



x=func1()   #执行func1函数并把return的返回值赋值给x,如果没有return,返回的是None
y=func2()   #执行func2函数并把return的返回值赋值给y,如果没有return,返回的是None
z=func3(2,3) #执行func3(a,b)函数,并把2传递给a,把3传递给b,执行完命令后把结果res赋值给z,刚才说的a和b叫形参,那么2和3叫实参,就是实际传递的参数

print (x)
print (y)
print (z)



 

3,默认参数   



def stu(name,age,country='china'):  #设置country这个参数的值是默认的,有默认参数必须放在最后
    print ("your name is %s" %name)
    print ("your age is %s" %age)
    print ("your country is %s" %country)


stu("zhang",18) 
#执行函数时如果不指定第三个参数,那第三个参数就用默认的,如果指定了,那就按照你指定的传参,实参也可以指定固定的,比如stu("zhang",agr=19) 同样,指定的实参也必须放在后面。
#正常情况,给函数传参要按照顺序来的,不按顺序会出错,比如stu("zhang",name="li") 这样会出错,因为zhang已经传递给形参name了,再给name传递一个肯定不行了。



 

4,非固定参数(如果不确定用户要传入多少参数,就用非固定参数)



def stu(name,age,*args):  # args 把用户传入的参数形成一个元组的形式
    print ("your name is %s" %name)
    print ("your age is %s" %age)
    print (args)


stu("zhang",18,'china','you are a good man')   

返回结果:
your name is zhang
your age is 18
('china', 'you are a good man')



如果传入的值是类似这种的sex="male",那 *args 就不能处理了,这就用到了 **kwargs   



def stu(name,age,**kwargs):  #kwargs 会把用户传递的参数形成字典形式
    print ("your name is %s" %name)
    print ("your age is %s" %age)
    print (kwargs)


stu("zhang",18,sex="male",country='china')   

返回的结果: 
your name is zhang
your age is 18
{'country': 'china', 'sex': 'male'}