首页 > 代码库 > python学习之路(六)

python学习之路(六)

 

今天来介绍一下文件的操作,包括文件的增删改查,以及字符编码与转码,还有一些简单的函数操作。

要对文件进行操作,首先要打开一个文件,而打开文件需要声明要对这个文件干什么,比如读(‘r‘),写(‘w‘),追加(‘a‘),读写(‘r+‘),写读(‘w+‘),还需要告诉系统,用什么字符集来打开,如utf-8或者Unicode等
首先介绍一下文件的读取。  f.read 这个是读取整个文件的内容。

首先有个叫yesterday的文本文件(就当他有,我这里没写这个文件)
f=open(yesterday‘,r‘,encoding=utf-8‘)
data1=f.read
data2=f.read
print(data1,“1”)
print(data2,“2”)
f.close

你会发现,输出的结果是data1输出的是文件的内容,data2输出的是空,而不是输出了两次整个文件,也不是读了两行。因为在这里,要介绍一个句柄的东西,大家可以理解成光标,f.read在读完文件的时候,句柄就停留在文件最后的位置,

在执行data2的时候,句柄在最后的位置,再往后面是没有内容的,所以输出的是一个空。而不是读第二遍文件。

这里还要注意一点的是,文件无论进行什么 操作,只要打开了文件,后面一定要关闭,f.close。

有时候我们可能不需要直接读取整个文件,这里介绍一下按行读取  f.readline

这里介绍几种方法
f=open(‘yesterday‘,‘r‘,encoding=‘utf-8‘)
我们可以从第一行读几行
for i in range (5):
  print(f.readline())
也可以读完整个文件
for line in f.readlines():
print(line.strip())

这里还有一种操作是按行输出,并写出这是第几行 用的是enumerate
for index,line in enumerate(f.readlines()):
  print(index,line)

不过,readline命令是全读到内存里,运行速度不如在内存中读一行,删一行的速度快
for line in f :
  print(line)

文件的读取介绍的差不多了,下面介绍文件的写入,‘w’模式是写入模式,他是创建(如果文件存在就覆盖)一个文件。

f=open(yesterday‘,w‘,encoding=utf-8‘)
f.write("abc")
f.weite("456")
f.close

代码执行之后会看到yesterday文件中有一行数据  abc456 ,他没有向我们程序中那样,写成两行,也是因为上文中提到的句柄,因为在写完abc之后,句柄就停留在了abc的后面,没有自动换行,所以在写入456的时候,他会紧接着abc写。

这里还有一点,就是在文件的写入过程中,不是write代码执行完成后,就立即写入硬盘文件中,而是在关闭这个文件的时候,数据才会一起写入磁盘中,之前都是保存在内存中的,所以这里也必须记得关闭文件。

如果想执行完write 就立即写入的话,可以再write语句后面使用 f.flush()  这个是直接写入到文件中,不需要关闭文件,括号中如果填数字,代表写这么多字符后自动写入文件。

还有几种文件的打开模式

A.  “a” 在这个模式下,写入的数据都会追加在原文件的末尾,而不会覆盖原文件。

B.  “r+”这个是读写模式,所谓读写模式是先读再写的模式。当你读取了三行后再写入,新写入的文件会出现在第三行的末尾而不是第四行。因为读取结束时,文件的句柄停留在了第三行的结尾,而且这个句柄不会自动移动到第四行,所以新写的数据会出现在第三行结束。读写模式,可读可写可追加,平时用处比较多。

C.  “w+”这个是写读模式,在这个模式下,系统会自动去寻找有没有这个文件,如果没有的话直接新建一个文件,如果有的话,覆盖这个文件。在读写模式下,先读取文件是没有用的,因为文件被覆盖,读不到任何数据。在写入的时候,虽然可以移动句柄,但是无法在移动后的句柄处写入,还是会写入在文件的末尾处。

D. "a+"是追加读写 

E.  "rb"让文件以二进制方式读取出来。

F.  “wb”以二进制方式写入。这时候就不能输入英文,汉字等了,写入的时候会报错,因为输入的不是二进制。

这里在介绍一下文件的修改。文件的修改有两种方式。

1.把文件全读取到内存中,修改完成后再全部写入。这种方法不推荐用,因为当文件过大时,内存可能无法处理这个文件,而且就算是一般的文件,处理速度也会比较慢,因为占用内存比较大。

2.打开原文件的同时打开另一个文件,将修改完成的文件写入另一个新的文件,这样可以一部分一部分的去执行,提高运行速度,节省内存,是主流的修改文件的方法。

修改的语句可以用replace

for line in f :
    if "abc" in line :
        line = line.repiace("abc","def")
这就实现了一个,将文件中的abc替换成def的功能。

打开文件还有另一种操作,就是用with,用with的好处就是不用去关闭文件,他会自动帮你处理好

with open ("yesterday","r",encoding="utf-8") as f :
    print (f.readline())

打开多个文件的方法是
with open ("yesterday1","r",encoding="utf-8") as f ,    with open ("yesterday2","r",encoding="utf-8") as ff :
下一个文件要记缩进。

 

下面介绍字符编码和转码 
python3中默认的编码是Unicode。在py3中encode,在转码的同时还会把string 变成bytes类型,decode在解码的同时还会把bytes变回string。

不管是encode还是decode。只要记住在不同的字符集转换的时候,都要经过Unicode再转到别的字符集!!!

utf-8是Unicode的扩展集,所以Unicode可以在utf-8下直接打印出来。

 

最后介绍一部分函数。

所以,先定义一个函数

def test (x) :
   x+=1
   return 0

这样,我们就定义了一个名为test的函数,他的形参是x,他的函数体是x+=1, 返回值是一个0。如果未在函数中指定return,那这个函数的返回值为None
函数和过程最大的区别是函数必须有返回值,而过程是没有返回值的。

return 后面可以跟任何东西,他代表函数执行完成的一个标志,返回这个值就相当于说函数已经执行完成,而在函数中,return后面的语句也不会被执行,因为return是这个函数的结尾。

假设一个 a= test(1) 打印他会得到0.这就是上个函数执行完成的标志 。也可以return x 。这个会打印出一个2.因为函数中有x+=1.执行完成后x就变成了2.

形参和实参:

形参:变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量

实参:可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值

就像刚才上边的例子 x 就是一个形参。而a=test(1)中的1就是实参。

一个函数可以有多个形参和实参,比如下面代码

def test(x,y):
    print (x)
    print (y)
    return 0

test(1,2)
test(x=1,y=2)
test(1,y=2)
以上三种调用函数的传参方法都对,前两种不必多说,第三种方法,在函数中,他会主动识别位置参数,然后在去看赋值。但是不能将赋值卸载位置参数前面,会报错

函数还能赋默认参数

def test(x,y=1)
    print(x)
    print(y)
    return 0

test(1)
test(1,3)
test(1,y=3)
test(x=1)
test(x=1,y=3)
以上方法都正确,默认参数是可以赋也可以不赋值的。这种多用于有默认选项的情况,如默认国籍,或者默认数据库服务器端口等

函数也可以通过元祖,字典等方式传值

def test (*args)
     print(args)
     return 0

test(1,2,3,4)
test(*[1,2,3,4])
这两种也都可以的

这种传值方法多用于与传单一参数一起传递值得情况,比如一开始我定义了一个函数,只有一个形参x ,但是后来发现形参不够,还想加,就可以用下面的方法,省的日后再去改代码
def test (x,*args)
    print (x)
     print (args)
     return 0

这时候可以用test(1,2,3,4)传值
输出的结果为 
12,3,4)

通过字典传值

def stu_register(name,age,*args,**kwargs): # *kwargs 会把多传入的参数变成一个dict形式 
    print(name,age,args,kwargs) 
  return 0 stu_register(
"Alex",22) #输出 #Alex 22 () {}#后面这个{}就是kwargs,只是因为没传值,所以为空 stu_register("Jack",32,"CN","Python",sex="Male",province="ShanDong") #输出 # Jack 32 (‘CN‘, ‘Python‘) {‘province‘: ‘ShanDong‘, ‘sex‘: ‘Male‘}

既然降到了函数,那么必然少不了局部变量和全局变量

在子程序中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。
全局变量作用域是整个程序,局部变量作用域是定义该变量的子程序。
当全局变量与局部变量同名时:
在定义局部变量的子程序内,局部变量起作用;在其它地方全局变量起作用
 
x=1
def aaa(x,y)
    print(x)
    x=3
    print(x)
    c=x+y    
    return 0
aaa(x,1)
print(x)
这个函数执行完之后是
1
3
1
在程序最顶端的是全局变量
而在函数里面的x是局部变量
虽然在函数里面可以通过语句global改变全局变量,但是不建议使用。
而且,只有str ,int 不能再函数中改变局部变量。
但是,列表,元祖,字典,集合,类,都可以在局部变量中改变全局变量。
 
递归函数

在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。

def calc(n): 
    print(n) 
    if int(n/2) ==0: 
        return n 
    return calc(int(n/2)) 
  
calc(10) 
  
输出: 
10
5
2
1 

递归特性:

1. 必须有一个明确的结束条件

2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少

3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)

 

高阶函数

变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。

注:abs是取绝对值

def add(x,y,f): 
    return f(x) + f(y) 
  
  
res = add(3,-6,abs) 
print(res) 

 

 

python学习之路(六)