第3章 文件处理和函数

1. 文件处理流程

     1). 打开文件,等到文件句柄并赋值给一个变量

     2). 通过句柄对文件进行操作

     3). 关闭文件

2. 文件基本操作

    2.1 文件操作基本流程

 1 f=open('user','r')
 2 line_data=f.readline()          #读取一行
 3 print(line_data)                #打印一行
 4 print('分割线'.center(30,'='))
 5 data=f.read()                   #读取剩余
 6 print(data)                     #打印读取内容
 7 f.close()                       #关闭文件
 8 
 9 with open('test','r',encoding='utf-8') as f1:    #这样打开文件,不需要直接关闭文件,执行完程序,会自动关闭文件
10     l=f1.readlines()           #会把文件内容全部读出变为列表形式,可以加参数,指定读取文件的大小
11     print(l)
12     for line in l:
13         print(line)
View Code

    2.2 字符编码

         文件保存编码如下:

    

         此刻错误的打开方式:

f=open('test','r',encoding='utf-8')
f.read()

    

         正确的打开方式:

#不指定打开编码,用操作系统默认编码,windows 系统默认编码是gbk,linux系统一般是utf8编码
f=open('test','r',encoding='gbk')  #打开文件test,字符编码是gbk,这里是windows平台,不指定编码也可以
data=f.read()
f.close()
print(data)

    2.3. 文件打开方式

   文件句柄 = open('文件','打开模式') 

   打开文件时,需要指定文件路径和以何等方式打开文件,打开文件以后,即可获取该文件句柄,日后通过此文件文件句柄对该文件操作

   打开文件的模式有:

  •    r,只读模式(默认模式,文件必须存在,不存在会报错)
  •   w,只写模式(不可读,文件不存在则创建,会清空文件)
  •   a,追加模式(可读,不存在则创建,存在则只追加)

   “+”表示可以同时读写某个文件

  •    r+,读写(可读,可写)
  •    w+,写读(可写,可读)
  •    a+,写读(可写,可读)

    “b”表示以字节的方式操作

  •    rb  或  r+b
  •    wb 或  w+b
  •    ab  或  a+b

       注:以b的方式打开时,读取到的内容是字节类型,写入是也要指定为字节类型,不能指定字符编码。

      练习 利用b模式,编写一个cp工具,要求如下:

          1.即可以拷贝文本,也可以拷贝视频,图片等文件

          2. 用户一旦参数错误,打印命令的正确使用方法,如:usage :cp  source_file target_file

          提示:可以使用 import sys

1 import sys                       #导入模块
2 sys.argv
3 if len(sys.argv) < 3:
4     print('usage :cp  source_file target_file')
5     sys.exit()
6 with open(r'%s'%sys.argv[1],'rb') as read_f,open(r'%s'%sys.argv[2],'wb') as write_f:
7      for line in read_f:
8          write_f.write(line)
View Code

    2.4 文件内光标移动

         1)read(3)

                a.文件打开方式为文本模式时,代表读取3个字符

                b.文件打开方式为b模式时,代表读取3个字节

          2)其余的文件内的光标移动都是以字节为单位如seek,tell,truncate

          注意:

                   a. seek有3种光标移动方式0,1,2,其中1,2必须在b模式下,但无论那种模式,都是以bytes为单位移动的

                   b.truncate是截断文件,所以文件的打开方式必须可写,但是不能用w或w+的方式打开文件,因为那样直接清空文件了,所以truncate要在r+或a或a+模式下测试效果 

 1 with open('user','r') as f:
 2     print(f.read(3))      #读取3个字符
 3     print(f.tell())          #光标在第3个字符后
 4 
 5 with open('user','rb') as f:
 6     print(f.read(3))
 7     f.seek(0)                 #光标移到开头
 8     print(f.tell())
 9 
10     f.seek(0,1)               #光标从当前位置开始
11     print(f.read())
12 
13     f.seek(1,1)              #光标从当前位置的第2个开始
14     print(f.tell())
15 
16     f.seek(0,2)              #光标移动到结尾
17     print(f.tell())
18  
19     f.seek(-1,2)             #光标移动到倒数第一个字节前
20     print(f.read().decode('utf-8'))
21     print(f.tell())
22 
23 with open('test','r+',encoding='utf-8') as f:
24     f.truncate(64)        #把文章截断,只要64个字节,其他的删除
25     data=f.read()
26     print(data)
View Code

      2.5 文件的修改

1 import os
2 with open('test','r',encoding='utf-8') as read_f,
3       open('test.swap','w',encoding='utf-8') as write_f:
4      for line in read_f:
5          if  line.endswith('hello world'):
6              line='哈哈哈
'
7          write_f.write(line)
8 os.remove('test')
9 os.rename('test.swap','test')
View Code

 3. 函数

      3.1 为什么有用函数

  •   不同函数感觉代码的组织结构不清晰
  •   代码冗余
  •   无法统一管理维护难度大

      3.2  函数的分类

  •    内置函数
  •    自定义函数

      3.3  为何要定义函数

  •  函数即变量,变量必须先定义后使用,未定义而直接引用函数,就相当于一个在引用一个不存在的变量名代码演示

      3.4  函数的使用

  •      先定义
  •      再调用

      3.5 函数定义阶段

           只检测语法,不执行代码

1 def foo():
2     print('from foo')
3     bar()
4 
5 def bar():
6     print('from bar')
7 
8 foo()
View Code

      3.6 定义函数(函数名要能反映其意义)及语法

           函数的语法:

           def  函数名(arg1,arg2,arg3):

                  #注释

                  函数体

                  return    返回值

           函数名一般是动词,arg1 是参数,一个函数内部可以有多个return,但是只执行一次,函数就结束调用,并且会把return后面的值作为函数的执行结果返回

       3.7  函数的定义的3种形式

  •      无参函数,应用场景仅仅只是执行一些操作,比如,用户交互,打印
  •      有参函数,需要根据外部传进来的参数,才能执行相应的逻辑,比如统计长度,求最大值最小值。
  •      空函数,设计代码结构
 1 def foo():
 2     print('from foo')
 3 foo()
 4 
 5 def my_max(x,y):
 6     if x > y :
 7        return x
 8     else:
 9        return y
10 res=my_max(2,3)
11 print(res)
12 
13 def select():
14     #select function
15     pass
16 
17 def insert():
18     #insert function
19     pass 
View Code

      3.8 函数的调用

            1)先找到函数名

            2)再根据名字调用代码

            3 )函数的返回值

1 大前提:return的返回值没有类型限制
2     1. 没有return:返回None,等同于return None
3     2. return 一个值:返回该值
4     3. return val1,val2,val3:返回(val1,val2,val3)
 1 def func():
 2     print('from func')
 3     # return [1,2,3],'a',1,{'a':3}
 4 res=func()
 5 print(res)
 6 
 7 def func():
 8     print('from func')
 9     return [1,2,3],'a',1,{'a':3}
10 res=func()
11 print(res)
View Code

               返回值什么时候该有?

                       通常调用函数,经过一系列的操作,最后要拿到一个明确的结果,则必须要有返回值

                       通常有参函数需要返回值,输入参数,经过计算,得到一个最终计算

               返回值什么时候不需要有?

                       通常调用函数,仅仅执行一系列操作,最后不需要一个明确的结果,则无需返回值

                       通常无参函数不需要有

 4 .函数调用的3种形式

  •        语句形式:foo()
  •        表达式形式:res=my_max(2,3)*10
  •        当中另一个函数的参数:range(len('hello world'))
 1 def my_max(x,y):
 2     if x > y:
 3         return x
 4     else:
 5         return y
 6 
 7 my_max(1,2) #语句形式
 8 res=my_max(1,2)*10 #表达式形式
 9 res2=my_max(my_max(1,2),3) #函数调用可以当做另外一个函数的参数
10 print(res2)

 5. 函数的参数

    1)形参和实参的定义:

1 def my_max(x,y):     #x,y是形参
2     if x > y :
3        return x
4     else:
5        return y
6 res=my_max(2,3)     #2,3是实参
7 print(res)

     2) 形参即变量名,实参即变量值,函数调用则值绑定到名字上,函数执行完毕,解除绑定

     3) 具体应用

            位置参数:按照从左到右的顺序定义参数

                   位置形参:必选参数

                   位置实参:按照位置为形参传值

            关键字参数:按照key=value的形式定义参数

                   无需按照位置为形参传值

                   注意的问题:

                          a. 关键字实参必须在位置实参的右边

                          b. 对同一形参不能重复传值

            默认参数:形参在定义时就已经为其赋值

                    可以传值也可以不传值,经常需要变动参数的定义为位置形参,变动较小的参数定义为默认参数(形参)

                    注意的问题:

                           a.只在定义时赋值一次

                           b.默认参数的定义在位置形参的右边

                           c.默认参数通常定义为不可变类型

            可变长参数:

                   针对实参在定义时长度不固定的情况,应该从形参的角度找到可以接收可变长实参的方案,这就是可变长参数(实参)

                   而实参有按位置和关键字两种定义方式,针对这两种形式的可变长,形参也应该有两种解决方案,分别是*args,**kwargs

 1 #=========*args=========
 2 def foo(x,y,*args):
 3     print(x,y)
 4     print(args)
 5 foo(1,2,3,4,5,6)
 6 
 7 def foo(x,y,*args):
 8     print(x,y)
 9     print(args)
10 foo(1,2,*[3,4,5,6])
11 
12 def foo(x,y,z):
13     print(x,y)
14     print(z)
15 foo(*[1,2,3])
16 
17 #========**kwargs======
18 def foo(x,y,**kwargs):
19     print(x,y)
20     print(kwargs)
21 foo(1,2,z=3,a=4,b=5,d=6)
22 
23 def foo(x,y,**kwargs):
24     print(x,y)
25     print(kwargs)
26 foo(1,y=2,**{'z': 3, 'a': 4, 'b': 5, 'd': 6})
27 
28 def foo(x,y,z):
29     print(x,y,z)
30 foo(**{'x':1,'y':2,'z':3})
31 
32 #====*args,**kwargs=====
33 def foo(x,y,z):
34     print(x,y,z)
35 
36 def wrapper(*args,**kwargs):
37     print('========>')
38     foo(*args,**kwargs)
39 wrapper(1,2,3)
40 ###这个可以测试函数的运行时间
41 import time
42 def register(name,age,sex='male'):
43     start_time=time.time()
44     print(name)
45     print(age)
46     print(sex)
47     time.sleep(3)
48     stop_time=time.time()
49     print('run time is %s' %(stop_time-start_time))
50 
51 def wrapper(*args, **kwargs): #args=('egon',) kwargs={'age':18}
52     start_time=time.time()
53     register(*args, **kwargs)
54     stop_time=time.time()
55     print('run time is %s' %(stop_time-start_time))
56 
57 wrapper('egon',age=18)

             命名关键字参数:*后定义的参数,必须被传值(有默认值除外),且必须按照关键字实参的形式传递可以保证,传入的参数一定包含某些关键字

 1 def foo(x,y,*args,a=1,b,**kwargs):
 2     print(x,y)
 3     print(args)
 4     print(a)
 5     print(b)
 6     print(kwargs)
 7 
 8 foo(1,2,3,4,5,6,a=1,b=2,c=3,d=5,e=6)
 9 #结果:
10 1 2
11 (3, 4, 5, 6)
12 1
13 2
14 {'c': 3, 'd': 5, 'e': 6}

 6.练习

1 1、写函数,,用户传入修改的文件名,与要修改的内容,执行函数,完成批了修改操作
2 2、写函数,计算传入字符串中【数字】、【字母】、【空格] 以及 【其他】的个数
3 3、写函数,判断用户传入的对象(字符串、列表、元组)长度是否大于5。
4 4、写函数,检查传入列表的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。
5 5、写函数,检查获取传入列表或元组对象的所有奇数位索引对应的元素,并将其作为新列表返回给调用者。
6 6、写函数,检查字典的每一个value的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。
7 dic = {"k1": "v1v1", "k2": [11,22,33,44]}
8 PS:字典中的value只能是字符串或列表
 1 # 1、写函数,,用户传入修改的文件名,与要修改的内容,执行函数,完成批了修改操作
 2 def rename_f(filename,old,new):
 3     import os
 4     with open(filename,'r',encoding='utf-8') as read_f,
 5         open('.bak.swap','w',encoding='utf-8') as write_f:
 6         for line in read_f:
 7             if old in line:
 8                 line=line.replace(old,new)
 9         write_f.write(line)
10     os.remove(filename)
11     os.rename('.bak.swap',filename)
12 rename_f('user.txt','test1','stu')
13 # 2、写函数,计算传入字符串中【数字】、【字母】、【空格] 以及 【其他】的个数
14 def check_str(msg):
15     res={
16         'num':0,
17         'string':0,
18         'space':0,
19         'other':0
20     }
21     for s in msg:
22         if s.isdigit():
23             res['num']+=1
24         elif s.isalpha():
25             res['string']+=1
26         elif s.isspace():
27             res['space']+=1
28         else:
29             res['other']+=1
30     return res
31 res=check_str('hello name:aSB passowrd:alex3714')
32 print(res)
33 # 3、写函数,判断用户传入的对象(字符串、列表、元组)长度是否大于5。
34 def func1(seq):
35     if len(seq) > 5:
36         return True
37     else:
38         return False
39 print(func1([1,2,3,4,5,6]))
40 
41 # 4、写函数,检查传入列表的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。
42 def func1(seq):
43     if len(seq) > 2:
44         seq=seq[0:2]
45         return seq
46 print(func1([1,2,3,4]))
47 # 5、写函数,检查获取传入列表或元组对象的所有奇数位索引对应的元素,并将其作为新列表返回给调用者。
48 def func2(seq):
49     return seq[::2]
50 print(func2([1,2,3,4,5,6,7]))
51 
52 # 6、写函数,检查字典的每一个value的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。
53 # dic = {"k1": "v1v1", "k2": [11,22,33,44]}
54 # PS:字典中的value只能是字符串或列表
55 def check_dic(dic):
56     d={}
57     for k,v in dic.items():
58         if len(v) >2:
59             d[k]=v[0:2]
60     return d
61 print(check_dic({"k1": "v1v1", "k2": [11,22,33,44]}))
View Code

 7.函数对象

    函数对象:函数是第一类对象,即函数可以当作数据传递

     1)可以被引用

     2)可以当作参数传递

     3)返回值可以是函数

     4)可以当作容器类型的元素

 1 # 利用该特性,优雅的取代多分支的if
 2 def foo():
 3     print('foo')
 4 
 5 def bar():
 6     print('bar')
 7 
 8 dic = {
 9     'foo': foo,
10     'bar': bar,
11 }
12 while True:
13     choice = input('>>: ').strip()
14     if choice in dic:
15         dic[choice]()

 作业:

      有以下员工信息表

      

       此表在文件存储是可以这样表示:

        1,Alex Li,22,13651054608,IT,2013-04-01

现需要对这个员工信息文件,实现增删改查操作

   1. 可进行模糊查询,语法至少支持下面3种:
           1. select name,age from staff_table where age > 22
           2. select  * from staff_table where dept = "IT"
           3. select  * from staff_table where enroll_date like "2013"
           4. 查到的信息,打印后,最后面还要显示查到的条数 
   2. 可创建新员工纪录,以phone做唯一键,staff_id需自增
   3. 可删除指定员工信息纪录,输入员工id,即可删除
   4. 可修改员工信息,语法如下:
          UPDATE staff_table SET dept="Market" WHERE where dept = "IT"

 注意:以上需求,要充分使用函数,请尽你的最大限度来减少重复代码!

             

       

         

            

     

                

     

原文地址:https://www.cnblogs.com/fanglingen/p/7195454.html