python基础之文件操作,集合,函数

文件操作:   

打开文件的方法:

 

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

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'}

 

 

 

 


posted @ 2016-08-12 09:14  疯狂的大叔  阅读(1044)  评论(0编辑  收藏  举报