admin管理员组文章数量:1660198
0.前言
此文章为作者学习python时候所做的笔记。
1.Python基础知识
1.1Python是一种怎样的语言
Python是一门跨平台、开源、免费的解释型高级动态编程语言,支持伪编译将Python源程序转换为字节码来优化程序和提高运行速度,支持使用py2exe、pyinstaller或cx_Freeze工具将Python程序转换为二进制可执行文件。
Python支持命令式编程(How to do)、函数式编程(What to do),完全支持面向对象程序设计,语法简洁清晰,拥有大量的几乎支持所有领域应用开发的成熟扩展库。
1.2相关重要网址
- Python官网
- Python2中文教程网
- Python3中文教程网
- Anaconda官网
- PyCharm官网
1.3Python编程环境
PyCharm(本文主要使用):JetBrains公司开发的Python IDE,功能强大,支持代码自动补全、调试、版本控制等。
PyCharm介绍: PyCharm使用详细教程
Visual Studio Code:微软开发的轻量级代码编辑器,支持Python插件,可以实现代码自动补全、调试等功能。
Sublime Text:一款轻量级的文本编辑器,支持Python插件,可以实现代码高亮、自动补全等功能。
Jupyter Notebook:一种基于Web的交互式计算环境,支持Python、R等多种编程语言,可以实现代码编辑、运行、可视化等功能。
IDLE:Python自带的集成开发环境,简单易用,适合初学者使用。
Anaconda本身并不是一个开发和调试环境,而是一个集成各类Python工具的集成平台,将很多第三方的开发调试环境集成到一起。
Anaconda安装:Anaconda超详细安装教程(Windows环境下)
Anaconda基础使用:Anaconda使用教程
Anaconda中的conda
Anaconda中的Spyder
1.4使用pip管理第三方包
pip 是 Python 包管理工具,该工具提供了对 Python 包的查找、下载、安装、卸载的功能。
软件包也可以在 https://pypi/ 中找到。
目前最新的 Python 版本已经预装了 pip。
pip常用命令 | 功能介绍 |
---|---|
pip --version | 查看pip版本(可以用于检测pip本体是否安装成功) |
pip list | 查看已经安装的包 |
pip install (packge[==version]) | 在线安装SomePackage模块的指定版本 |
pip download (package[==version]) | 下载但不安装包 |
pip install (package.whl) | 通过whl文件离线安装扩展库 |
pip install --upgrade (package) | 升级SomePackage模块 |
pip uninstall (package[==version]) | 卸载SomePackage模块的指定版本 |
更多的 命令功能 请在命令行
中输入pip help来获取帮助
在Windows平台上,如果在线安装扩展库失败,可以使用pip命令进行离线安装:
- 打开http://www.lfd.uci.edu/~gohlke/pythonlibs/
- 下载扩展库编译好的.whl文件(注意版本,并且一定不要修改下载的文件名)
-文件下载好后,打开文件所在文件夹 - 按Shift + 右键 → 在终端(命令窗口)中打开
- 输入:pip install 包名.whl
pip命令还支持指定国内的站点来提高速度。
默认下载网址在外国,下载速度很慢。
国内常用pip源:
https://pypi.tuna.tsinghua.edu/simple #清华(推荐)
http://mirrors.aliyun/pypi/simple/ #阿里云(推荐)
https://pypi.mirrors.ustc.edu/simple/ #中国科技大学
http://pypi.hustunique/ #华中理工大学
http://pypi.sdutlinux/ #山东理工大学
http://pypi.douban/simple/ #豆瓣
临时使用其他源(比如阿里源):
pip install (包名) -i https://pypi.tuna.tsinghua.edu/simple some-package
永久使用其他源:
- 首先按Win + R键 输入%APPDATA%并运行,进入Roaming文件夹
- 找到目录中的pip文件夹(没有则新建),再打开pip.ini并修改内容为下列,保存退出:
[global]
index-url = https://mirrors.aliyun/pypi/simple/extra-index-url = https://pypi.tuna.tsinghua.edu/simple
[install]
trusted-host = https://mirrors.aliyun/pypi/simple/
- 在命令窗口输入pip config list,检查是否修改成功
[global]中第一条为首选源(阿里源)
第二条(extra-index-url)为额外补充的源(清华源)
[install]中第一条将阿里源设为信任源
如果遇到类似于“拒绝访问”的出错信息,需要在执行pip命令时增加选项–user,例如
pip install (包名)–user
1.5文件名
- .py:Python源文件,由Python解释器负责解释执行。
- .pyw:Python源文件,常用于图形界面程序文件。
- .pyc:Python字节码文件,无法使用文本编辑器直接查看该类型文件内容,可用于隐藏Python源代码和提高运行速度。对于Python模块,第一次被导入时将被编译成字节码的形式,并在以后再次导入时优先使用“.pyc”文件,以提高模块的加载和运行速度。对于非模块文件,直接执行时并不生成“.pyc”文件,但可以使用py_compile模块的compile()函数进行编译以提高加载和运行速度。另外,Python还提供了compileall模块,其中包含compile_dir()、compile_file()和compile_path()等方法,用来支持批量Python源程序文件的编译。
- .pyo:优化的Python字节码文件,同样无法使用文本编辑器直接查看其内容。可以使用“python –O -m py_compile file.py”或“python –OO -m py_compile file.py”进行优化编译。Python 3.5不再支持.pyo文件。
- .pyd:一般是由其他语言编写并编译的二进制文件,常用于实现某些软件工具的Python编程接口插件或Python动态链接库。
1.6Python程序打包
生成可运行文件(windows下为.exe)
可以把Python程序打包为可执行程序的工具有py2exe(仅适用于Windows平台)、pyinstaller、cx_Freeze等等。
以pyinstaller为例,使用pip工具安装该工具之后在命令提示符环境中使用命令“pyinstaller -F -w kousuan.pyw”或者“python pyinstaller-script.py -F -w kousuan.pyw”即可将Python程序kousuan.pyw及其所有依赖包打包成为当前所用平台上的可执行文件。
2.Python基本创建与处理
2.1Python的对象模型
对象是python语言中最基本的概念,在python中处理的一切都是对象。python中有许多内置对象可供编程者使用,内置对象可直接使用,如数字、字符串、列表、del等;非内置对象需要导入模块才能使用,如正弦函数sin(x),随机数产生函数random( )等。
对象类型 | 类型名称 | 示例 | 简要说明 |
数字 | int, float, complex | 1234, 3.14, 1.3e5, 3+4j | 数字大小没有限制,内置支持复数及其运算 |
字符串 | str | 'swfu', "I'm student", '''Python ''', r'abc', R'bcd' | 使用单引号、双引号、三引号作为定界符,以字母r或R引导的表示原始字符串 |
字节串 | bytes | b’hello world’ | 以字母b引导,可以使用单引号、双引号、三引号作为定界符 |
列表 | list | [1, 2, 3],['a', 'b', ['c', 2]] | 所有元素放在一对方括号中,元素之间使用逗号分隔,其中的元素可以是任意类型 |
字典 | dict | {1:'food' ,2:'taste', 3:'import'} | 所有元素放在一对大括号中,元素之间使用逗号分隔,元素形式为“键:值” |
元组 | tuple | (2, -5, 6), (3,) | 不可变,所有元素放在一对圆括号中,元素之间使用逗号分隔,如果元组中只有一个元素的话,后面的逗号不能省略 |
集合 | set frozenset | {'a', 'b', 'c'} | 所有元素放在一对大括号中,元素之间使用逗号分隔,元素不允许重复;另外,set是可变的,而frozenset是不可变的 |
布尔型 | bool | True False | 逻辑值,关系运算符、成员测试运算符、同一性测试运算符组成的表达式的值一般为True或False |
空类型 | NoneType | None | 空值 |
异常 | Exception、ValueError、TypeError | Python内置大量异常类,分别对应不同类型的异常 | |
文件 |
| f = open('data.dat', 'rb') | open是Python内置函数,使用指定的模式打开文件,返回文件对象 |
其他可迭代对象 |
| 生成器对象、range对象、zip对象、enumerate对象、map对象、filter对象等等 | 具有惰性求值的特点,除range对象之外,其他对象中的元素只能看一次 |
编程单元 | 函数(使用def定义) 类(使用class定义) 模块(类型为module) | 类和函数都属于可调用对象,模块用来集中存放函数、类、常量或其他对象 |
2.2Python变量
2.2.1Python变量创建
Python中,不需要事先声明变量名及其类型,直接赋值即可创建各种类型的对象变量。这一点适用于Python任意类型的对象。
Python属于强类型编程语言,Python解释器会根据赋值或运算来自动推断变量类型。
Python还是一种动态类型语言,变量的类型也是可以随时变化的。
定义变量名的时候,需要注意以下问题:
- 变量名必须以字母、汉字或下划线开头,但以下划线开头的变量在Python中有特殊含义;
- 变量名中不能有空格以及标点符号(括号、引号、逗号、斜线、反斜线、冒号、句号、问号等等);
- 不能使用关键字作变量名,可以导入keyword模块后使用print(keyword.kwlist)查看所有Python关键字;
- 不建议使用系统内置的模块名、类型名或函数名以及已导入的模块名及其成员名作变量名,这将会改变其类型和含义,可以通过dir(__builtins__)查看所有内置模块、类型和函数;
- 变量名对英文字母的大小写敏感,例如student和Student是不同的变量。
创建数字
可以表示任意大小的数值,不像C/C++那样有具体的数据类型限制。
也可以用科学计数法,例如:314.15e-2。
整数类型可分为二进制(0b开头),八进制(0o开头),十进制,十六进制(0x开头)。
Python内置支持复数类型,例如:c = 8+10j,可用c.real查看实部,c.imag查看虚部,c.conjugate()返回共轭复数,还可以进行加减乘除。
Python 3.6.x开始支持在数字中间位置使用单个下划线作为分隔来提高数字的可读性,例如:1_2_3_4 == 1234
创建字符串
字符串属于不可变序列。单引号、双引号或三引号界定的符号系列称为字符串,同时可以互相嵌套来表示复杂字符串,例如:'''Tom said, "Let's go"'''
三引号'''或"""表示的字符串可以换行,支持排版较为复杂的字符串;三引号还可以在程序中表示较长的注释。
字符串中常用一些转用字符:
转义字符 | 含义 | 转义字符 | 含义 |
\b | 退格,把光标移动到前一列位置 | \\ | 一个斜线\ |
\f | 换页符 | \’ | 单引号’ |
\n | 换行符 | \” | 双引号” |
\r | 回车 | \ooo | 3位八进制数对应的字符 |
\t | 水平制表符 | \xhh | 2位十六进制数对应的字符 |
\v | 垂直制表符 | \uhhhh | 4位十六进制数表示的Unicode字符 |
字符串界定符前面加字母r或R表示原始字符串,其中的特殊字符不进行转义,但字符串的最后一个字符不能是\。原始字符串主要用于正则表达式、文件路径或者URL的场合。
2.2.2Python变量存储与地址
#创建了整型变量x,并赋值为3
x = 3
print(type(x)) #输出:<class 'int'>
#创建了字符串变量x,并赋值为'Hello world.'此时为新的字符串变量,不是原来的x。
x = 'Hello world.'
print(type(x)) #输出:<class 'str'>
x = [1,2,3]
print(type(x)) #输出:<class 'list'>
如果变量出现在赋值运算符或复合赋值运算符(例如+=、*=等等)的左边:表示创建变量或修改变量的值,否则表示引用该变量的值。
>>> x = 3 #创建整型变量
>>> print(x**2) 9 >>> x += 6 #修改变量值
>>> print(x) #读取变量值并输出显示
9
>>> x = [1,2,3] #创建列表对象
>>> x[1] = 5 #修改列表元素值
>>> print(x) #输出显示整个列表
[1, 5, 3]
>>> print(x[2]) #输出显示列表指定元素
3
字符串和元组属于不可变序列,不能通过下标的方式来修改其中的元素值,试图修改元组中元素的值时会抛出异常。
>>> x = (1,2,3)
>>> y = 'abcd'
>>> print(x)
(1, 2, 3)
>>> print(y)
abcd
>>> x[1] = 5
ERROR
在Python中,允许多个变量指向同一个值(变量名不同但是地址相同)
然而,当为其中一个变量修改值以后,其内存地址将会变化,但这并不影响另一个变量
Python采用基于值的内存管理方式,如果为不同变量赋值为相同值,这个值在内存中只保存一份,多个变量指向同一个值的内存空间首地址,这样可以减少内存空间的占用,提高内存利用率。
Python启动时,会对[-5, 256]区间的整数进行缓存。也就是说,如果多个变量的值相等且介于[-5, 256]区间内,那么这些变量共用同一个值的内存空间。 对于区间[-5, 256]区间之外的整数,同一个程序中或交互模式下同一个语句中的同值不同名变量会共用同一个内存空间,不同程序或交互模式下不同语句不遵守这个约定。
>>> x = 3
>>> id(x)
1786684560 #x的地址
>>> y = x
>>> id(y)
1786684560 #y的地址,与x相同
>>> x += 6 #x的值修改
>>> id(x)
1786684752 #x地址变化
>>> y
3 #y的值不变
>>> id(y)
1786684560 #y地址不变
赋值语句的执行过程是:首先把等号右侧表达式的值计算出来,然后在内存中寻找一个位置把值存放进去,最后创建变量并指向这个内存地址。(Python不太一样)
Python中的变量并不直接存储值,而是存储了值的内存地址或者引用,这也是变量类型随时可以改变的原因。
Python具有自动管理内存的功能,会跟踪所有的值,并自动删除不再使用或者引用次数为0的值。如果确定某个变量不再使用,可以使用del命令显式删除该变量,值的引用次数减1,当某个值的引用次数变为0时,将会被Python的垃圾回收机制自动删除并释放内存空间。
2.3运算符和表达式
功能介绍
运算符 | 功能说明 |
+ | 算术加法,列表、元组、字符串合并与连接,正号 |
- | 算术减法,集合差集,相反数 |
* | 算术乘法,(内容进行重复“a"*3="aaa")序列重复 |
/ | 真除法 |
// | 整除,求整商,但如果操作数中有实数的话,结果为实数形式的整数 |
% | 求余数,字符串格式化 |
** | 幂运算 |
<、<=、>、>=、==、!= | 大小比较,集合的包含关系比较 (Python中关系运算符可用连用。1 < 3 < 5等价于1 < 3 and 3 < 5) |
or | 逻辑或(惰性求值) |
and | 逻辑与(惰性求值) |
not | 逻辑非 |
in | 成员测试(测试一个对象是否为另一个对象的元素) |
is | 对象同一性测试,即测试是否为同一个对象或内存地址是否相同 |
|、^、&、<<、>>、~ | 位或、位异或、位与、左移位、右移位、位求反 (位运算符只能用于整数,转为二进制数进行) 集合运算借助于位运算符来实现,交集(&)、并集(|)、对称差集(^)、差集(-) |
&、|、^ | 集合交集、并集、对称差集 |
, | 逗号并不是运算符,只是一个普通分隔符。 |
++,-- | Python不支持++和--运算符,只是两个连续的加号和减号。 |
优先度排序
运算符(优先度从低到高) | 描述 |
:= | 赋值表达式,Python 3.8新增 |
lambda | lambda 表达式 |
if -- else | 条件表达式 |
or | 逻辑或运算 |
and | 逻辑与运算 |
not | 逻辑非运算 |
in, not in, is, is not, <, <=, >, >=, !=, == | 测试、比较 |
| | 位或运算 |
^ | 位异或运算 |
& | 位与运算 |
<<, >> | 左移位,右移位 |
+, - | 加,减 |
*, @, /, //, % | 乘,矩阵乘,除,整除,取余 |
+x, -x, ~x | 正,负,位求反 |
** | 幂运算,具有右结合性 |
await x | await表达式 |
x[index], x[index:index], x(arguments...), x.attribute | 抽取,切片,调用,属性引用 |
(expressions...), [expressions...], {key: value...}, {expressions...} | 绑定或加圆括号的表达式,列表显示,字典显示,集合显示 |
2.4常用内置函数
内置函数不需要导入任何模块即可使用,执行 dir(__builtins__) 可列出所有内置函数
函数 | 功能简要说明 |
数学操作 | |
abs(x) | 返回数字x的绝对值或复数x的模 |
max(x)、 min(x) | 返回可迭代对象x中的最大值、最小值,要求x中的所有元素之间可比较大小,允许指定排序规则和x为空时返回的默认值。key参数可以用来指定比较规则,例:长度为比较方法max(x, key=len)。 |
pow(x, y, z=None) | 返回x的y次方,等价于x ** y或(x ** y) % z |
round(x [, 小数位数]) | 对x进行四舍五入,若不指定小数位数,则返回整数 |
complex(real, [imag]) | 返回复数 |
divmod(x, y) | 返回包含整商和余数的元组((x-x%y)/y, x%y) |
eval(s[, globals[, locals]]) | 计算并返回字符串s中表达式的值 |
转换 | |
ord(x) | 返回1个字符x的Unicode编码 |
chr(x) | 返回Unicode编码x对应的1个字符 |
ascii(obj) | 把对象转换为ASCII码表示形式,必要的时候使用转义字符来表示特定isinstance的字符 |
bool(x) | 返回与x等价的布尔值True或False |
bytes(x) | 生成字节串,或把指定对象x转换为字节串表示形式 |
bin(x),oct(x),hex(x) | 把整数x转换为二进制串表示形式,八进制,十六进制 |
id(obj) | 返回对象obj的标识(内存地址) |
str(obj) | 把对象obj直接转换为字符串 |
类型查看 | |
type(obj) | 返回对象obj的类型 |
isinstance(obj, class-or-type-or-tuple) | 测试对象obj是否属于指定类型(如果有多个类型的话需要放到元组中)的实例 |
帮助信息 | |
dir(obj) | 返回指定对象或模块obj的成员列表或者指定对象类型所支持的操作。如果不带参数则返回当前作用域内所有标识符 |
help(obj) | 返回对象obj的帮助信息 |
输入输出 | |
print(value, ..., sep=' ', end='\n', file = sys. stdout, flush=False) | 基本输出函数 |
input([提示]) | 显示提示,接收键盘输入的内容,返回字符串。需要将其转换为相应的类型再处理。 |
其他 | |
callable(obj) | 测试对象obj是否可调用。类和函数是可调用的,包含__call__()方法的类的对象也是可调用的 |
delattr(obj, name) | 删除属性,等价于del obj.name |
compile() | 用于把Python代码编译成可被exec()或eval()函数执行的代码对象 |
exec(x) | 执行代码或代码对象x |
exit() | 退出当前解释器环境 |
quit() | 退出当前解释器环境 |
getattr(obj, name[, default]) | 获取对象中指定属性的值,等价于obj.name,如果不存在指定属性则返回default的值,如果要访问的属性不存在并且没有指定default则抛出异常 |
hasattr(obj, name) | 测试对象obj是否具有名为name的成员 |
hash(x) | 返回对象x的哈希值,如果x不可哈希则抛出异常 |
int(x[, d]),float(x),double(x), | 数据类型转换,或把对应的字符串x转换为相应数据类型并返回。 |
iter(...) | 返回指定对象的可迭代对象 |
locals() | 返回包含当前作用域内局部变量及其值的字典 |
next(iterator[, default]) | 返回可迭代对象x中的下一个元素,允许指定迭代结束之后继续迭代时返回的默认值 |
open(name[, mode]) | 以指定模式mode打开文件name并返回文件对象 |
repr(obj) | 返回对象obj的规范化字符串表示形式,对于大多数对象有eval(repr(obj))==obj |
创建二维列表 x = [[randrange(1,100) for i in range(10)] for j in range(5)]
2.5模块导入和使用
Python默认安装仅包含部分基本或核心模块,但用户可以安装大量的扩展模块,pip是管理模块的重要工具。
在Python启动时,仅加载了很少的一部分模块,在需要时由程序员显式地加载(可能需要先安装)其他模块。
减小运行的压力,仅加载真正需要的模块和功能,且具有很强的可扩展性。
可以使用 sys.modules.items() 显示所有预加载模块的相关信息。
- 可以使用dir()函数查看任意模块中所有的对象列表,如果调用不带参数的dir()函数,则返回当前作用域所有名字列表。
- 可以使用help()函数查看任意模块或函数的使用帮助。
基本语法:
import 模块名
from 模块名 import 对象名 as 别名 #可以减少查询次数,提高执行速度,别名可不写
导入模块时的文件搜索顺序:
- 当前文件夹
- sys.path变量指定的文件夹
- 优先导入pyc文件
在2.x中可以使用reload函数重新导入一个模块,在3.x中,需要使用imp模块的reload函数。
Python首先在当前目录中查找需要导入的模块文件,如果没有找到则从sys模块的path变量所指定的目录中查找。可以使用sys模块的path变量查看python导入模块时搜索模块的路径,也可以向其中append自定义的目录以扩展搜索路径。
在导入模块时,会优先导入相应的pyc文件,如果相应的pyc文件与py文件时间不相符,则导入py文件并重新编译该模块。
2.6代码规范
可以使用pip来安装pep8工具,然后使用命令pep8 test.py来检查test.py文件中Python代码的规范性。pep8常用的可选参数有--show-source、--first、--show-pep8等等。
flake8结合了pyflakes和pep8的特点,可以检查更多的内容,优先推荐使用,使用pip install flake8可以直接安装,然后使用命令flake8 test.py检查test.py中代码的规范性。
也可以使用pip安装pylint,然后使用命令行工具pylint或者可视化工具pylint-gui来检查程序的规范性。
2.6.1缩进
- 类定义、函数定义、选择结构、循环结构、with块,行尾的冒号表示缩进的开始。
- python程序是依靠代码块的缩进来体现代码之间的逻辑关系的,缩进结束就表示一个代码块结束了。
- 同一个级别的代码块的缩进量必须相同。
- 一般而言,以4个空格为基本缩进单位(按一下tab)。
2.6.2注释
- 以#开始,表示本行#之后的内容为注释。
- 包含在一对三引号'''...'''或"""..."""之间且不属于任何语句的内容将被解释器认为是注释。
2.6.3美观
- 如果一行语句太长,可以在行尾加上续行符\来换行分成多行,但是更建议使用括号来包含多行内容。
- 必要的空格与空行:运算符两侧、逗号后面建议增加一个空格。 不同功能的代码块之间、不同的函数定义之间建议增加一个空行以增加可读性。
2.8补充
2.8.1Python脚本的“__name__”属性
每个Python脚本在运行时都有一个“__name__”属性。
如果脚本作为模块被导入,则其“__name__”属性的值被自动设置为模块名;
如果脚本独立运行,则其“__name__”属性值被自动设置为“__main__”。
2.8.2编写自己的包与模块
在包的每个目录中都必须包含一个__init__.py文件,该文件可以是一个空文件,仅用于表示该目录是一个包。
__init__.py文件的主要用途是设置__all__变量以及所包含的包初始化所需的代码。其中__all__变量中定义的对象可以在使用from …import *时全部正确导入.
2.8.3Python程序伪编译
可以使用py_compile模块的compile()函数或compileall模块的compile_file()函数对Python源程序文件进行伪编译得到扩展名为.pyc的字节码以提高加载和运行速度,同时还可以隐藏源代码。
假设有Python程序Stack.py文件,并已导入py_compile,那么可以使用语句py_compilepile('Stack.py')把Stack.py伪编译为字节码,如果需要优化编译可以使用py_compilepile('Stack.py', optimize=1)或py_compilepile('Stack.py', optimize=2)生成不同优化级别的字节码文件。
生成的字节码文件都保存为__pycache__文件夹中。
3.Python序列
3.1序列概述
Python中常用的序列结构有列表、元组、字符串,字典、集合以及range、zip、filter等对象也支持很多类似的操作。
Python采用的是基于值的自动内存管理方式,当为对象修改值时,并不是真的直接修改变量的值,而是使变量指向新的值,这对于Python所有类型的变量都是一样的。
>>> a = [1,2,3] >>> id(a) #返回对象的内存地址
20230752
>>> a = [1,2]
>>> id(a)
20338208
3.1.1 | 列表 | 元组 | 字典 | 集合 |
类型名称 | list | tuple | dict | set |
定界符 | 方括号[] | 圆括号() | 大括号{} | 大括号{} |
是否可变 | 是 | 否 | 是 | 是 |
是否有序 | 是 | 是 | 否 | 否 |
是否支持下标 | 是(序号下标) | 是(序号下标) | 是(“键”下标) | 否 |
元素分隔符 | 逗号 | 逗号 | 逗号 | 逗号 |
对元素形式的要求 | 无 | 无 | 键:值 | 必须可哈希 |
对元素值的要求 | 无 | 无 | “键”必须可哈希 | 必须可哈希 |
元素是否可重复 | 是 | 是 | “键”不可重复,“值”可重复 | 否 |
元素查找速度 | 非常慢 | 很慢 | 非常快 | 非常快 |
新增和删除元素速度 | 尾部操作快 其他位置慢 | 不允许 | 快 | 快 |
3.1.2列表排序
1. 使用列表对象的 sort() 方法进行原地排序,支持多种不同的排序方法。sort() 方法没有返回值。
aList.sort() # 默为认升序排序
aList.sort(reverse=True) # 降序排序
aList.sort(key=lambda x:len(str(x))) # 按转换成字符串的长度排序
2. 使用内置函数 sorted() 对列表进行排序并返回新列表。
sorted(aList) #升序排序
#其他语法大致一样
3. 使用列表对象的 reverse() 方法将元素原地逆序。
4. 使用内置函数 reversed() 对列表元素进行逆序排列并返回迭代对象。
newList = reversed(aList) #返回reversed对象
list(newList) #把reversed对象转换成列表
5. 举例
使用key来指定排序依据,先按姓名升序排序,姓名相同的按年龄降序排序
sorted(persons, key=lambda x:(x['name'], -x['age']))
#按字典中元素值进行排序
sorted(phonebook.items(), key=itemgetter(1))
#按字典中元素的键进行排序
sorted(phonebook.items(), key=itemgetter(0))
gameresult = [['Bob', 95.0, 'A'], ['Alan', 86.0, 'C'], ['Mandy', 83.5, 'A'], ['Rob', 89.3, 'E']]
sorted(gameresult, key=itemgetter(0, 1)) #按姓名升序,姓名相同按分数升序排序
#按'wins'升序,该值相同的按'name'升序排序
gameresult = [{'name':'Bob', 'wins':10, 'losses':3, 'rating':75.0},
{'name':'David', 'wins':3, 'losses':5, 'rating':57.0},
{'name':'Carol', 'wins':4, 'losses':5, 'rating':57.0},
{'name':'Patty', 'wins':9, 'losses':3, 'rating':72.8}]
sorted(gameresult, key=itemgetter('wins', 'name'))
3.1.3序列操作的常用内置函数 | |
sorted(iterable, key=None, reverse=False) | 返回排序后的列表,其中iterable表示要排序的序列或迭代对象,key用来指定排序规则或依据,reverse用来指定升序或降序。该函数不改变iterable内任何元素的顺序 |
frozenset([x])) | 创建不可变的集合对象 |
globals() | 返回包含当前作用域内全局变量及其值的字典 |
len(obj) | 返回对象obj包含的元素个数,适用于列表、元组、集合、字典、字符串以及range对象和其他可迭代对象 |
sum(列表) | 对列表的元素进行求和运算,对非数值型列表运算需要指定start参数,同样适用于元组、range。 |
max(列表)、 min(列表) | 返回列表中的最大或最小元素,同样适用于元组、字典、集合、range对象等。 |
list([x])、set([x])、tuple([x])、dict([x]) | 把对象x转换为列表、集合、元组或字典并返回,或生成空列表、空集合、空元组、空字典 |
range([start,] end [, step] ) | 返回range对象,其中包含左闭右开区间[start,end)内以step为步长的整数 |
reversed(seq) | 返回seq(可以是列表、元组、字符串、range以及其他可迭代对象)中所有元素逆序后的迭代器对象 |
reduce(func, sequence[, initial]) | 将双参数的函数func以迭代的方式从左到右依次应用至序列seq中每个元素,最终返回单个值作为结果。在Python 2.x中该函数为内置函数,在Python 3.x中需要从functools中导入reduce函数再使用 |
all(iterable) | 如果对于可迭代对象中所有元素x都等价于True,也就是对于所有元素x都有bool(x)等于True,则返回True。对于空的可迭代对象也返回True |
any(iterable) | 只要可迭代对象iterable中存在元素x使得bool(x)为True,则返回True。对于空的可迭代对象,返回False |
map(func, *iterables) | 返回包含若干函数值的map对象,函数func的参数分别来自于iterables指定的每个迭代对象 |
enumerate(iterable[, start]) | 返回包含元素形式为(0, iterable[0]), (1, iterable[1]), (2, iterable[2]), ...的迭代器对象 |
filter(func, seq) | 返回filter对象,其中包含序列seq中使得单参数函数func返回值为True的那些元素,如果函数func为None则返回包含seq中等价于True的元素的filter对象。(即生成以func判断为真的元素为元素的列表) |
zip(seq1 [, seq2 [...]]) | 返回zip对象,其中元素为(seq1[i], seq2[i], ...)形式的元组,最终结果中包含的元素个数取决于所有参数序列或可迭代对象中最短的那个 |
补充说明:map、filter、enumerate、zip等对象不仅具有惰性求值的特点,还有另外一个特点:访问过的元素不可再次访问。 |
3.2序列概述
列表是Python中内置有序、可变序列,列表的所有元素放在一对中括号[]中,并使用逗号分隔开;
当列表元素增加或删除时,列表对象自动进行扩展或收缩内存,保证元素之间没有缝隙;
Python中,一个列表中的数据类型可以各不相同,可以同时分别为整数、实数、字符串等基本类型,甚至是列表、元组、字典、集合以及其他自定义类型的对象。
3.2.1列表常用方法 | 说明 |
lst.append(x) | 将元素x添加至列表lst尾部(直接添加) |
lst.extend(L) | 将列表L中所有元素添加至列表lst尾部 |
lst.insert(index, x) | 在列表lst指定位置index处添加元素x,该位置后面的所有元素后移一个位置 |
lst.remove(x) | 在列表lst中删除首次出现的指定元素,该元素之后的所有元素前移一个位置 |
lst.pop([index]) | 删除并返回列表lst中下标为index(默认为-1)的元素 |
lst.clear() | 删除列表lst中所有元素,但保留列表对象 |
lst.index(x) | 返回列表lst中第一个值为x的元素的下标,若不存在值为x的元素则抛出异常 |
lst.count(x) | 返回指定元素x在列表lst中的出现次数 |
lst.reverse() | 对列表lst所有元素进行逆序 |
lst.sort(key=None, reverse=False) | 对列表lst中的元素进行排序,key用来指定排序依据,reverse决定升序(False)还是降序(True) |
lst.copy() | 返回列表lst的浅复制 |
其他操作 | |
= | 直接将一个列表赋值给变量即可创建列表对象 a_list = ['a', 'b', '1', 'example'] a_list = [] #创建空列表 |
list() | 可以使用函数将元组、range对象、字符串或其他类型的可迭代对象类型的数据转换为列表。 a_list = list((3,5,7,9,11)) list(range(1,10,2)) list('hello world') |
del | 当不再使用时,使用del命令删除整个列表。 del a_list |
+ | 可以使用“+”运算符将元素添加到列表中 这并不是真的为列表添加元素,而是创建了一个新列表。该操作速度较慢 aList = aList + [7] |
+= | 类似于列表的extend()方法。 |
* | 扩展列表对象,将列表与整数相乘,生成一个新列表,新列表是原列表中元素的重复。 aList = [3,5,7] aList * 3 [3, 5, 7, 3, 5, 7, 3, 5, 7] |
in | 使用in关键字来判断一个值是否存在于列表中,返回结果为“True”或“False”。 3 in a_List |
3.2.2列表中包含的是元素值的引用,而不是直接包含元素值。
- 如果是直接修改序列变量的值,则与Python普通变量的情况是一样的
- 如果是通过下标来修改序列中元素的值或通过可变序列对象自身提供的方法来增加和删除元素时,序列对象在内存中的起始地址是不变的,仅仅是被改变值的元素地址发生变化,也就是所谓的“原地操作”。
3.2.3应尽量从列表尾部进行元素的增加与删除操作。
- 列表的insert()可以在列表的任意位置插入元素,但由于列表的自动内存管理功能,insert()方法会引起插入位置之后所有元素的移动,这会影响处理速度。
- 类似的还有后面介绍的remove()方法以及使用pop()函数弹出列表非尾部元素和使用del命令删除列表非尾部元素的情况。
当使用 * 运算符将包含列表的列表重复并创建新列表时,并不是复制子列表值,而是复制已有元素的引用。因此,当修改其中一个值时,相应的引用也会被修改。
>>> x = [[None] * 2] * 3
>>> x
[[None, None], [None, None], [None, None]]
>>> x[0][0] = 5
>>> print(x)
[[5, None], [5, None], [5, None]]
3.2.4切片操作
切片适用于列表、元组、字符串、range对象等类型,但作用于列表时功能最强大。可以使用切片来截取列表中的任何部分,得到一个新列表,也可以通过切片来修改和删除列表中部分元素,甚至可以通过切片操作为列表对象增加元素。
切片使用2个冒号分隔的3个数字来完成 [ : : ]
- 第一个数字表示切片开始位置(默认为0)。
- 第二个数字表示切片截止(但不包含)位置(默认为列表长度)。
- 第三个数字表示切片的步长(默认为1),当步长省略时可以顺便省略最后一个冒号。
切片操作不会因为下标越界而抛出异常,而是简单地在列表尾部截断或者返回一个空列表,代码具有更强的健壮性。
>>> aList = [3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
>>> aList[::] #返回包含所有元素的新列表
[3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
>>> aList[::-1] #逆序的所有元素
[17, 15, 13, 11, 9, 7, 6, 5, 4, 3]
>>> aList[::2] #偶数位置,隔一个取一个
[3, 5, 7, 11, 15]
可以使用切片来原地修改列表内容
>>> aList = [3, 5, 7]
>>> aList[len(aList):] = [9] #在尾部追加元素
>>> aList
[3, 5, 7, 9]
>>> aList[:3] = [1, 2, 3] #替换前3个元素
>>> aList
[1, 2, 3, 9]
>>> aList[:3] = [] #删除前3个元素
>>> aList
[9]
>>> aList[::2] = [0]*3 #切片不连续,两侧元素个数必须一样多
Error
使用 del 与切片结合来删除列表元素
>>> aList = [3,5,7,9,11]
>>> del aList[:3] #删除前3个元素
>>> aList
[9, 11]
切片返回的是浅复制。
所谓浅复制,是指生成一个新的列表,并且把原列表中所选元素的引用都复制到新列表中。
如果原列表中只包含整数、实数、复数等基本类型或元组、字符串这样的不可变类型的数据,一般是没有问题的。
如果原列表中包含列表之类的可变数据类型,由于浅复制时只是把子列表的引用复制到新列表中,这样的话修改任何一个都会影响另外一个。
>>> aList = [3, 5, 7]
>>> bList = aList[:] #切片,浅复制
>>> aList == bList #切片刚完成的瞬间,bList和aList中包含同样的元素引用
True
>>> bList[1] = 8 #列表中只包含可哈希对象,修改bList时不影响aList
>>> bList
[3, 8, 7]
>>> aList
[3, 5, 7]
>>> aList = [3, [5], 7] #列表aList中包含可变的列表对象
>>> bList = aList[:] #切片
>>> bList[1].append(6) #调用子列表的append()方法,这个方法是原地操作的
>>> bList
[3, [5, 6], 7]
>>> aList #aList受到影响
[3, [5, 6], 7]
标准库 copy 中的 deepcopy() 函数实现深复制。
所谓深复制,是指对原列表中的元素进行递归,把所有的值都复制到新列表中,对嵌套的子列表不再是复制引用。
新列表和原列表是互相独立,修改任何一个都不会影响另外一个。
>>> aList = [3, [5], 7]
>>> import copy
>>> bList = copy.deepcopy(aList) #深赋值,递归复制,直到遇到可哈希对象
>>> aList == bList #aList和bList完全独立,互相不影响
True
>>> aList is bList
False
>>> bList[1].append(6) #修改bList不会影响aList
>>> bList
[3, [5, 6], 7]
>>> aList
[3, [5], 7]
3.2.5列表推导式
列表推导式使用非常简洁的方式来快速生成满足特定需求的列表,代码具有非常强的可读性。
列表推导式语法形式为:
[expression for expr1 in sequence1 if condition1
for expr2 in sequence2 if condition2
for expr3 in sequence3 if condition3
...
for exprN in sequenceN if conditionN]
列表推导式在内部实际上是一个循环结构,只是形式更加简洁,例如:
aList = [x*x for x in range(10)]
相当于
>>> aList = []
>>> for x in range(10):
aList.append(x*x)
也相当于
>>> aList = list(map(lambda x: x*x, range(10)))
直接求和:sum([2**i for i in range(64)])
使用列表推导式实现嵌套列表的平铺
>>> vec = [[1,2,3], [4,5,6], [7,8,9]]
>>> [num for elem in vec for num in elem]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
相当于
>>> vec = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> result = []
>>> for elem in vec:
for num in elem:
result.append(num)
3.3元组tuple
元组和列表类似,但属于不可变序列,元组一旦创建,用任何方法都不可以修改其元素。
元组的定义方式和列表相同,但定义时所有元素是放在一对圆括号“()”中,而不是方括号中。
元组的速度比列表更快。如果定义了一系列常量值,而所需做的仅是对它进行遍历,那么一般使用元组而不用列表。
元组对不需要改变的数据进行“写保护”将使得代码更加安全。
操作 | |
= | 将一个元组赋值给变量 a_tuple = ('a', 'b', 'mpilgrim', 'z', 'example') a = (3,) #包含一个元素的元组,最后必须多写个逗号 a = 3, #也可以这样创建元组 x = () #空元组 |
tuple() | 将其他序列转换为元组 tuple('abcdefg') s = tuple() #空元组 |
del | 删除整个元组 |
3.3.1 元组可用作字典的“键”,也可以作为集合的元素。列表不能作为字典的“键”,包含列表、字典、集合或其他类型可变对象的 元组 也不能做字典的“键”。
3.3.2 如果元组中包含列表或其他类型的可变对象,这些对象是可变的,但元组元素的引用仍是不可变的。
>>> x = ([1, 2], 3)
>>> x[0][0] = 5
>>> x
([5, 2], 3)
>>> x[0].append(8) #成功修改
>>> x
([5, 2, 8], 3)
>>> x[0] = x[0]+[10] #报错,未起作用
TypeError: 'tuple' object does not support item assignment
>>> x
([5, 2, 8], 3)
>>> x[0] += [10] #报错,但是仍起作用
TypeError: 'tuple' object does not support item assignment
>>> x
([5, 2, 8, 10], 3)
3.3.3 生成器推导式
生成器推导式的结果是一个生成器对象。使用生成器对象的元素时,可以根据需要将其转化为列表或元组,也可以使用生成器对象__next__()方法或内置函数next()进行遍历,或者直接将其作为迭代器对象来使用。
生成器对象具有惰性求值的特点,只在需要时生成新元素,空间占用非常少,尤其适合大数据处理的场合。
不管用哪种方法访问生成器对象,都无法再次访问已访问过的元素。(惰性求值)
使用生成器对象__next__()方法或内置函数next()进行遍历
>>> g = ((i+2)**2 for i in range(10)) #创建生成器对象
>>> g
<generator object <genexpr> at 0x0000000003095200>
>>> tuple(g) #将生成器对象转换为元组
(4, 9, 16, 25, 36, 49, 64, 81, 100, 121)
>>> list(g) #生成器对象已遍历结束,没有元素了
[]
>>> g = ((i+2)**2 for i in range(10)) #重新创建生成器对象
>>> g.__next__() #使用生成器对象的__next__()方法获取元素
4
>>> g.__next__() #获取下一个元素
9
>>> next(g) #使用函数next()获取生成器对象中的元素
16
使用for循环直接迭代生成器对象中的元素
>>> g = ((i+2)**2 for i in range(10))
>>> for item in g: #使用循环直接遍历生成器对象中的元素
print(item, end=' ')
3.4字典dict
- 字典是无序、可变序列。
- 定义字典时,每个元素的键和值用冒号分隔,元素之间用逗号分隔,所有的元素放在一对大括号“{}”中。
- 字典中的键可以为任意不可变数据,比如整数、实数、复数、字符串、元组等等。
- 以键作为下标可以读取字典元素,若键不存在则抛出异常
操作 | |
= | 将一个字典赋值给一个变量 a_dict = {'server': 'db.diveintopython3', 'database': 'mysql'} x = {} #空字典 下标访问元素,用 = 时,若键存在,则可以修改该键的值;若不存在,则表示添加一个键、值对。 aDict['age'] = 38 #age存在,修改元素值 aDict['address'] = 'SDIBT' #address不存在,增加新元素,并赋值 |
dict() | 利用已有数据创建字典 keys = ['a', 'b', 'c', 'd'] values = [1, 2, 3, 4] dictionary = dict(zip(keys, values)) x = dict() #空字典 使用dict根据给定的键、值创建字典 d = dict(name='Dong', age=37) 以给定内容为键,创建值为空的字典 adict = dict.fromkeys(['name', 'age', 'sex'] #值为None |
get() | 获取指定键对应的值,并且可以在键不存在的时候返回指定值。 >>> print(aDict.get('address')) None >>> print(aDict.get('address', 'SDIBT')) SDIB |
update() | 将另一个字典的键、值对添加到当前字典对象。 aDict.update({'a':'a','b':'b'}) |
globals() | 返回包含当前作用域内所有全局变量和值的字典。 |
locals() | 返回包含当前作用域内所有局部变量和值的字典。 |
items() | 返回字典的元素 for item in aDict.items(): #输出字典中所有元素 print(item) |
keys() | 返回字典的“键” for key in aDict: #不加特殊说明,默认输出“键” print(key) |
values() | 返回字典的“值” for key in aDict.values(): #输出字典中所有值 print(key) |
del | 删除整个字典,或删除字典中指定键的元素 |
clear() | 删除字典中所有元素 |
pop() | 删除并返回指定键的元素 |
popitem() | 删除并返回字典中的一个元素 |
3.5集合set
集合是无序、可变序列,使用一对大括号界定,元素不可重复,同一个集合中每个元素都是唯一的。
集合中只能包含数字、字符串、元组等不可变类型(或者说可哈希)的数据,而不能包含列表、字典、集合等可变类型的数据。
集合内会自动去除重复并按一定规则排序
操作 | |
= | 直接将集合赋值给变量 a = {3, 5} |
|、&、-、^ | 分布对应:并集、交集、差集、对称差集(相同元素去除,其余合并) |
set() | 将其他类型数据转换为集合 a_set = set(range(8,14)) c_set = set() #空集合 使用dict根据给定的键、值创建字典 d = dict(name='Dong', age=37) 以给定内容为键,创建值为空的字典 adict = dict.fromkeys(['name', 'age', 'sex'] #值为None |
del | 删除整个集合 |
clear() | 清空集合 |
pop() | 弹出并删除其中一个元素 |
remove() | 直接删除指定元素 |
3.6进阶序列(此处不做详细介绍)
堆 import heapq
队列 import queue
栈 import Stack
链表,二叉树,有向图
4.选择与循环
4.1条件表达式
几乎所有的Python合法表达式都可以作为条件表达式.
算术运算符:+、-、*、/、//、%、**
关系运算符:>、<、==、<=、>=、!=,可以连续使用,惰性求值
逻辑运算符:and和or。具有惰性求值特点,只计算必须计算的表达式。
在选择和循环结构中,条件表达式的值只要不是False、0(或0.0、0j等)、空值None、空列表、空元组、空集合、空字典、空字符串、空range对象或其他空迭代对象,Python解释器均认为与True等价。
在Python中,条件表达式中不允许使用赋值运算符“=”
4.2条件判断
基本语法:
if 表达式:
语句块1
elif:
语句块2
else:
语句块3
表达式用法:
value1 if condition else value2
补充:跳转表构建
- 使用列表、元组或字典可以很容易构建跳转表,在某些场合下可以更快速地实现类似于多分支选择结构的功能。
funcDict = {'1':lambda:print('You input 1'),
'2':lambda:print('You input 2'),
'3':lambda:print('You input 3')}
x = input('Input an integer to call different function:')
func = funcDict.get(x, None)
if func:
func()
else:
print('Wrong integer.')
4.3循环
为了优化程序以获得更高的效率和运行速度,在编写循环语句时,应尽量减少循环内部不必要的计算,将与循环变量无关的代码尽可能地提取到循环之外。对于使用多重循环嵌套的情况,应尽量减少内层循环中不必要的计算,尽可能地向外提。
4.3.1基本循环
while循环
while :
循环体
[else: # 如果循环是因为break结束的,就不执行else中的代码
else子句代码块]
for循环
for 取值 in 序列或迭代对象:
循环体
[else:
else子句代码块]
4.3.2break语句和continue语句
break语句在while循环和for循环中都可以使用,一般放在if选择结构中,一旦break语句被执行,将使得整个循环提前结束。
continue语句的作用是终止当前循环,并忽略continue之后的语句,然后回到循环的顶端,提前进入下一次循环。
5.字符串
5.1基础知识
最早的字符串编码是美国标准信息交换码ASCII,仅对10个数字、26个大写英文字母、26个小写英文字母及一些其他符号进行了编码。ASCII码采用1个字节来对字符进行编码,最多只能表示256个符号。
不同的应用领域和场合对字符串编码的要求有不同,于是又分别设计了多种不同的编码格式,常见的主要有UTF-8、UTF-16、UTF-32、GB2312、GBK、CP936等。
GB2312是我国制定的中文编码,使用1个字节表示英语,2个字节表示中文;GBK是GB2312的扩充,而CP936是微软在GBK基础上开发的编码方式。GB2312、GBK和CP936都是使用2个字节表示中文。
UTF-8对全世界所有国家需要用到的字符进行了编码,以1个字节表示英语字符(兼容ASCII),以3个字节表示常见汉字,还有些语言的符号使用2个字节(例如俄语和希腊语符号)或者4个字节。
不同编码格式之间相差很大,采用不同的编码格式意味着不同的表示和存储形式,把同一字符存入文件时,写入的内容可能会不同,在试图理解其内容时必须了解编码规则并进行正确的解码。如果解码方法不正确就无法还原信息,从这个角度来讲,字符串编码也具有加密的效果。
在Python中,字符串属于不可变对象,不支持原地修改,如果需要修改其中的值,只能重新创建一个新的字符串对象。然而,如果确实需要一个支持原地修改的unicode数据对象,可以使用io.StringIO对象或array模块。
5.2字符串格式化
% | [-] | [+] | [指定字符] | [m] | [.n] | 格式字符 | % | x |
格式标志,表示格式开始 | 指定左对齐输出 | 对正数加加号 | 指定空位填 指定字符 | 指定最小宽度 | 指定精度 | 指定类型 | 指定类型 | 待转换的表达式 |
格式字符 | 说明 |
%s | 字符串 (采用str()的显示) |
%r | 字符串 (采用repr()的显示) |
%c | 单个字符 |
%d | 十进制整数 |
%i | 十进制整数 |
%o | 八进制整数 |
%x | 十六进制整数 |
%e | 指数 (基底写为e) |
%E | 指数 (基底写为E) |
%f、%F | 浮点数 |
%g | 指数(e)或浮点数 (根据显示长度) |
%G | 指数(E)或浮点数 (根据显示长度) |
%% | 一个字符% |
>>> x = 1235
>>> "%o" % x
"2323"
>>> "%x" % x
"4d3"
>>> "%e" % x
"1.235000e+03"
>>> "%s" % 65
"65"
>>> "%s" % 65333
"65333"
>>> '%s'%[1, 2, 3] #直接把对象转换成字符串
'[1, 2, 3]'
使用 format() 方法进行格式化
>>> print("The number {0:,} in hex is: {0:#x}, the number {1} in oct is {1:#o}".format(5555,55))
The number 5,555 in hex is: 0x15b3, the number 55 in oct is 0o67
>>> print("The number {1:,} in hex is: {1:#x}, the number {0} in oct is {0:o}".format(5555,55))
The number 55 in hex is: 0x37, the number 5555 in oct is 12663
>>> print("my name is {name}, my age is {age}, and my QQ is {qq}".format(name="Dong Fuguo",age=40,qq="30646****"))
my name is Dong Fuguo, my age is 40, and my QQ is 30646****
>>> position = (5, 8, 13)
>>> print("X:{0[0]};Y:{0[1]};Z:{0[2]}".format(position))
X:5;Y:8;Z:13
>>> '{0:<8d},{0:^8d},{0:>8d}'.format(65) #设置对齐方式
'65 , 65 , 65
>>> '{0:+<8d},{0:-^8d},{0:=>8d}'.format(65)
'65++++++,---65---,======65'
从Python 3.6.x开始支持一种新的字符串格式化方式,官方叫做Formatted String Literals,在字符串前加字母f,含义与字符串对象format()方法类似。
>>> width = 8
>>> height = 6
>>> print(f'Rectangle of {width}*{height}\nArea:{width*height}')
Rectangle of 8*6
Area:48
5.3字符串常用方法
方法 | 说明 |
find() 和 rfind() find("字串",起点,终点) | 分别用来查找一个字符串在另一个字符串指定范围(默认是整个字符串)中首次和最后一次出现的位置,如果不存在则返回-1; |
index() 和 rindex() | 用来返回一个字符串在另一个字符串指定范围中首次和最后一次出现的位置,如果不存在则抛出异常; |
count() | 用来返回一个字符串在当前字符串中出现的次数。 |
split()和rsplit() split(分割符,最大切割次数) | 用来以指定字符为分隔符,把当前字符串从左往右或从右往左分隔成多个字符串,并返回包含分隔结果的列表; 不指定分隔符,则字符串中的任何空白符号(空格、换行符、制表符等)都将被认为是分隔符,并删除切分结果中的空字符串。 明确分隔符时,会保留切分得到的空字符串。 |
partition()和rpartition() | 以指定字符串为分隔符将原字符串分隔为3部分,即分隔符前的字符串、分隔符字符串、分隔符后的字符串,如果指定的分隔符不在原字符串中,则返回原字符串和两个空字符串。 |
join() | 字符串连接 (不推荐使用+运算符连接字符串,优先使用join()方法。) >>> ','.join(li) #列表处理 'apple,peach,banana,pear' |
concat() | 将字符串重复指定次数,并使用指定的分隔符进行连接,结果字符串最后不带分隔符。 concat('good', 5, ',')的返回结果为'good,good,good,good,good' |
lower(), upper() | 返回小/大写字符串 |
capitalize() | 字符串首字符大写 |
title() | 每个单词的首字母大写 |
swapcase() | 大小写互换 |
replace() | 查找替换,找到相应字符串后替换 |
maketrans(),translate() | 字符串对象的 maketrans() 方法用来生成字符映射表,而 translate() 方法用来根据映射表中定义的对应关系转换字符串并替换其中的字符,使用这两个方法的组合可以同时处理多个字符。 #创建映射表,将字符"abcdef123"一一对应地转换为"uvwxyz@#$" >>> table = ''.maketrans('abcdef123', 'uvwxyz@#$') >>> s = "Python is a great programming language. I like it!" >>> s.translate(table) #按映射表进行替换 'Python is u gryut progrumming lunguugy. I liky it‘ |
strip("字符") | 不填入字符则删除空白字符(空格、换行符、制表符等) 填入字符则删除两侧的指定字符(字符可以填入多个,每一个符合的字符都会被删掉,而不是删除对应字符串) |
rstrip("") | 只删除字符串右端出现的指定字符 |
lstrip("") | 只删除字符串左端出现的指定字符 |
eval() | 内置函数,计算括号内表达式的值并作为字符串加入字符串中 eval("3+4") #计算表达式的值 eval('a+b') #要求变量a和b已存在 |
关键字in | 成员判断,测试一个字符中是否存在于另一个字符串中 |
字符串与整数的乘法 | 表示序列重复,也就是字符串内容的重复,得到新字符串。 |
startswith(),endswith() | 判断字符串是否以指定字符串开始或结束,可以添加检测范围 |
center()、ljust()、rjust() | 返回指定宽度的新字符串,原字符串居中、左对齐或右对齐出现在新字符串中,如果指定宽度大于字符串长度,则使用指定的字符(默认为空格)进行填充。 >>> 'Hello world!'.center(20) #居中对齐,以空格进行填充 ' Hello world! ' >>> 'Hello world!'.center(20, '=') #居中对齐,以字符=进行填充 '====Hello world!====' >>> 'Hello world!'.ljust(20, '=') #左对齐 'Hello world!========' >>> 'Hello world!'.rjust(20, '=') #右对齐 '========Hello world!' |
isalnum()、isalpha()、isdigit()、isdecimal()、isnumeric()、isspace()、isupper()、islower() | 用来测试字符串是否为数字或字母、是否为字母、是否为数字字符(isnumeric支持汉字,罗马数字)、是否为空白字符、是否为大写字母以及是否为小写字母。 |
切片[ : : ] | 切片也适用于字符串,但仅限于读取其中的元素,不支持字符串修改。 |
Python标准库string中定义数字字符、标点符号、英文字母、大写字母、小写字母等常量。
>>> import string
>>> string.digits
'0123456789'
>>> string.punctuation
'!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
>>> string.ascii_letters
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> string.ascii_lowercase
'abcdefghijklmnopqrstuvwxyz'
>>> string.ascii_uppercase
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
6.正则表达式
正则表达式使用某种预定义的模式去匹配一类具有共同特征的字符串,主要用于处理字符串,可以快速、准确地完成复杂的查找、替换等处理要求,在文本编辑与处理、网页爬虫之类的场合中有重要应用。
Python中,re模块提供了正则表达式操作所需要的功能。需要import re
元字符 | 功能说明 |
. | 匹配除换行符以外的任意单个字符 |
* | 匹配位于*之前的字符或子模式的0次或多次出现 |
+ | 匹配位于+之前的字符或子模式的1次或多次出现 |
- | 在[]之内用来表示范围 |
| | 匹配位于|之前或之后的字符 |
^ | 匹配行首,匹配以^后面的字符开头的字符串 |
$ | 匹配行尾,匹配以$之前的字符结束的字符串 |
? | 匹配位于?之前的0个或1个字符。当此字符紧随任何其他限定符(*、+、?、{n}、{n,}、{n,m})之后时,匹配模式是“非贪心的”。“非贪心的”模式匹配搜索到的、尽可能短的字符串,而默认的“贪心的”模式匹配搜索到的、尽可能长的字符串。例如,在字符串“oooo”中,“o+?”只匹配单个“o”,而“o+”匹配所有“o” |
\ | 表示位于\之后的为转义字符 |
\num | 此处的num是一个正整数,表示子模式编号。 例如,“(.)\1”匹配两个连续的相同字符 |
\f | 换页符匹配 |
\n | 换行符匹配 |
\r | 匹配一个回车符 |
\b | 匹配单词头或单词尾 |
\B | 与\b含义相反 |
\d | 匹配任何数字,相当于[0-9] |
\D | 与\d含义相反,等效于[^0-9] |
\s | 匹配任何空白字符,包括空格、制表符、换页符,与 [ \f\n\r\t\v] 等效 |
\S | 与\s含义相反 |
\w | 匹配任何字母、数字以及下划线,相当于[a-zA-Z0-9_] |
\W | 与\w含义相反\w含义相反,与“[^A-Za-z0-9_]”等效 |
() | 表示一个子模式,将位于()内的内容作为一个整体来对待。 |
{m,n} | {}前的字符或子模式重复至少m次,至多n次 |
[] | 表示范围,匹配位于[]中的任意一个字符 |
[^xyz] | 反向字符集,匹配除x、y、z之外的任何字符 |
[a-z] | 字符范围,匹配指定范围内的任何字符 |
[^a-z] | 反向范围字符,匹配除小写英文字母之外的任何字符 |
子模式扩展语法:
- (?P<groupname>):为子模式命名
- (?iLmsux):设置匹配标志,可以是几个字母的组合,每个字母含义与编译标志相同
- (?:...):匹配但不捕获该匹配的子表达式
- (?P=groupname):表示在此之前的命名为groupname的子模式
- (?#...):表示注释
- (?=…):用于正则表达式之后,表示如果=后的内容在字符串中出现则匹配,但不返回=之后的内容
- (?!...):用于正则表达式之后,表示如果!后的内容在字符串中不出现则匹配,但不返回!之后的内容
- (?<=…):用于正则表达式之前,与(?=…)含义相同
- (?<!...):用于正则表达式之前,与(?!...)含义相同
举例说明:
最简单的正则表达式是普通字符串,可以匹配自身
'[pjc]ython'可以匹配'python'、'jython'、'cython'
'[a-zA-Z0-9]'可以匹配一个任意大小写字母或数字
'[^abc]'可以一个匹配任意除'a'、'b'、'c'之外的字符
'python|perl'或'p(ython|erl)'都可以匹配'python'或'perl'
子模式后面加上问号表示可选。
r'(http://)?(www\.)?python\'
只能匹配'http://www.python'、'http://python'、'www.python'和'python'
'^http'只能匹配所有以'http'开头的字符串
(pattern)*:允许模式重复0次或多次
(pattern)+:允许模式重复1次或多次
(pattern){m,n}:允许模式重复m~n次
'(a|b)*c':匹配多个(包含0个)a或b,后面紧跟一个字母c。
'ab{1,}':等价于'ab+',匹配以字母a开头后面带1个至多个字母b的字符串。
'^[a-zA-Z]{1}([a-zA-Z0-9._]){4,19}$':匹配长度为5-20的字符串,必须以字母开头并且可带字母、数字、“_”、“.”的字符串。
'^(\w){6,20}$':匹配长度为6-20的字符串,可以包含字母、数字、下划线。
'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$':检查给定字符串是否为合法IP地址。
r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$':检查给定字符串是否为手机号码。
'^[a-zA-Z]+$':检查给定字符串是否只包含英文字母大小写。
'^\w+@(\w+\.)+\w+$':检查给定字符串是否为合法电子邮件地址。
r'(\w)(?!.*\1)':查找字符串中每个字符的最后一次出现。
r'(\w)(?=.*\1)':查找字符串中所有重复出现的字符。
'^(\-)?\d+(\.\d{1,2})?$':检查给定字符串是否为最多带有2位小数的正数或负数。
'[\u4e00-\u9fa5]':匹配给定字符串中所有汉字。
'^\d{18}|\d{15}$':检查给定字符串是否为合法身份证格式。
'\d{4}-\d{1,2}-\d{1,2}':匹配指定格式的日期,例如2016-1-31。
'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[,._]).{8,}$':检查给定字符串是否为强密码,必须同时包含英语字母大写字母、英文小写字母、数字或特殊符号(如英文逗号、英文句号、下划线),并且长度必须至少8位。
"(?!.*[\'\"\/;=%?]).+":如果给定字符串中包含'、"、/、;、=、%、?则匹配失败。
'(.)\\1+':匹配任意字符的两次或多次重复出现。
'((?P<f>\b\w+\b)\s+(?P=f))':匹配连续出现两次的单词。
'((?P<f>.)(?P=f)(?P<g>.)(?P=g))':匹配AABB形式的成语或字母组合。
r"/d+(?=[a-z]+)":匹配连续的数字并且最后一个数字跟着小写字母。
r"/d+(?![a-z]+)":匹配连续的数字,并且最后一个数字后面不能跟小写字母。
r"(?<=[a-z])\d+":匹配连续的数字,并且第一个数字的前面是小写字母。
r"(?<![a-z])\d+":连续的数字,并且第一个数字的前面不能小写字母。
r'\d{3}(?!\d)':匹配三位数字,而且这三位数字的后面不能是数字。
r'\b((?!abc)\w)+\b':匹配不包含连续字符串abc的单词。
r'(?<![a-z])\d{7}':匹配前面不是小写字母的七位数字。
r"(?<=<(\w{4})>)(.*)(?=<\/\1>)":匹配"<span> hello world </span>"中的span和hello world。
方法 | 功能说明 |
compile(pattern[, flags]) | 创建正则表达式对象。 使用编译后的正则表达式对象可以提高字符串处理速度,也提供了更强大的文本处理功能。 |
escape(string) | 将字符串中所有特殊正则表达式字符转义 |
findall(pattern, string[, flags]) | 返回包含字符串中所有与给定模式匹配的项的列表 |
finditer(pattern, string, flags=0) | 返回包含所有匹配项的迭代对象,其中每个匹配项都是Match对象 |
fullmatch(pattern, string, flags=0) | 尝试把模式作用于整个字符串,返回Match对象或None |
match(pattern, string[, flags]) | 从字符串的开始处匹配模式,返回Match对象或None,模式必须出现在字符串开头或指定位置 |
purge() | 清空正则表达式缓存 |
search(pattern, string[, flags]) | 在整个字符串中寻找模式,返回Match对象或None |
split(pattern, string[, maxsplit=0]) | 根据模式匹配项分隔字符串 |
sub(pat, repl, string[, count=0]) | 将字符串中所有与pat匹配的项用repl替换,返回新字符串,实现字符串替换功能,repl可以是字符串或返回字符串的可调用对象,作用于每个匹配的Match对象 |
subn(pat, repl, string[, count=0]) | 将字符串中所有pat的匹配项用repl替换,返回包含新字符串和替换次数的二元元组, repl可以是字符串或返回字符串的可调用对象, 作用于每个匹配的Match对象 |
正则表达式对象的match方法和search方法匹配成功后返回Match对象。Match对象的主要方法有:
- group():返回匹配的一个或多个子模式内容
- groups():返回一个包含匹配的所有子模式内容的元组
- groupdict():返回包含匹配的所有命名子模式内容的字典
- start():返回指定子模式内容的起始位置
- end():返回指定子模式内容的结束位置的前一个位置
- span():返回一个包含指定子模式内容起始位置和结束位置前一个位置(下标)的元组。
flag参数常用值 | 含义 |
re.A | 使得正则表达式中\w、\W、\b、\B、\d、\D、\s和\S等元字符只匹配ASCII字符,不匹配Unicode字符。 >>> re.findall('\d+', '1231234') ['1231234'] >>> re.findall('\d+', '1231234', re.A) ['123'] >>> re.findall('\w+', '1a2b3c1d2e3g4', re.A) ['1a2b3c', 'd', 'e', 'g'] >>> re.findall('\w+', '1a2b3c1d2e3g4') ['1a2b3c1d2e3g4'] |
re.I | 忽略大小写。 >>> re.findall('[a-z0-9]+', '1a2b3c1D2e3G4') ['1a2b3c', 'e'] >>> re.findall('[a-z0-9]+', '1a2b3c1D2e3G4', re.I) ['1a2b3c', 'D', 'e', 'G'] >>> re.findall('[a-z0-90-9]+', '1a2b3c1D2e3G4', re.I) ['1a2b3c1D2e3G4'] >>> re.findall('[a-z0-90-9]+', '1a2b3c1D2e3G4') ['1a2b3c1', '2e3', '4'] |
re.M | 多行模式,^可以匹配每行开始,$可以匹配每行结束。默认情况下分别匹配字符串的开始和结束。 >>> text = ''' abc1234 1234 abc Python ''' >>> re.findall(r'^\w+$', text) [] >>> re.findall(r'^.+$', text) [] >>> re.findall(r'^\w+$', text, re.M) ['abc1234', '1234', 'abc', 'Python'] >>> re.findall(r'^.+$', text, re.M) ['abc1234', '1234', 'abc', 'Python'] |
re.S | 单行模式,圆点可以匹配换行符。 >>> text = '''<p>Beautiful is better than ugly. Explicit is better than implicit. Simple is better than complex.</p>''' >>> re.findall(r'<p>(.+?)</p>', text) [] >>> re.findall(r'<p>(.+?)</p>', text, re.S) ['Beautiful is better than ugly.\nExplicit is better than implicit.\nSimple is better than complex.'] |
re.X | 允许正则表达式换行,并忽略其中的空白字符和#注释。 >>> text = 'abc123.4dfg8.88888hij9999.9' >>> pattern = r'''\d+ # 数字 \. # 圆点 \d +''' >>> re.findall(pattern, text) [] >>> re.findall(pattern, text, re.X) ['123.4', '8.88888', '9999.9'] |
多个flag可以使用+组合使用。 |
7.函数的设计和使用
7.1函数定义
将可能需要反复执行的代码封装为函数,并在需要该功能的地方进行调用,不仅可以实现代码复用,更重要的是可以保证代码的一致性,只需要修改该函数代码则所有调用均受到影响。
设计函数时,应注意提高模块的内聚性,同时降低模块之间的隐式耦合。
在实际项目开发中,往往会把一些通用的函数封装到一个模块中,并把这个通用模块文件放到顶层文件夹中,这样更方便管理。
在编写函数时,应尽量减少副作用,尽量不要修改参数本身,不要修改除返回值以外的其他内容。
不要在一个函数中执行太多的功能,尽量只让一个函数完成一个高度相关且大小合适的任务,一个函数的代码尽量能在一个屏幕内完整显示。
尽量减少不同函数之间的隐式耦合,减少全局变量的使用,使得函数之间仅通过调用和参数传递来显式体现其相互关系。
应充分利用Python函数式编程的特点,让自己定义的函数尽量符合纯函数式编程的要求,例如保证线程安全、可以并行运行等等。
函数定义语法:
def 函数名([参数列表]):
'''注释'''
函数体
.
形参和实参:
- 函数定义时括弧内为形参,一个函数可以没有形参,但是括弧必须要有,表示该函数不接受参数。
- 函数调用时,将实参的引用传递给形参。对于绝大多数情况下,在函数内部直接修改形参的值不会影响实参,而是创建一个新变量。在有些情况下,可以通过特殊的方式在函数内部修改实参的值(如果传递给函数的实参是可变序列,并且在函数内部使用下标或可变序列自身的原地操作方法增加、删除元素或修改元素时,实参也得到相应的修改)。
- 在定义函数时,对参数个数并没有限制,如果有多个形参,需要使用逗号进行分隔。
参数类型:
- 在Python中,函数参数可以为普通参数、默认值参数、关键参数、可变长度参数等等..。
- Python在定义函数时不需要指定形参的类型,完全由调用者传递的实参类型以及Python解释器的理解和推断来决定。
- 位置参数(positional arguments)是比较常用的形式,调用函数时实参和形参的顺序和数量必须严格一致。
- 调用带有默认值参数的函数时,可以不对默认值参数进行赋值,也可以为其赋值,具有很大的灵活性。(注意:默认值参数必须出现在函数参数列表的最右端)
注意事项:
- 函数形参不需要声明类型,也不需要指定函数返回值类型
- 即使该函数不需要接收任何参数,也必须保留一对空的圆括号
- 括号后面的冒号必不可少
- 函数体相对于def关键字必须保持一定的空格缩进
- Python允许嵌套定义函数
- 默认值参数的赋值只会在函数定义时被解释一次。当使用可变序列作为参数默认值时,一定要谨慎操作。
Python中的函数和自定义对象的成员也是可以随时发生改变的,可以为函数和自定义对象动态增加新成员。
>>> def func():
print(func.x) #查看函数func的成员x
>>> func.x = 3 #动态为函数增加新成员
>>> func()
3
>>> func.x #在外部也可以直接访问函数的成员
3
函数的递归调用是函数调用的一种特殊情况,函数调用自己,自己再调用自己,自己再调用自己,...,当某个条件得到满足的时候就不再调用了,然后再一层一层地返回直到该函数第一次调用的位置。
通过关键参数,实参顺序可以和形参顺序不一致,但不影响传递结果,避免了用户需要牢记位置参数顺序的麻烦。
>>> def demo(a,b,c=5):
print(a,b,c)
>>> demo(3,7)
3 7 5
>>> demo(a=7,b=3,c=6)
7 3 6
>>> demo(c=8,a=9,b=0)
9 0 8
可变长度参数主要有两种形式:在参数名前加1个星号*或2个星号**。
- *parameter用来接收多个位置实参并将其放在元组中。
>>> def demo(*p):
print(p)
>>> demo(1,2,3)
(1, 2, 3)
- **parameter接收多个关键参数并存放到字典中。
>>> def demo(**p):
for item in p.items():
print(item)
>>> demo(x=1,y=2,z=3)
('x', 1)
('y', 2)
('z', 3)
- 几种不同类型的参数可以混合使用,但是不建议这样做。
>>> def func_4(a, b, c=4, *aa, **bb):
print(a,b,c)
print(aa)
print(bb)
>>> func_4(1,2,3,4,5,6,7,8,9,xx='1',yy='2',zz=3)
1 2 3
(4, 5, 6, 7, 8, 9)
{'xx': '1', 'yy': '2', 'zz': 3}
>>> func_4(1,2,3,4,5,6,7,xx='1',y
- 传递参数时,可以通过在实参序列前加一个星号将其解包,然后传递给多个单变量形参。
>>> def demo(a, b, c):
print(a+b+c)
>>> seq = [1, 2, 3]
>>> demo(*seq)
6
- 如果函数实参是字典,可以在前面加两个星号进行解包,等价于关键参数。
>>> def demo(a, b, c):
print(a+b+c)
>>> dic = {'a':1, 'b':2, 'c':3}
>>> demo(**dic)
6
>>> demo(*dic.values())
6
- 注意:调用函数时对实参序列使用一个星号*进行解包后的实参将会被当做普通位置参数对待,并且会在关键参数和使用两个星号**进行序列解包的参数之前进行处理。
7.2变量作用域
- 变量起作用的代码范围称为变量的作用域,不同作用域内变量名可以相同,互不影响。
- 在函数内部定义的普通变量只在函数内部起作用,称为局部变量。当函数执行结束后,局部变量自动删除,不再可以使用。
- 局部变量的引用比全局变量速度快。
- 全局变量会增加函数之间的隐式耦合。
全局变量可以通过关键字global来定义。
这分为两种情况:
- 一个变量已在函数外定义,如果在函数内需要为这个变量赋值,并要将这个赋值结果反映到函数外,可以在函数内使用global将其声明为全局变量。
- 如果一个变量在函数外没有定义,在函数内部也可以直接将一个变量定义为全局变量,该函数执行后,将增加一个新的全局变量。
注意:在某个作用域内任意位置只要有为变量赋值的操作,该变量在这个作用域内就是局部变量,除非使用global进行了声明。如果局部变量与全局变量具有相同的名字,那么该局部变量会在自己的作用域内隐藏同名的全局变量。
7.3Lambda表达式
- lambda表达式可以用来声明匿名函数(也可以定义具名函数),也就是没有函数名字的临时使用的小函数,尤其适合需要一个函数作为另一个函数参数的场合。
- lambda表达式只可以包含一个表达式,该表达式可以任意复杂,其计算结果可以看作是函数的返回值。
lambda 函数的语法只包含一个语句,表现形式如下:(其中,lambda 是 Python 预留的关键字)
lambda 参数: 表达式
>>> f = lambda x, y, z: x+y+z #可以给lambda表达式起名字
>>> f(1,2,3) #像函数一样调用
6
>>> L = [(lambda x: x**2), #匿名函数
(lambda x: x**3),
(lambda x: x**4)]
>>> print(L[0](2),L[1](2),L[2](2)) #调用lambda表达式
4 8 16
>>> D = {'f1':(lambda:2+3), 'f2':(lambda:2*3), 'f3':(lambda:2**3)}
>>> print(D['f1'](), D['f2'](), D['f3']())
5 6 8
>>> L = [1,2,3,4,5]
>>> print(list(map(lambda x: x+10, L))) #lambda表达式作为函数参数
[11, 12, 13, 14, 15]
7.4高级补充
map()
内置函数map()可以将一个函数作用到一个或多个序列或迭代器对象上,返回可迭代的map对象。
>>> list(map(str,range(5)))
['0', '1', '2', '3', '4']
>>> def add5(v):
return v+5
>>> list(map(add5,range(10)))
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
reduce()
标准库functools中的reduce()函数可以将一个接受2个参数的函数以迭代的方式从左到右依次作用到一个序列或迭代器对象的所有元素上,并且允许指定一个初始值。
reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])
计算过程为((((1+2)+3)+4)+5)
→第一次计算时x为1而y为2
→再次计算时x的值为(1+2)而y的值为3
→再次计算时x的值为((1+2)+3)而y的值为4
以此类推,最终完成计算并返回((((1+2)+3)+4)+5)的值。
filter()
内置函数filter将一个函数作用到一个序列上,返回该序列中使得该函数返回值为True的那些元素组成的filter对象。
>>> seq=['foo','x41','?!','***']
>>> def func(x):
return x.isalnum()
>>> list(filter(func,seq))
['foo', 'x41']
>>> seq
['foo', 'x41', '?!', '***']
>>> [x for x in seq if x.isalnum()]
['foo', 'x41']
>>> list(filter(lambda x:x.isalnum(),seq))
['foo', 'x41']
生成器函数
生成器是Python中的一个对象,对这个对象进行操作,可以依次生产出按生成器内部运算产生的数据。但是要注意,如果不对生成器进行操作,是不会产生数据的。称这样的方式为惰性求值,延或者迟求值,适合大数据处理。
包含yield语句的函数可以用来创建生成器对象,这样的函数也称生成器函数。这个 yield 可以类比 return,遇到之后就返回后面的值,但是yield会记住当时执行到哪里了,下一次执行从这个地方开始(返回一个值然后暂停或挂起后面代码的执行,就是生成器的特点)下次通过生成器对象的__next__()方法、内置函数next()、for循环遍历生成器对象元素或其他方式显式“索要”数据时恢复执行。
斐波那契数列:
>>> def f():
a, b = 1, 1 #序列解包,同时为多个元素赋值
while True:
yield a #暂停执行,需要时再产生一个新元素
a, b = b, a+b #序列解包,继续生成新元素
>>> a = f() #创建生成器对象
>>> for i in range(10): #斐波那契数列中前10个元素
print(a.__next__(), end=' ')
1 1 2 3 5 8 13 21 34 55
>>> for i in f(): #斐波那契数列中第一个大于100的元素
if i > 100:
print(i, end=' ')
break
144
>>> a = f() #创建生成器对象
>>> next(a) #使用内置函数next()获取生成器对象中的元素
1
>>> next(a) #每次索取新元素时,由yield语句生成
1
>>> a.__next__() #也可以调用生成器对象的__next__()方法
2
>>> def f():
yield from 'abcdefg' #使用yield表达式创建生成器
>>> x = f()
>>> next(x)
'a'
>>> next(x)
'b'
>>> for item in x: #输出x中的剩余元素
print(item, end=' ')
c d e f g
>>> def gen():
yield 1
yield 2
yield 3
>>> x, y, z = gen() #生成器对象支持序列解包
字节码指令
什么是py字节码?Python 代码先被编译为字节码后,再由 Python 虚拟机来执行字节码,Python 的字节码是一种类似汇编指令的中间语言,一个 Python 语句会对应若干字节码指令,虚拟机一条一条执行字节码指令,从而完成程序执行。
- 使用dis模块可以查看函数的字节码指令
>>> def add(n):
n += 1
return n
>>> import dis
>>> dis.dis(add)
2 0 LOAD_FAST 0 (n)
3 LOAD_CONST 1 (1)
6 INPLACE_ADD
7 STORE_FAST 0 (n)
3 10 LOAD_FAST 0 (n)
13 RETURN_VALUE
- 反编译Python字节码
可以使用Python扩展库uncompyle6或其他类似模块来完成这个功能。使用pip工具安装uncompyle6之后,使用类似于下面的代码对上面生成的.pyc文件进行反编译得到源代码:
uncompyle6.uncompyle_file('__pycache__\\Stack.cpython-35.opt-1.pyc',
open('__pycache__\\Stack.py', 'w'))
另外,http://tool.lu/pyc/这个网站可以在线上传一个.pyc文件,然后可以得到Python源代码(个别地方可能不是非常准确,需要自己稍作调整),并且还提供了一定的代码美化功能,能够自动处理代码布局和排版规范。
修饰器
- 修饰器(decorator)是函数嵌套定义的另一个重要应用。修饰器本质上也是一个函数,只不过这个函数接收其他函数作为参数并对其进行一定的改造之后返回新函数。
- Python面向对象程序设计中的静态方法、类方法、属性等也都是通过修饰器实现的,Python中还有很多这样的用法。
下面的代码演示了修饰器的定义与使用方法,定义其他函数调用之前或之后需要执行的通用代码,可作用于其他任何函数,提高代码复用度。
def before(func): #定义修饰器
def wrapper(*args, **kwargs):
print('Before function called.')
return func(*args, **kwargs)
return wrapper
def after(func): #定义修饰器
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
print('After function called.')
return result
return wrapper
@before
@after
def test(): #同时使用两个修饰器改造函数
print(3)
test() #调用被修饰的函数
函数柯里化
偏函数(partial function)和函数柯里化(function currying)是函数式编程中常用的技术。
有时候我们在复用已有函数时可能需要固定其中的部分参数,这除了可以通过默认值参数来实现之外,还可以使用偏函数。
例如,有个函数用来实现3个数字相加:
def add3(a, b, c):
return a+b+c
如果现在需要一个类似的函数,与上面的函数add3()的区别仅在于参数b固定为一个数字(例如666),这时就可以使用偏函数的技术来复用上面的函数。
def add2(a, c):
return add3(a, 666, c)
print(add2(1, 1))
或者使用标准库functools提供的partial()方法创建指定函数的偏函数。
from functools import partial
add2 = partial(add3, b=666)
print(add2(a=1, c=1))
函数柯里化除了可以实现偏函数类似的功能之外,还可以利用单参数函数来实现多参数函数,这要归功于Python对函数嵌套定义和lambda表达式的支持。
def func(a):
return lambda b: a+b
print(func(3)(5))
或者
def func(a):
def funcNested(b):
return a+b
return funcNested
print(func(3)(5))
也可以多级嵌套定义函数实现更多参数的需求。
def func(a):
def funcNested(b):
def funcNestedNested(c):
return a+b+c
return funcNestedNested
return funcNested
print(func(3)(5)(8))
8.文件操作
8.1文本操作
- 为了长期保存数据以便重复使用、修改和共享,必须将数据以文件的形式存储到外部存储介质(如磁盘、U盘、光盘或云盘、网盘、快盘等)中。
- 文件操作在各类应用软件的开发中均占有重要的地位:
1. 管理信息系统是使用数据库来存储数据的,而数据库最终还是要以文件的形式存储到硬盘或其他存储介质上。
2. 应用程序的配置信息往往也是使用文件来存储的。
3. 图形、图像、音频、视频、可执行文件等等也都是以文件的形式存储在磁盘上的。
8.1.1分类
按文件中数据的组织形式把文件分为文本文件和二进制文件两类。
文本文件
文本文件存储的是常规字符串,由若干文本行组成,通常每行以换行符'\n'结尾。
常规字符串是指记事本或其他文本编辑器能正常显示、编辑并且人类能够直接阅读和理解的字符串
如英文字母、汉字、数字字符串。文本文件可以使用字处理软件如gedit、记事本进行编辑。
二进制文件
二进制文件把对象内容以字节串(bytes)进行存储,无法用记事本或其他普通字处理软件直接进行编辑,通常也无法被人类直接阅读和理解,需要使用专门的软件进行解码后读取、显示、修改或执行。
常见的如图形图像文件、音视频文件、可执行文件、资源文件、各种数据库文件、各类office文档等都属于二进制文件
8.1.2文本基本操作
文件内容操作三步走:打开、读写、关闭。
具体实现:open() 方法
语法格式:
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
参数说明:
file: 必需,文件路径(相对或者绝对路径)指定被打开的文件名称。。
mode: 可选,文件打开模式,指定了打开文件后的处理方式。
buffering: 指定读写文件的缓存模式。0表示不缓存,1表示缓存,如大于1则表示缓冲区的大小。默认值-1表示由系统管理缓存。
encoding: 指定对文本进行编码和解码的方式,只适用于文本模式。一般使用utf8
errors: 报错级别
newline: 区分换行符
closefd: 传入的file参数类型
opener: 设置自定义开启器,开启器的返回值必须是一个打开的文件描述符。
open() 函数常用形式是接收两个参数:文件名(file)和模式(mode)。
f1 = open('file1.txt', 'r') # 以读模式打开文件
f2 = open('file2.txt', 'w') # 以写模式打开文件
- 如果执行正常,open()函数返回1个文件对象,通过该文件对象可以对文件进行读写操作。
- 如果执行异常,由各种原因原因导致创建文件对象失败,则抛出 OSError。
- 使用 open() 方法一定要保证关闭文件对象,保证修改被存入,即调用 close() 方法。
f1.close()
- 但是,即使写了关闭文件的代码,也无法保证文件一定能够正常关闭。例如,如果在打开文件之后和关闭文件之前发生了错误导致程序崩溃,这时文件就无法正常关闭。
在管理文件对象时推荐使用with关键字,可以有效地避免上诉问题。
语法格式:with open(filename, mode, encoding) as fp: #这里写通过文件对象fp读写文件内容的语句
(例)with open('test.txt', 'r') as src, open('test_new.txt', 'w') as dst:
dst.write(src.read()) #此处是在dst写入src的所有内容.
mode参数具体说明
mode | 描述 |
r | 以只读方式打开文件。文件的指针将会放在文件的开头。默认模式。 |
t | 文本模式 (默认)。 |
w | 打开一个文件只用于写入。文件已存在则清空文件内容,文件不存在则创建新文件。 |
x | 写模式,新建一个文件,如果该文件已存在则会报错。 |
a | 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
b | 二进制模式。 |
+ | 打开一个文件进行更新(可读,可写)。 |
组合 | 描述 |
rb | 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。一般用于非文本文件如图片等。 |
r+ | 打开一个文件用于读写。文件指针将会放在文件的开头。 |
rb+ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。一般用于非文本文件如图片等。 |
wb | 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。 |
w+ | 打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
wb+ | 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。 |
ab | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
a+ | 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。 |
ab+ | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。 |
文件对象常用属性:
属性 | 说明 |
buffer | 返回当前文件的缓冲区对象 |
closed | 判断文件是否关闭,若文件已关闭则返回True |
fileno | 文件号,一般不需要太关心这个数字 |
mode | 返回文件的打开模式 |
name | 返回文件的名称 |
文件对象常用方法:
方法 | 描述 |
file.close() | 把缓冲区的内容写入文件,同时关闭文件,并释放文件对象 |
file.read([size]) | 从文本文件中读取size个字符(Python 3.x)的内容作为结果返回,或从二进制文件中读取指定数量的字节并返回,如果省略size则表示读取所有内容 |
file.readable() | 测试当前文件是否可读 |
file.readline() | 从文本文件中读取一行内容作为结果返回 |
file.readlines() | 把文本文件中的每行文本作为一个字符串存入列表中,返回该列表,对于大文件会占用较多内存,不建议使用 |
file.seek(offset[, whence]) | 把文件指针移动到新的字节位置,offset表示相对于whence的位置。whence为0表示从文件头开始计算,1表示从当前位置开始计算,2表示从文件尾开始计算,默认为0 |
file.write(s) | 把s的内容写入文件 |
file.writable() | 测试当前文件是否可写 |
file.writelines(s) | 把字符串列表写入文本文件,不添加换行符 |
file.tell() | 返回文件当前位置。 |
file.flush() | 刷新文件内部缓冲,直接把内部缓冲区的数据立刻写入文件, 而不是被动的等待输出缓冲区写入。 |
文本操作案例
1.向文本文件中写入内容,然后再读出。
s = 'Hello world\n123\n456\n'
with open('sample.txt', 'w') as fp:
fp.write(s)
with open('sample.txt') as fp:
print(fp.read())
2.读取并显示文本文件的前5个字符。
with open('sample.txt', 'r') as f:
s = f.read(5)
print('s=',s)
print('字符串s的长度(字符个数)=', len(s))
3.读取并显示文本文件所有行。
with open('sample.txt') as fp:
for line in fp: #文件对象可以直接迭代
print(line)
4.移动文件指针,然后读取并显示文本文件中的内容。
seek()方法把文件指针定位到文件中指定字节的位置。读取时遇到无法解码的字符会抛出异常。
>>> s = '中国山东烟台SDIBT'
>>> with open(r'sample.txt', 'w') as fp:
fp.write(s)
>>> fp = open(r'sample.txt', 'r')
>>> print(fp.read(3))
中国山
>>> print(fp.seek(2))
2
>>> print(fp.read(1))
国
>>> fp.seek(13)
13
>>> print(fp.read(1))
D
>>> fp.seek(3)
3
>>> print(fp.read(1))
UnicodeDecodeError: 'gbk' codec can't decode byte 0xfa in position 0: illegal multibyte sequence
5.读取文本文件data.txt(文件中每行存放一个整数)中所有整数,按升序排序后再写入文本文件data_new.txt中。
with open('data.txt') as fp:
data = fp.readlines() #获取由每行字符串组成的数组
data.sort(key = int) #按字符串中的Int升序排序
with open('data_new.txt', 'w') as fp:
fp.writelines(data) #字符串列表写入文件
6.编写程序,保存为demo6.py,运行后生成文件demo6_new.py,其中的内容与demo6.py一致,但是在每行的行尾加上了行号。
filename = 'demo6.py'
with open(filename, 'r') as fp:
lines = fp.readlines()
maxLength = len(max(lines, key=len)) #获取最长那行的长度
#处理字符串,先去掉尾部的换行,然后将字符串设置为与最长字符串对齐
lines = [line.rstrip().ljust(maxLength) + '#' + str(index) + '\n'
for index, line in enumerate(lines)]
with open(filename[:-3]+'_new.py', 'w') as fp:
fp.writelines(lines)
补充:字符串编码格式和字体对中英文混排时对齐的影响。
sentences = ['Readability counts.',
'老龙恼怒闹老农,老农恼怒闹老龙。农怒龙恼农更怒,龙恼农怒龙怕农。',
'人生苦短,我用Python',
'Python程序设计基础(第2版),Python程序设计(第2版),Python可以这样学,'
'Python程序设计开发宝典,玩转Python轻松过二级',
'樱桃,cherry']
longestSentence = max(sentences, key=lambda s:len(s.encode('gbk'))) # 最长一行的内容
maxLength = len(longestSentence.encode('gbk')) # 最长一行的长度
for index, sentence in enumerate(sentences): # 在GBK编码中,一个汉字占2个英文字符宽度
print(sentence+' '*(maxLength-len(sentence.encode('gbk')))+'#{}'.format(index))
7.批量修改文本文件编码格式。
import os
# 获取当前文件夹中所有记事本文件清单
fns = (fn for fn in os.listdir() if fn.endswith('.txt'))
for fn in fns:
try:
# 首先尝试使用UTF8编码打开并读取文件内容
# 如果失败会抛出异常
with open(fn, encoding='utf8') as fp:
fp.read()
except:
# 以默认的GBK编码读取原文件内容
# 以UTF8编码写入新文件
with open(fn) as fp1:
with open('t.txt', 'w', encoding='utf8') as fp2:
fp2.write(fp1.read())
# 删除原文件,把新文件重命名为原文件
os.remove(fn)
os.rename('t.txt', fn)
8.1.3二进制文本文件操作
- 数据库文件、图像文件、可执行文件、音视频文件、Office文档等等均属于二进制文件。
- 对于二进制文件,不能使用记事本或其他文本编辑软件进行正常读写,也无法通过Python的文件对象直接读取和理解二进制文件的内容。
- 必须正确理解二进制文件结构和序列化规则,才能准确地理解二进制文件内容并且设计正确的反序列化规则。
- 所谓序列化,简单地说就是把内存中的数据在不丢失其类型信息的情况下转成对象的二进制形式的过程,对象序列化后的形式经过正确的反序列化过程应该能够准确无误地恢复为原来的对象。
- Python中常用的序列化模块有struct、pickle、marshal和shelve。
序列化模块pickle
写入:
import pickle
i = 13000000
a = 99.056
s = '中国人民123abc'
lst = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
tu = (-5, 10, 8)
coll = {4, 5, 6}
dic = {'a':'apple', 'b':'banana', 'g':'grape', 'o':'orange'}
data = [i, a, s, lst, tu, coll, dic] #前面数据的集合列表
with open('sample_pickle.dat', 'wb') as f:
try:
pickle.dump(len(data), f) #表示后面将要写入的数据个数
for item in data:
pickle.dump(item, f)
except:
print('写文件异常!') #如果写文件异常则跳到此处执行
读取:
import pickle
with open('sample_pickle.dat', 'rb') as f:
n = pickle.load(f) #读出文件的数据个数
for i in range(n):
x = pickle.load(f)
print(x)
序列化模块struct
写入:
import struct
n = 1300000000
x = 96.45
b = True
s = 'a1@中国'
sn = struct.pack('if?', n, x, b) #打包,序列化
with open('sample_struct.dat', 'wb') as fp:
fp.write(sn) #写入字节串
fp.write(s.encode()) #字符串直接编码为字节串写入
读取:
import struct
with open('sample_struct.dat', 'rb') as fp:
sn = fp.read(9)
tu = struct.unpack('if?', sn)
print(tu)
n, x, bl = tu
print('n=', n)
print('x=', x)
print('bl=', bl)
s = fp.read(9).decode()
print('s=', s)
序列化模块shelve
Python标准库shelve也提供了二进制文件操作的功能,可以像字典赋值一样来写入二进制文件,也可以像字典一样读取二进制文件。
写入:
import struct
with open('sample_struct.dat', 'rb') as fp:
sn = fp.read(9)
tu = struct.unpack('if?', sn)
print(tu)
n, x, bl = tu
print('n=', n)
print('x=', x)
print('bl=', bl)
s = fp.read(9).decode()
print('s=', s)
读取:
import shelve
with shelve.open('shelve_test.dat') as fp:
print(fp['zhangsan']) # 读取并显示文件内容
print(fp['zhangsan']['age'])
print(fp['lisi']['qq'])
print(fp['3'])
序列化模块marshal
写入:
import marshal
x1 = 30
x2 = 5.0
x3 = [1, 2, 3]
x4 = (4, 5, 6)
x5 = {'a':1, 'b':2, 'c':3}
x6 = {7, 8, 9}
x = [eval('x'+str(i)) for i in range(1,7)] #把待序列化对象放到列表中
print(x)
with open('test.dat', 'wb') as fp: #创建二进制文件
marshal.dump(len(x), fp) #先写入对象个数
for item in x:
marshal.dump(item,fp)
读取:
import marshal
with open('test.dat', 'rb') as fp:
n = marshal.load(fp) #获取对象个数
for i in range(n):
print(marshal.load(fp)) #反序列化,输出结果
8.2文件操作
8.2.1 OS与OS.Path模块
OS模块常用的文件操作函数 | 功能说明 |
os.access(path, mode) | 测试是否可以按照mode指定的权限访问文件 |
os.chdir(path) | 把path设为当前工作目录 |
os.chmod(path, mode, *, dir_fd=None, follow_symlinks=True) | 改变文件的访问权限 |
os.chflags(path, flags) | 设置路径的标记为数字标记。 |
os.chown(path, uid, gid) | 更改文件所有者 |
os.curdir | 当前文件夹 |
os.environ | 包含系统环境变量和值的字典 |
os.extsep | 当前操作系统所使用的文件扩展名分隔符 |
os.get_exec_path() | 返回可执行文件的搜索路径 |
os.getcwd() | 返回当前工作目录 |
os.listdir(path) | 返回path目录下的文件和目录列表 |
os.open(path, flags, mode=0o777, *, dir_fd=None) | 按照mode指定的权限打开文件,默认权限为可读、可写、可执行 |
os.popen(cmd, mode='r', buffering=-1) | 创建进程,启动外部程序 |
os.remove(path) | 删除指定的文件,要求用户拥有删除文件的权限,并且文件没有只读或其他特殊属性 |
os.rename(src, dst) | 重命名文件或目录,可以实现文件的移动,若目标文件已存在则抛出异常,不能跨越磁盘或分区 |
os.replace(old, new) | 重命名文件或目录,若目标文件已存在则直接覆盖,不能跨越磁盘或分区 |
os.scandir(path='.') | 返回包含指定文件夹中所有DirEntry对象的迭代对象,遍历文件夹时比listdir()更加高效 |
os.sep | 当前操作系统所使用的路径分隔符 |
os.startfile(filepath [, operation]) | 使用关联的应用程序打开指定文件或启动指定应用程序 |
os.stat(path) | 返回文件的所有属性 |
os.system() | 启动外部程序 |
os.truncate(path, length) | 将文件截断,只保留指定长度的内容 |
os.write(fd, data) | 将bytes对象data写入文件fd |
os.remove(path) | 删除指定的文件,要求用户拥有删除文件的权限,并且文件没有只读或其他特殊属性 |
os.rename(src, dst) | 重命名文件或目录,可以实现文件的移动,若目标文件已存在则抛出异常,不能跨越磁盘或分区 |
os.replace(old, new) | 重命名文件或目录,若目标文件已存在则直接覆盖,不能跨越磁盘或分区 |
os.scandir(path='.') | 返回包含指定文件夹中所有DirEntry对象的迭代对象,遍历文件夹时比listdir()更加高效 |
os.path常用的文件操作函数 | 功能说明 |
os.path.abspath(path) | 返回给定路径的绝对路径 |
os.path.basename(path) | 返回指定路径的最后一个组成部分 |
os.pathmonpath(paths) | 返回给定的多个路径的最长公共路径 |
os.pathmonprefix(paths) | 返回给定的多个路径的最长公共前缀 |
os.path.dirname(p) | 返回给定路径的文件夹部分 |
os.path.exists(path) | 判断文件是否存在 |
os.path.getatime(filename) | 返回文件的最后访问时间 |
os.path.getctime(filename) | 返回文件的创建时间 |
os.path.getmtime(filename) | 返回文件的最后修改时间 |
os.path.getsize(filename) | 返回文件的大小 |
os.path.isabs(path) | 判断path是否为绝对路径 |
os.path.isdir(path) | 判断path是否为文件夹 |
os.path.isfile(path) | 判断path是否为文件 |
os.path.join(path, *paths) | 连接两个或多个path |
os.path.realpath(path) | 返回给定路径的绝对路径 |
os.path.relpath(path) | 返回给定路径的相对路径,不能跨越磁盘驱动器或分区 |
os.path.samefile(f1, f2) | 测试f1和f2这两个路径是否引用的同一个文件 |
os.path.split(path) | 以路径中的最后一个斜线为分隔符把路径分隔成两部分,以元组形式返回 |
os.path.splitext(path) | 从路径中分隔文件的扩展名 |
os.path.splitdrive(path) | 从路径中分隔驱动器的名称 |
1. 列出当前目录下所有扩展名为pyc的文件:
import os
print([fname
for fname in os.listdir(os.getcwd())
if os.path.isfile(fname) and fname.endswith('.txt')])
#返回path目录下的文件和目录列表
#返回当前工作目录
#判断path是否为文件
['data.txt', 'data_new.txt', 'sample.txt']
2.将当前目录中所有扩展名为html的文件重命名为htm的文件:
import os
file_list = [filename
for filename in os.listdir(".")
if filename.endswith('.html')]
for filename in file_list:
newname = filename[:-4]+'htm'
os.rename(filename, newname)
print(filename+"更名为:"+newname)
8.2.2 shutil模块
shutil模块常用的文件操作函数 | 功能说明 |
shutil.copy(src, dst) | 复制文件,新文件具有同样的文件属性,如果目标文件已存在则抛出异常 |
shutil.copy2(src, dst) | 复制文件,新文件具有原文件完全一样的属性,包括创建时间、修改时间和最后访问时间等等,如果目标文件已存在则抛出异常 |
shutil.copyfile(src, dst) | 复制文件,不复制文件属性,如果目标文件已存在则直接覆盖 |
shutil.copyfileobj(fsrc, fdst) | 在两个文件对象之间复制数据,例如copyfileobj(open('123.txt'), open('456.txt', 'a')) |
shutil.copymode(src, dst) | 把src的模式位(mode bit)复制到dst上,之后二者具有相同的模式 |
shutil.copystat(src, dst) | 把src的模式位、访问时间等所有状态都复制到dst上 |
shutil.copytree(src, dst) | 递归复制文件夹 |
shutil.disk_usage(path) | 查看磁盘使用情况 |
shutil.move(src, dst) | 移动文件或递归移动文件夹,也可以给文件和文件夹重命名 |
shutil.rmtree(path) | 递归删除文件夹 |
shutil.make_archive(base_name, format, root_dir=None, base_dir=None) | 创建tar或zip格式的压缩文件 |
shutil.unpack_archive(filename, extract_dir=None, format=None) | 解压缩压缩文件 |
- 使用该模块的copyfile()方法复制文件
>>> import shutil
>>> shutil.copyfile('C:\\dir.txt', 'C:\\dir1.txt')
- 将C:\Python37\Dlls文件夹以及该文件夹中所有文件压缩至D:\a.zip文件
>>> shutil.make_archive('D:\\a', 'zip', 'C:\\Python37', 'Dlls')
- 将刚压缩得到的文件D:\a.zip解压缩至D:\a_unpack文件夹
>>> shutil.unpack_archive('D:\\a.zip', 'D:\\a_unpack')
- 删除刚刚解压缩得到的文件夹
>>> shutil.rmtree('D:\\a_unpack')
8.3目录操作
OS模块常用的目录操作函数 | 功能说明 |
os.mkdir(path[, mode=0o777]) | 创建目录,要求上级目录必须存在 |
os.makedirs(path1/path2…, mode=511) | 创建多级目录,会根据需要自动创建中间缺失的目录 |
os.rmdir(path) | 删除目录,要求该文件夹中不能有文件或子文件夹 |
os.removedirs(path1/path2…) | 删除多级目录 |
os.listdir(path) | 返回指定目录下所有文件信息 |
os.getcwd() | 返回当前工作目录 |
os.chdir(path) | 把path设为当前工作目录 |
os.walk(top, topdown=True, οnerrοr=None) | 遍历目录树,该方法返回一个元组,包括3个元素:所有路径名、所有目录列表与文件列表 |
>>> import os
>>> os.getcwd() #返回当前工作目录
'C:\\Python35'
>>> os.mkdir(os.getcwd()+'\\temp') #创建目录
>>> os.chdir(os.getcwd()+'\\temp') #改变当前工作目录
>>> os.getcwd()
'C:\\Python35\\temp'
>>> os.mkdir(os.getcwd()+'\\test')
>>> os.listdir('.')
['test']
>>> os.rmdir('test') #删除目录
>>> os.listdir('.')
[]
- 递归遍历文件夹(深度优先)
from os import listdir
from os.path import join, isfile, isdir
def listDirDepthFirst(directory):
#遍历文件夹,文件直接输出,文件夹输出显示后递归遍历该文件夹
for subPath in listdir(directory):
path = join(directory, subPath)
if isfile(path):
print(path)
elif isdir(path):
print(path)
listDirDepthFirst(path)
listDirDepthFirst(r"目录路径")
- 遍历指定文件夹(广度优先)
from os import listdir
from os.path import join, isfile, isdir
def listDirWidthFirst(directory):
dirs = [directory] #获取所有文件夹和文件的列表
#如果还有没遍历过的文件夹,继续循环
while dirs:
current = dirs.pop(0) #遍历还没遍历过的第一项
#遍历该文件夹,文件直接输出显示,文件夹输出显示后标记为待遍历项
for subPath in listdir(current):
path = join(current, subPath)
if isfile(path):
print(path)
elif isdir(path):
print(path)
dirs.append(path) #重新加入到尾部
listDirWidthFirst(r"目录路径")
- 使用os.walk函数遍历
import os
def visitDir2(path):
if not os.path.isdir(path):
print('Error:"',path,'" is not a directory or does not exist.')
return #结束
list_dirs = os.walk(path) #os.walk返回一个元组,包括3个元素:
#所有路径名、所有目录列表与文件列表
for root, dirs, files in list_dirs: #遍历该元组的目录和文件信息
for d in dirs:
print(os.path.join(root, d)) #获取完整路径
for f in files:
print(os.path.join(root, f)) #获取文件绝对路径
9.面向对象程序设计
版权声明:本文标题:【快速入门】python极速版-个人笔记 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/xitong/1729855728a1215556.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论