-
昨天回顾
id(x) 函数
is / is not 运算符
-
函数式编程
-
高阶函数
map(函数, 可迭代对象) # 返回生成器对象 filter(函数, 可迭代对象) # 返回生成器对象(生成器对象是可迭代对象) sorted(可迭代对象, key=None<函数>, reverse=False) # 返回列表
-
-
模块
xxx.py # xxx 就是模块名
-
导入模块
# 以 random 模块为例 # 1\. import random random.randint(1, 100) random.choice([1, 2, 3, 4, 5]) # 2\. from random import randint randint(1, 100) # 3\. from random import * randint(1, 100) choice([1, 2, 3, 4, 5])
-
-
预置模块
- random 模块
- time 模块
- datetime 模块
异常
-
作用
用作信号通知,通知上层调用者有错误产生需要处理
try 语句
- 语法
try:
可能发生异常的语句块
except 错误类型1 [as 变量名1]:
异常处理语句块1
except 错误类型2 [as 变量名2]:
异常处理语句块2
...
except 错误类型n [as 变量名n]:
异常处理语句块n
except:
异常处理语句块other
else:
未发生异常的语句
finally:
最终的处理语句
-
作用
尝试捕获异常,得到异常通知,将程序由异常状态变为正常状态
-
说明
except 子句可以有 1个或多个
except: 不给错误类型,可以匹配全部的错误类型
else 子句里的语句会在 没有错误发生时执行,当处于异常时不执行
finally 子句里的语句,无论何时都执行
-
示例
try: x = int(input("请输入一个整数:")) print('x=', x) except ValueError: print('您的输入不能转成整数') print("程序结束")
raise 语句
-
问题
# 写一个函数, get_score 函数,读取用户输入的整数成绩, # 成绩的正常值是0~100 之间, 要求, 如果不在0~100 之间 # 报 ValueError类型的错误 def get_score(): x = int(input('请输入成绩:')) if 0 <= x <= 100: return x raise ValueError('用户输入的成绩不在 0~100之间!')
-
语法
raise 异常类型
或
raise 异常对象 -
作用
- 抛出一个错误,让程序进入异常状态
- 发送错误通知给调用者
-
说明
- 一旦raise 语句被调用,则raise 之后的语句将不会执行。
-
示例:
# 写一个函数, get_score 函数,读取用户输入的整数成绩, # 成绩的正常值是0~100 之间, 要求, 如果不在0~100 之间 # 报 ValueError类型的错误 def get_score(): x = int(input('请输入成绩:')) if 0 <= x <= 100: return x # raise ValueError raise ValueError('用户输入的成绩不在 0~100 之间') try: score = get_score() print(score) except ValueError as err: print("成绩输入有误 err=", err)
-
异常类型的可选种类
详见:
>>> help(_builtins_)
字节串 bytes 和字节数组 bytearray
1 一个字节(byte)是8个二进制的位 (bit)
1个byte的取值范围是 0 ~ 255
bytes 不可变
bytearray 可变
字节串的字面值
>>> b''
>>> b""
>>> b''''''
>>> b''''''
>>> b'ABC'
>>> bytes([65, 66, 67, 68])
>>> bytes([65, 66, 67, 68, 200,255])
>>> bytes([65, 66, 67, 68, 200,255, 300]) # 300 超出了255 报错
>>> bytearray([65, 66, 67, 68, 200,255]) # 字节数组的创建必须使用bytearray函数
-
字节串的运算
字节串是序列,运算规则同元组一样
+ += * *= > >= < <= == != in / not in
索引和切片
-
示例
>>> b = bytes([65, 66, 67, 68, 200,255]) >>> b b'ABCD\xc8\xff' >>> b[0] 65 >>> b[:2] b'AB' >>> b += b'123' >>> b b'ABCD\xc8\xff123' >>> len(b) 9
-
bytes 和 str 的区别
bytes 存储的字节 (0~255 之间的数)
str 存储的是字符的编码
-
bytes 与 str 转换
编码(encode) str -------------> bytes b = s.encode(encoding='utf-8') 解码(decode) bytes -----------> str s = b.decode(encoding='utf-8')
示例
>>> s = 'hello 小张' >>> >>> b = s.encode() # 将字符串编码成为字节串 >>> b b'hello \xe5\xb0\x8f\xe5\xbc\xa0' # 在utf-8 编码中,1个汉字通常用3个字节进行编码 >>> len(b) 12 >>> s2 = b.decode() # 将字节串解码成为字符串 >>> s2 'hello 小张'
文件
-
什么是文件
文件通常用来存储以字节为单位的数据
-
文件的操作流程
- 打开文件
- 读/写文件
- 关闭文件
-
打开文件用open 函数
open(file, mode='rt') # open 函数返回文件流对象 # 打开失败回收到异常通知 # mode 的缺省值的 'rt'
-
示例
myfile = open('/etc/passwd', 'rt') s = myfile.read() # 用 myfile 绑定的文件流对象的read() 方法,得到 文件内部的数据 print(s) myfile.close() # 关闭文件
-
-
两种操作文件的模式
-
直接用 字节串操作文件(内部可以存储文字,也可以存储图片等信息)
打开模式 mode = 'b' # b是binary
-
用字符串操作文本文件(内部存储的都是文字)
打开模式 mode='t' # t 是text 的首字母(默认为't')
-
-
示例见
-
用字符串操作文件
f = open('mynote.txt', 'rt') # 'r 代表读 s = f.read() # 在't' 模式下 ,read 返回字符串 print(s) f.close() # 关闭
-
用字节串操作文件
f = open('mynote.txt', 'rb') # 'r' 代表读 'b' 代表以二进制方式操作 b = f.read() # 在't' 模式下 ,read 返回字节串 print(b) s = b.decode() # 将字节串转成了字符串 print(s) f.close() # 关闭
-
-
文件的打开模式 mode
模式 说明 't' 以文本(字符串) 的模式操作文件(默认) 'b' 以二进制(字节串) 的模式操作文件 -
文件的打开方式 mode
方式 说明 'r' 读取文件(默认) 'w' 写和覆盖写文件(如果文件不存在则创建文件 ) 'a' 写并且追加文件内容(如果文件不存在则创建文件) python 文件流对象的方法
方法名 说明 F.close() 关闭文件 读取文件的方法 F.read(size=-1) 读取文件(不给出size 参数过读取全部) F.readline() 读取文件中的一行,以'\n' 作为行分隔符 F.readlines() 读取文件中的全部,以'\n' 作为行分隔符, 返回行的列表 写文件的方法 F.write(x) 写文件: 'b'模式 x 必须是字节串, 't'模式x必须是字符串, 如果文件不存在则新建文件 -
练习
1. 写一个程序,输入任意个正整数,当输入负数是结束输入,
将输入的正整数写入文件data.txt 中
如:
请输入: 1
请输入: 2
请输入: 3
请输入: 4
请输入: -1
文件中的内容是:
1
2
3
42. 写一个程序,读入data.txt 中的数字,计算这些正整数的和并打印出来
mynote.txt 文件中的内容
我是老魏
我在 tarena
读数据
>>> f = open('mynote.txt', 'rb')
>>> f.read() # 返回全部
b'\xe6\x88\x91\xe6\x98\xaf\xe9\xad\x8f\xe7\x9c\x80\xe6\x8b\xa9\n\xe6\x88\x91\xe5\x9c\xa8 tarena\n'
>>> f.read() # 当到达文件尾部,返回空
b''
>>> f.close()
>>> f = open('mynote.txt', 'r')
>>> f.read()
'我是魏眀择\n我在 tarena\n'
>>> f.close()
>>> f = open('mynote.txt', 'r')
>>> f.readline() # 返回一行
'我是魏眀择\n'
>>> f.readline()
'我在 tarena\n'
>>> f.readline()
''
>>> f.close()
>>> f = open('mynote.txt', 'r')
>>> f.readlines() # 取出所有的行数据,返回列表
['我是魏眀择\n', '我在 tarena\n']
>>> f.close()
写数据
>>> f = open('python.log', 'w') # 以字符串方式写文件, 如果文件文件不存在回新建一个文件
>>> f.write('该吃饭了')
4
>>> f.write('!')
1
>>> f.write('\n') # 写一个换行
1
>>> f.write('下课')
2
>>> f.close()
-
移动文件的读写指针seek 方法
- 在读写二进制模式打开的文件,在不关闭文件的情况下, 可以使用seek 方法移动文件的读写指针
F.seek(偏移量, whence=相对位置)
偏移量(整数)
大于0 向文件末尾方向
小于0 向文件头方向
相对位置:
0 代表从文件头开始偏移
1 代表从当前的读写位置开始偏移
2 代表从文件末尾开始偏移 -
tell() 方法,返回文件的读写指针的位置
F.tell() # 返回整数
-
示例
mynote3.txt 的内容
1234567890ABCDE
示例程序
myfile = open('mynote2.txt', 'rb') print('刚打开文件时,文件指针的位置是:', myfile.tell()) # 0 b = myfile.read(2) print(b) # b'12' print('读取两个字节后,文件指针的位置是:', myfile.tell()) # 2 # 读取 67890 这个5个字节 # myfile.seek(5, 0) # 0 开始位置,向后移动5个字节 # myfile.seek(3, 1) # 1 当前位置,向后移动3个字节 myfile.seek(-10, 2) # 2 文件末尾位置,向前移动10个字节 print('myfile.seek()后,文件指针的位置是:', myfile.tell()) # 5 b = myfile.read(5) # b'67890' print('myfile.read(5)后,文件指针的位置是:', myfile.tell()) # 10 print(b) myfile.close()
with 语句
通过with 语句打开文件,with 语句结束,则文件会自动关闭
-
语法
with 表达式1 as 变量1[, 表达式2 as 变量2, ...]:
语句块 -
示例
# file: mynote2.txt # 不用with 语句 f = open('mynote2.txt') s = f.read() print(s) f.close() # 用with 语句 with open('mynote2.txt') as f: s = f.read() print(s)
sys模块
-
Shell 的位置参数
$0 $1 $2
-
python 上获取命令行参数
#! /usr/bin/python3 # file 04_myprog.py import sys print(sys.argv) # ['./04_myprog', '/root', 'hello'] # 如下是shell 中运行的内容 $ chmod +x myprog.py $ ./myprog /root hello # $0='./04_myprog' $1='/root' $2='hello'
-
os 模块
- 对操作系统的访问大多使用 python 中的os 模块
文档: https://docs.python.org/zh-cn/3/library/os.html
>>> import os
>>> os.getcwd() # 返回当前的工作路径,pwd
'/root/桌面/py02/day03_code'
>>> os.mkdir('/tmp/nsd21xx') # mkdir /tmp/nsd21xx
>>> os.makedirs('/tmp/nsd21xx/a/b/c') # mkdir -p /tmp/nsd21xx/a/b/c
>>> os.listdir() # ls
['mygames.py', '.idea', 'mynote.txt', 'python.log', 'mynote2.txt', '03_file_seek.py', '04_myprog.py', '05_cp.py', '01_read_text_file_by_string.py', '02_read_text_file_by_bytes.py']
>>> os.listdir('/tmp') # ls /tmp # 列出所有的文件夹
[ 'nsd21xx', 'dir1', 'dir2']
>>> os.chdir('/tmp/nsd21xx') # cd /tmp/nsd21xx
>>> os.getcwd() # pwd
'/tmp/nsd21xx'
>>> os.symlink('/etc/passwd', '/tmp/abc') # ln -s /etc/passwd /tmp/abc
>>> os.mknod('/tmp/myfile.txt') # touch /tmp/myfile.txt
>>> os.chmod('/tmp/myfile.txt', 0o755) # chmod 755 /tmp/myfile.txt
>>> os.rename('/tmp/myfile.txt', '/tmp/a.txt') # mv /tmp/myfile.txt /tmp/a.txt
>>> os.rmdir('/tmp/dir2') # rmdir /tmp/dir2
>>> os.remove('/tmp/a.txt') # rm /tmp/a.txt
-
字符串用于去掉空白字符串的方法
空白字符是指
' ', '\n' '\r' '\t'
>>> s = ' \n \t hello world \n' >>> s.strip() # 去掉左右两侧的空白字符 'hello world' >>> s.lstrip() # 去掉左侧的空白字符 'hello world \n' >>> s.rstrip() # 去掉右侧的空白字符 ' \n \t hello world'
os.path 模块
用于路径的操作的模块
>>> import os
>>> os.path.isabs('/root/abc.txt') # 判断是否为绝对路径
True
>>> os.path.isdir('/tmp/nsd21xx') # 判断是否是文件夹
True
>>> os.mknod('/tmp/b.txt') # touch /tmp/b.txt
>>> os.path.isfile('/tmp/b.txt') # 判断是否是文件
True
>>> os.path.islink('/tmp/abc') # 判断是否是软连接?
True
>>> os.path.ismount('/home') # 存在并且是挂载点
True
>>> os.path.exists('/root') # 判断文件或文件夹是否存在
True
>>> os.path.basename('/tmp/nsd21xx/hello.py') # 返回文件名
'hello.py'
>>> os.path.dirname('/tmp/nsd21xx/hello.py') # 返回路径
'/tmp/nsd21xx'
>>> os.path.split('/tmp/nsd21xx/hello.py') # 拆分 路径和文件名
('/tmp/nsd21xx', 'hello.py')
>>> os.path.join('/tmp/nsd21xx', 'world.py') # 拼接路径
'/tmp/nsd21xx/world.py'
os.walk() 函数
遍历文件夹
[root@localhost tmp]# tree /tmp/nsd21xx/
/tmp/nsd21xx/
├── a
│ ├── aaa.txt
│ └── b
│ ├── bbb.txt
│ └── c
└── aa
└── bb
└── cc
示例
>>> for x in os.walk('/tmp/nsd21xx'):
... print(x)
...
# (路径 , 路径内的所有文件夹列表 , 路径内的所有文件列表)
('/tmp/nsd21xx', ['a', 'aa'], [])
('/tmp/nsd21xx/a', ['b'], ['aaa.txt'])
('/tmp/nsd21xx/a/b', ['c'], ['bbb.txt'])
('/tmp/nsd21xx/a/b/c', [], [])
('/tmp/nsd21xx/aa', ['bb'], [])
('/tmp/nsd21xx/aa/bb', ['cc'], [])
('/tmp/nsd21xx/aa/bb/cc', [], [])
shutil 模块
文档: https://docs.python.org/zh-cn/3/library/shutil.html
>>> import shutil
>>> f1 = open('/etc/passwd', 'rb')
>>> f2 = open('/tmp/mypass.txt', 'wb')
>>> shutil.copyfileobj(f1, f2)
>>> f1.close()
>>> f2.close()
>>>
>>> shutil.copy('/etc/passwd', '/tmp/mypass2.txt') # cp /etc/passwd /tmp/mypass2.txt
'/tmp/mypass2.txt'
>>> shutil.copytree('/root/桌面/py02/day03_code', '/tmp/mycode') # cp -r /root/桌面/py02/day03_code /tmp/mycode
'/tmp/mycode'
>>> shutil.move('/tmp/mypass.txt', '/tmp/nsd21xx/a.txt') # mv /tmp/mypass.txt /tmp/nsd21xx/a.txt
>>> shutil.rmtree('/tmp/mycode') # rm -rf /tmp/mycode
>>> shutil.chown('/tmp/mypass.txt', user='xxx', group='yyy') # 改属主属组
-
课后练习:
实现 cp 命令
$ cp /etc/passwd /root/passwd
生成器
生成器是在程序运行时生成数据,与容器不同,它通常不会在内存中保留大量的数据,而是现用现生成。
生成器可以用算法动态的生成数据
生成器有两种
- 生成器函数
- 生成器表达式
生成器函数
含有yield 语句的函数 是生成器函数,此函数调用回返回一个生成器对象,生成器也是可迭代对象
yield 语句的语法
yield 表达式
生成器函数示例:
# 定义一个生成器函数, 有 yield 的函数调用后回返回生成器对象
def myrange(stop):
i = 0
while i < stop:
yield i # 为 遍历次生产器的for 语句提供数据
i += 1
for x in myrange(5):
print('x=', x)
生成器表达式
- 语法:
( 表达式 for 变量 in 可迭代对象 [if 真值表达式])
[] 内容代表可以省略
-
作用
用推导式的形式创建一个生成器
示例
>>> [x ** 2 for x in range(1, 5)] # 列表解析(列表推导式)
[1, 4, 9, 16]
>>>
>>> (x ** 2 for x in range(1, 5)) # 生成器表达式
at 0x7f41dcd30a40>
>>> for y in (x ** 2 for x in range(1, 5)):
... print(y)
...
1
4
9
16