文件对象
处理文件的三个步骤:打开、读写、关闭。
文件读取
open内建函数
- 作为打开文件之门的“钥匙”,内建函数open() 提供了初始化输入/输出(I/O)操作的通用接口
- 成功打开文件后时候会返回一个文件对象,否则引发一个错误
- 基本语法:
file_object = open(file_name, mode='r', buffering=-1)
文件对象访问模式
文件模式 | 操作 |
---|---|
r | 以读方式打开(文件不存在则报错) |
w | 以写方式打开(文件存在则清空,不存在则创建) |
a | 以追加模式打开(必要时创建新文件) |
r+ | 以读写模式打开(参见r) |
w+ | 以读写模式打开(参见w) |
a+ | 以读写模式打开(参见a) |
b | 以二进制模式打开 |
- 文件读取
[root@room8pc16 ]# cp /etc/passwd /tmp/mima
>>> f = open('/tmp/mima') # 默认以r方式打开
>>> data = f.read() # 默认read读取全部数据
>>> print(data)
>>> data = f.read() # 因为文件指针已经到文件结尾,再读数据将是空
>>> print(data)
>>> data
''
>>> f.close()
- 重新打开文件
>>> f = open('/tmp/mima')
>>> f.read(4) # 读取4字节
'root'
>>> f.read(4)
':x:0'
>>> f.readline() # 读取到遇到的第一个\n
>>> f.readlines() # 把文件的第一行作为列表项,保存到列表中
>>> f.close()
最常用的、读取文本文件的方式是for循环遍历:
>>> f = open('/tmp/mima')
>>> for line in f:
... print(line, end='')
>>> f.close()
写入文件
write方法
- write()内建方法功能与read()和readline()相反。它把含有文本数据或二进制数据块的字符串写入到文件中去
- 写入文件时,不会自动添加行结束标志,需要程序员手工输入
>>> fobj.write('Hello World!\n')
13
writelines方法
- 和readlines()一样,writelines()方法是针对列表的操
- 它接受一个字符串列表作为参数,将它们写入文件
- 行结束符并不会被自动加入,所以如果需要的话,必
须在调用writelines()前给每行结尾加上行结束符
>>> fobj.writelines(['Hello World!\n', 'python programing\n'])
- 写文件
>>> f = open('/tmp/mima', 'w') # 文件不存在则创建,存在会清空
>>> f.write('hello world!\n')
13 # 返回写入到文件的字节数
>>> f.writelines(['2nd line.\n', '3rd line.\n'])
[root@room9pc01 ~]# cat /tmp/mima # 此时文件仍然为空的
>>> f.flush() # 立即将数据从缓存同步到磁盘
[root@room9pc01 ~]# cat /tmp/mima
hello world!
2nd line.
3rd line.
>>> f.write('end\n')
4
>>> f.flush()
>>> f.write('kjlkjl\n')
7
>>> f.close() # 关闭文件时,数据也会写入磁盘
- 处理非文本文件,与文本文件大体相似,只不过在打开文件时,需要加上b
>>> f = open('/tmp/ls')
>>> f.read(10) # 报错.因为打开时默认以UTF-8编码打开,但是ls不是文本文件,读取时,Python试图把读出来的10个字节显示为UTF-8字符
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.6/codecs.py", line 321, in decode
(result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc4 in position 24: invalid continuation byte
>>> f.close()
>>> f = open('/tmp/ls', 'rb') # 以bytes类型打开
>>> f.read(10)
b'\x7fELF\x02\x01\x01\x00\x00\x00'
# 文本文件也能以bytes方式打开
>>> f = open('/tmp/mima', 'rb')
>>> f.read()
b'hello world!\n2nd line.\n3rd line.\nend\nkjlkjl\n'
>>> f.close()
with子句
- with语句是用来简化代码的
- 在将打开文件的操作放在with语句中,代码块结束后,文件将自动关闭
>>> with open('foo.py') as f:
... data = f.readlines()
...
>>> f.closed
True
- 文件打开后,如果不关闭,也可能没有问题,当程序结束时.文件自动关闭,但是关闭文件是很好的习惯。
- 如果使用with语句打开文件,当with语句结束时,文件自动关闭。
>>> with open('/tmp/mima') as f:
... f.readline()
... f.readline()
...
'hello world!\n'
'2nd line.\n'
>>> f.readline() # 文件已经关闭,无法再读取数据
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: I/O operation on closed file.
文件内移动
移动文件指针:seek(x, y)。y可以取值0,1,2,分别表示文件开头、当前位置和结尾。x是偏移量。
- seek(offset[, whence]):移动文件指针到不同的位
– offset是相对于某个位置的偏移量
– whence的值,0表示文件开头,1表示当前位置,2表示文件的结尾 - tell():返回当前文件指针的位置
>>> f = open('/tmp/mima')
>>> f.tell() # 显示当前位置,永远从开头算偏移量
0
>>> f.seek(5, 0)
5
>>> f.read(1)
' '
>>> f.close()
>>> f = open('/tmp/mima')
>>> f.read() # 读取全部内容
>>> f.read() # 再读就没有数据了
''
>>> f.seek(0, 0) # 回到文件开头
0
>>> f.read() # 再次读取文件内容
>>> f.close() # 关闭文件
>>> f = open('/tmp/mima', 'rb')
>>> f.seek(-5, 2) # 指针移动到文件结尾前5个字节处
32
>>> f.read()
b'\nend\n'
#以下写法,可以工作,但是不好,如果源文件很大,数据读取出来赋值给打data
#将会消耗大量内存
with open('/bin/ls', 'rb') as f1:
data = f1.read()
with open('/tmp/list', 'wb') as f2:
f2.write(data)
scr_fobj = open(scr_fname,'rb')
dst_fobj = open(dst_fname, 'wb')
while True:
data = scr_fobj.read(4096) # 每次最多读取4096字节
#if data == b'':
#if len(data) == 0: #leg(b'') -> 0
if not data: #data值为b'',表示False
break
else:
dst_fobj.write(data)
scr_fobj.close()
dst_fobj.close()
位置参数
python将位置参数保存在sys.argv列表中
# vim args.py
import sys
print(sys.argv)
# python3 args.py
['args.py']
# python3 args.py hao 123
['args.py', 'hao', '123']
函数基本操作
函数基本概念
- 函数是对程序逻辑进行结构化或过程化的一种编程方
- 将整块代码巧妙地隔离成易于管理的小块
- 把重复代码放到函数中而不是进行大量的拷贝,这样既能节省空间,也有助于保持一致性
- 通常函数都是用于实现某一种功能
创建函数
- 函数是用def语句来创建的,语法如下:
def function_name(arguments):
"function_documentation_string"
function_body_suite
- 标题行由def关键字,函数的名字,以及参数的集合(如果有的话)组成
- def子句的剩余部分包括了一个虽然可选但是强烈推荐的文档字串,和必需的函数体
调用函数
- 同大多数语言相同,python用一对圆括号调用函数
- 如果没有加圆括号,只是对函数的引用
>>> def foo():
... print('hello')
...
>>> foo()
hello
>>> foo
<function foo at 0x7ff2328967d0>
例子:
def fib_func():
#函数定义时,不会执行函数体内的代码
fib = [0,1]
n = int(input('长度: '))
for i in range(n - 2):
fib.append(fib[-1] + fib[-2])
print(fib)
fib_func() # 函数调用时,将会执行函数体内的代码
fib_func()
fib_func()
函数的返回值
- 多数情况下,函数并不直接输出数据,而是向调用者返回值
- 函数的返回值使用return关键字
- 没有return的话,函数默认返回None
>>> def foo():
... res = 3 + 4
>>> i = foo()
>>> print i
None
例子:
def fib_func():
#函数定义时,不会执行函数体内的代码
fib = [0,1]
n = int(input('长度: '))
for i in range(n - 2):
fib.append(fib[-1] + fib[-2])
return fib # 函数的运行结果.用关键字return返回
a = fib_func()
print(a)
函数参数
定义参数
- 形式参数
函数定义时,紧跟在函数名后(圆括号内)的参数被称为形式参数,简称形参。由于它不是实际存在变量,所以又称虚拟变量
def fib_func(n): # 函数的参数,形参
fib = [0,1]
for i in range(n - 2):
fib.append(fib[-1] + fib[-2])
return fib # 函数的运行结果.用关键字return返回
for i in range(2, 10):
print(fib_func(i))
- 实际参数
在主调函数中调用一个函数时,函数名后面括弧中的参数(可以是一个表达式)称为“实际参数”,简称实参
传递参数
- 调用函数时,实参的个数需要与形参个数一致
- 实参将依次传递给形参
>>> def foo(x, y):
... print('x=%d,y=%d' % (x,y))
>>> foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() takes exactly 2 arguments (0 given)
>>> foo(3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() takes exactly 2 arguments (1 given)
>>> foo(3, 4)
x=3, y=4
位置参数
- 与shell脚本类似,程序名以及参数都以位置参数的方式传递给python程序
- 使用sys模块的argv列表接收
[root@room9pc01 day03]# cat 3.py
# Python的位置变量保存在sys.argv列表中,即,argv是sys模块的一个列表
import sys
print(sys.argv)
[root@room9pc01 day03]# python3 3.py
['3.py']
[root@room9pc01 day03]# python3 3.py hao
['3.py', 'hao']
[root@room9pc01 day03]# python3 3.py hao 123
['3.py', 'hao', '123']
import sys
def copy(scr_fname, dst_fname):
scr_fobj = open(scr_fname,'rb')
dst_fobj = open(dst_fname, 'wb')
while True:
data = scr_fobj.read(4096) # 每次最多读取4096字节
#if data == b'':
#if len(data) == 0: #leg(b'') -> 0
if not data: #data值为b'',表示False
break
else:
dst_fobj.write(data)
scr_fobj.close()
dst_fobj.close()
copy(sys.argv[1], sys.argv[2])
默认参数
- 默认参数就是声明了默认值的参数
- 因为给参数赋予了默认值,所以在函数调用时,不向该参数传入值也是允许的
python
def pstar(n=30):
print('*' * n)
pstar(10) # 传参,使用n=10
pstar(50) # 传参,使用n=50
pstar(60)
pstar() # 传参,使用默认n=30
模块基础
模块实际上就是一个以.py结尾的文件,去除.py之后前面的文件名
模块基本概念
- 模块是从逻辑上组织python代码的形式
- 当代码量变得相当大的时候,最好把代码分成一些有组织的代码段,前提是保证它们的彼此交互
- 这些代码片段相互间有一定的联系,可能是一个包含数据成员和方法的类,也可能是一组相关但彼此独立的操作函数
创建模块
- 模块物理层面上组织模块的方法是文件,每一个以.py作为结尾的python文件都是一个模块
- 模块名称切记不要与系统中已存在的模块重名
- 模块文件名字去掉后面的扩展名(.py)即为模块名
导入模块(import)
- 使用import导入模块
- 模块属性通过“模块名.属性”的方法调用
- 如果仅需要模块中的某些属性,也可以单独导入
导入模块的方法
- import os :常用
- from random import randint,choice:仅导入模块的某些功能
>>> from random import randint, choice
>>> randint(1, 10)
5
>>> choice('abd')
'a'
>>> random.randint(1, 10)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'random' is not defined
- import sys,time,getpass :不常用
- import getpass as gp: 导入模块时,为其创建别名,不常用
>>> import getpass as gp
>>> gp.getpass()
Password:
- 第一模块导入(import)时,模块中的代码将会执行(load)一遍;再次导入,代码就不再执行了。
模块导入的特殊属性
- 每个模块都有一个内部变量叫_name_, _name_值有两种。当程序文件直接运行的时候,它的值是_main_,当它被别的程序导入时,值是模块名。
[root@room8pc16 day03]# cat foo.py
print(__name__)
[root@room8pc16 day03]# cat bar.py
import foo
[root@room8pc16 day03]# python3 foo.py
__main__
[root@room8pc16 day03]# python3 bar.py
foo