Python自动化运维 - day3 - 文件处理 - 函数part1




文件处理



 



1、读取文件



f = file('/etc/passwd','r') ----> Python 3.x 里面没有file,统一用open
for line in f.readlines():
    line = line.strip('\n').split(':')
    print line



结果:



['root', 'x', '0', '0', 'root', '/root', '/bin/bash']
['bin', 'x', '1', '1', 'bin', '/bin', '/sbin/nologin']



 



以指定编码格式打开文件:



f = open('/etc/password',encoding = 'UTF-8')



我们把这个 f 成为文件句柄(用来标识一个文件的内存对象),包含文件名,字符集,大小,硬盘上的起始位置等等。



f在这里就变成了一个文件迭代器,我们可以通过使用for line in f ,去循环的读取文件的每一行内容



2、文件方法



  r:只读打开



  w:只写模式打开(不能读)  如果选择这个模式打开,那么在执行write的时候,会覆盖源文件(非追加)



  a:只追加模式打开(不能读)



  r+: 读写模式(写是追加) --->常用



  a+: 追加读写



  w+:写读模式(写同样是追加) ---->不常用



  rb:二进制读模式(一般用来做网络传输数据的时候,因为网络传输都是基于二进制格式的,所以必须用b) python 2.x 是可以用str传输的



  r+b:以二进制读写模式打开



  w+b:以二进制写读模式打开



  a+b:以二进制追加及读模式打开



  b:使用二进制模式(适合在windows上使用,例如windows上的回车符和Linux不同)



 



注:



  U:表示在读取的时候,可以将‘\r\n’ 转换成 \n (与r或r+模式连用)这样的好处是方便windows上到Linux的使用



  因为回车符在windows上表示为\r\n 而Linux上 表示为\n



 



二进制只是一个文件的编码格式,并不带表文件的内容都是01010。所以我们一个str类型的文件也是可以当成二进制文件来处理的,只不过我们把str写入文件的时候需要转换成二进制格式,才能写入:



f = open('test.txt','rb')
f.write('你好'.encoding())



通过encoding就可以转换成二进制



 



3、文件对象方法



  fd.closed():判断文件是否被关闭,若被打开提示False,没有的话提示True



  fd.flush():把修改的内容,强制刷新到文件中去



  fd.isatty:判断是否是一个终端文件



  fd.mode:查看文件的打开模式



  fd.name:查看文件的名称



  fd.next:迭代的方法,和readline很像,区别是,next读到末尾会报错,readline会继续返回空



  fd.read:一次性读取所有内容,以字符串的方式存取



  fd.readable():判断文件是否可读



  fd.readlines:一次性读取所有内容,以列表的方式存取(适合操作小文件)



  fd.readline():每次读取一行内容



  fd.seek(0):调整文件读取的指针位置



  fd.seekable():判断文件是否可以调整指针位置(tty,磁盘等文件是不能被seek的),可以被seek则返回真,否则返回假 --Python3.x



  fd.tell():查询文件目前读取位置(以字符为单位)



  fd.truncate():截取文件,从开头开始截取,不指定指针位置的话,那么会清空文件



  fd.write:把一个字符串写入到文件中去



  fd.writelines():把字符串列表写入文件中



  fd.xreadlines():读一行打印一行,针对大文件非常适用 -----> Python 2.x 中适用,3.x中已经取消



  fd.encoding:查看文件的编码



  fd.writeable():判断文件是否可以写



   fd.fileno(): 返回文件在操作系统上的文件描述符(默认会打开三个:0表示 stdin、1表示 stdout,2表示stderr)



  fd.name:打印文件名称



函数 



面向过程和函数式编程的最主要的区别是,过程是没有返回值的函数,Python中给过程隐士的定义了返回值为none,所以过程和函数式在Python中没什么区别



 



函数的定义:



def fun(arg,*args,**kargs)
    pass



参数:



  arg,函数可以有参数也可以没有



 



传递参数:



  1、关键字调用(无序的)



  2、位置参数调用(有序的)



  3、二者混用,关键字调用必须放在参数列表的末尾(关键字参数不能放在位置参数前)



 



默认参数:



  def func(arg = 'value'),表示如果arg没有传值,那么它默认等于values,如果对某个参数设定了默须放在参数列表中的最后。



  特点:调用参数的时候非默认传递,可以根据默认值来预先编写函数逻辑



  注意:默认参数最好指向不变的对象



  对默认参数进行赋值的时候,可以用位置参数进行赋值,也可以用关键则参数进行赋值



 



可变参数(参数组):



  *args:表示参数可能是多个的,函数内部使用元祖tuple来存储这些参数



 



关键字参数:



  **kargs:也表示参数是多个的,只是函数内部使用dict来存储这些参数,适用于var = value(关键字)的方式传值!



 



主要区别:



  1、*args接受的是N个位置参数,用元祖存储



  2、**kwargs接受的是N个关键字参数,用字典存储



  注意:



    1、当函数接受可变参数的时候,如果我们刚好有一个list 或者tuple,可以直接在前面加上*,把元素变成可变参数进行传递



a = [1,2,3]
test(*a)



    2、如果已有字典要传递给函数的话,可以在传递的时候加上**,把字典的key,value变成关键字参数进行传递



    3、三个参数的位置不能调换,若同时存在arg,*argv,**kargv,必须先给arg赋值(除非它有默认值),然后才能给*argv和**kargv赋值。



 



命名关键字参数:



  我们可以指定命名关键字参数进行传递,如果传如的关键字参数没有包含命名关键字参数,那么将会报错。



  如果函数有可变参数,那么可以在后面直接定义命名关键字参数,如果函数只有位置参数,那么命名关键字参数之前就需要添加*,来隔开,表示后面的为命名关键字参数



def func(name,age,*,city,job):
print(name,age,city,job)
>>> func('daxin',22,city='beijing',job='linux')
daxin 22 beijing linux



  这里可以指定命名关键字的默认值



 



注意:



  参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数



 



返回值:



  return var,在函数的内部把某个结果进行返回,return之后直接跳出函数。



  返回值数量=0,返回None。



  返回值数量=1,返回object。



  返回值数量>1,返回tuple。



 



例子:



def test(arg,*argv,**kargv):
    print arg
    print argv
    print kargv
 
test('1','2','3',a='4',b='5')



结果:



1
('2', '3')
{'a': '4', 'b': '5'}



直接传递字典进去是不行的,也是需要在字典变量前加**,列表相同



 



局部变量:



  在函数内定义的变量,只在函数里生效,那么该函数就是该变量的作用域



 



全局变量:



  在程序中定义的变量,在程序内全局生效。



 



  函数内是无法修改全局变量的值的,如果非要修改,那么就需要在函数内声明变量为全局变量的值



  global varname --->一般是不用的



 



 



注意:



  函数内是无法修改字符串、数值类型的变量的。但是可以修改字典,列表,集合,类的变量的值!



 



三元运算符和lambda表达式



正常情况下:



if 1 > 3:
    print 'lt'
else:
    print 'gt'



运用三元运算符:(三目运算符)



print 'lt' if 1>3 else 'gt'



lambda表达式:



  又叫匿名函数



tem = lambda x,y:x+y
print tem(2,3)
等于:
def tem(x,y):
return x+y
print tem(2,3)



一般用在函数逻辑比较简单,在程序内基本不会重复调用的函数,节省代码量



 



递归:



  在函数内部,可以调用其他函数.如果一个桉树在内部调用自己本身,那么这个函数就是递归函数.



 



递推特性:



  1、递归必须要有一个明确的条件



  2、每次进入更深一层的调用时,问题规模相比上一次递归应该有所减少



    比如:数字是依次递减,列表的元素依次减少等等。



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



 



例子:



def calc_division(n):
    'this func user for n devision 2'
    print(n)
    if int(n/2) > 0:
        return calc_division(int(n/2))
    print('-->',n)
 
calc_division(20)



Python中的排序分为原地排序和复制排序。



  - 原地排序(in place sort) 指按照指定的方式排列数据,然后用排序后的数据替换原有数据



  - 复制排序(copied sort)指按你指定的方式排列数据,然后返回一个源数据的有序副本,源数据的顺序依然保留



  - 原地排序使用对象的sort()方法



  - 复制排序使用内置BIF sorted()



  - 默认都是正序,倒序的话可以添加reverse=True



 



原地排序:



>>> a =[2,3,6,9,43,6,98,4,8]
>>> a.sort()
>>> a
[2, 3, 4, 6, 6, 8, 9, 43, 98]
>>> a.sort(reverse=True)
>>> a
[98, 43, 9, 8, 6, 6, 4, 3, 2]
>>> sorted(a,reverse=True)
[98, 43, 9, 8, 6, 6, 4, 3, 2]



 



复制排序:



>>> b = [7,45,8,3,5,7,9,0,5,7]
>>> sorted(b)
[0, 3, 5, 5, 7, 7, 7, 8, 9, 45]
>>> b
[7, 45, 8, 3, 5, 7, 9, 0, 5, 7]



 



去重:



对一个列表进行去重其实有很多方法:
>>> d = ['a','b','a','c']
>>> e=[]
>>> for i in d:
if i not in e:
e.append(i)
>>> e
['a', 'b', 'c']
这里可以利用一种特殊的数据类型集合。集合是无序的并且元素是唯一的
>>> d
['a', 'b', 'a', 'c']
>>> set(d)
{'b', 'a', 'c'}



字符编码

计算机里面,编码方法有很多种,英文的一般用ascii,而中文有unicode,utf-8,gbk等等。


unicode是 utf-8,gbk等这些的父编码,这些子编码都能转换成unicode编码,然后转化成子编码,例如utf8可以转成unicode,再转gbk,但不能直接从utf8转gbk,需要有一个中间过程

所以,python中就有两个方法用来解码(decode)与编码(encode),解码是子编码转unicode,编码就是unicode转子编码

1.编码



a = '你好'

print(a.encode('gbk'))
print(a.encode('utf-8'))



这里使用Python 3, 所以a的默认编码类型为unicode

输出的结果为:



b'\xc4\xe3\xba\xc3'
b'\xe4\xbd\xa0\xe5\xa5\xbd'



2.解码



a = '你好'

print(a.encode('gbk').decode('gbk'))
print(a.encode('utf-8'))



这里a为unicode编码,decode方法将gbk的bytes格式的数据转换为unicode编码
输出结果:



你好
b'\xe4\xbd\xa0\xe5\xa5\xbd'



因为a是unicode编码的,如果对a进行解码,那就会报错,没有decode方法



AttributeError: 'str' object has no attribute 'decode'



3、文件加载过程

  1、程序向系统发送调用命令

  2、系统切换到内核态从磁盘(bytes格式)加载到内存中(unicode格式),这里就有一个编码(decode)的过程,既 bytes(utf-8) -> unicode 

  3、python解释器读取内存中的unicode编码的文件,如果python解释器指定了编码集为UTF-8,那么就会产生一个解码(encode)的过程,既unicode  -> utf-8

  4、python 3中的字符串存储格式是unicode,python 2 中的 bytes格式

  5、python3 默认支持中文,python不支持