python学习笔记
2021-08-24 10:25:50 0 举报
AI智能生成
登录查看完整内容
python快速入门,一张图看懂如何写python
作者其他创作
大纲/内容
“ ”
' '
多行自动换行
''' ‘''
英文逗号
在print命令中输入多个变量
输出时默认为空格间隔
指定间隔符
sep=' '
默认\,换行
通过end参数定义更换print输出完成后
end=\" \"
输出目标指定,默认值为 sys.stdout输出到屏幕
先将文件打开,变量赋值后,即可写入文件
file=
用于控制输出缓存,该参数一般保持默认 False 即可
flush
实例 :age = 8 print(\"C语言中文网已经%d岁了!\" % age)
实例: name = \"C语言中文网\" age = 8 url = \"http://c.biancheng.net/\" print(\"%s已经%d岁了,它的网址是%s。\
转换说明符(Conversion Specifier)
%10d 表示输出的整数宽度至少为 10
对于整数和字符串,当数据的实际宽度小于指定宽度时,会默认在左侧以空格补齐;当数据的实际宽度大于指定宽度时,会按照数据的实际宽度输出。
指定最小输出宽度
Python 允许在最小宽度之前增加一个标志来改变对齐方式
子主题
实例:n = 123456 # %09d 表示最小宽度为9,左边补0 print(\"n(09):%09d\" % n) # %+9d 表示最小宽度为9,带上符号 print(\"n(+9):%+9d\" % n) f = 140.5 # %-+010f 表示最小宽度为10,左对齐,带上符号 print(\"f(-+0):%-+010f\" % f) s = \"Hello\" # %-10s 表示最小宽度为10,左对齐 print(\"s(-10):%-10s.\" % s)
指定对齐方式
精度值需要放在最小宽度之后,中间用点号.隔开;也可以不写最小宽度,只写精度。
%m.nf%.nfm 表示最小宽度,n 表示输出精度,.是必须存在的。
实例: f = 3.141592653 # 最小宽度为8,小数点后保留3位 print(\"%8.3f\" % f) # 最小宽度为8,小数点后保留3位,左边补0 print(\"%08.3f\" % f) # 最小宽度为8,小数点后保留3位,左边补0,带符号 print(\"%+08.3f\" % f)
指定小数精度
%
print()
单行注释
#
多行注释
''' '''
数字分隔符
作为数字(包括整数和小数)的分隔符
提高数字的的可读性
通常每隔三个数字添加一个下划线,类似于英文数字中的逗号。下划线不会影响数字本身的值。
_
从控制台读取用户输入的内容
input(显示在控制台的提示信息)
以字符串的形式来处理用户输入的内容
input()
\在输出时换行,\\在书写字符串时换行
\\ 转义字符
常用算术运算符
当+用于数字时表示加法,但是当+用于字符串时,它还有拼接字符串(将两个字符串连接为一个)的作用
实例str1 = \"hello \"print(str1 * 4)
*除了可以用作乘法运算,还可以用来重复字符串
求余结果的正负和第一个数字没有关系,只由第二个数字决定
两边的数字都是整数时,求余的结果也是整数;但是只要有一个数字是小数,求余的结果就是小数。
开方运算
算术运算符
== 用来判断两边的值是否相等
扩展赋值运算符
位运算符
= 赋值运算符
比较运算符汇总
is 用来比对两个变量引用的是否是同一个对象
两个对象的内存地址相同,说明两个对象使用的是同一块内存,就是同一个对象
比较运算符(关系运算符)
逻辑运算符
and 和 or 不一定会计算右边表达式的值,有时候只计算左边表达式的值就能得到最终结果
and 和 or 运算符会将其中一个表达式的值作为最终结果,而不是将 True 或者 False 作为最终结果
对于 and 运算符,两边的值都为真时最终结果才为真,但是只要其中有一个值为假,那么最终结果就是假,所以 Python 按照下面的规则执行 and 运算: 如果左边表达式的值为假,那么就不用计算右边表达式的值了,因为不管右边表达式的值是什么,都不会影响最终结果,最终结果都是假,此时 and 会把左边表达式的值作为最终结果。 如果左边表达式的值为真,那么最终值是不能确定的,and 会继续计算右边表达式的值,并将右边表达式的值作为最终结果。对于 or 运算符,情况是类似的,两边的值都为假时最终结果才为假,只要其中有一个值为真,那么最终结果就是真,所以 Python 按照下面的规则执行 or 运算: 如果左边表达式的值为真,那么就不用计算右边表达式的值了,因为不管右边表达式的值是什么,都不会影响最终结果,最终结果都是真,此时 or 会把左边表达式的值作为最终结果。 如果左边表达式的值为假,那么最终值是不能确定的,or 会继续计算右边表达式的值,并将右边表达式的值作为最终结果。
使用 if else 实现三目运算符(条件运算符)的格式如下:exp1 if contion else exp2condition 是判断条件,exp1 和 exp2 是两个表达式。如果 condition 成立(结果为真),就执行 exp1,并把 exp1 的结果作为整个表达式的结果;如果 condition 不成立(结果为假),就执行 exp2,并把 exp2 的结果作为整个表达式的结果。前面的语句max = a if a>b else b的含义是: 如果 a>b 成立,就把 a 作为整个表达式的值,并赋给变量 max; 如果 a> b 不成立,就把 b 作为整个表达式的值,并赋给变量 max。
三目运算符(三元运算符)
应尽量使用( )来控制表达式的执行顺序
当一个表达式中出现多个运算符时,Python 会先比较各个运算符的优先级,按照优先级从高到低的顺序依次执行;当遇到优先级相同的运算符时,再根据结合性决定先执行哪个运算符:如果是左结合性就先执行左边的运算符,如果是右结合性就先执行右边的运算符。
计算优先级
它不表示 0,也不表示空字符串,而表示没有值,也就是空值
>>> type(None)<class 'NoneType'>
常量 None(N 必须大写)
基础命令
if 语句
if else 语句
if elif else 语句
Python 是以缩进来标记代码块的代码块一定要有缩进,没有缩进的不是代码块另外,同一个代码块的缩进量要相同,缩进量不同的不属于同一个代码块
if、elif、else 语句的最后都有冒号:
b = False if b: print('b是True') else: print('b是False') n = 0 if n: print('n不是零值') else: print('n是零值') s = \"\" if s: print('s不是空字符串') else: print('s是空字符串') l = [] if l: print('l不是空列表') else: print('l是空列表') d = {} if d: print('d不是空字典') else: print('d是空字典') def func(): print(\"函数被调用\") if func(): print('func()返回值不是空') else: print('func()返回值为空')
Python 会把 True 当做“真”,把 False 当做“假”对于数字,Python 会把 0 和 0.0 当做“假”,把其它值当做“真”对于其它类型,当对象为空或者为 None 时,Python 会把它们当做“假”,其它情况当做真。
注意
pass 是 Python 中的关键字,用来让解释器跳过此处,什么都不做
pass
能缩小版的 if 语句它用于判断某个表达式的值,如果值为真,则程序可以继续往下执行反之,Python 解释器会报 AssertionError 错误
首先判断条件表达式的值,其值为真(True)时,则执行代码块中的语句当执行完毕后,再回过头来重新判断条件表达式的值是否为真若仍为真,则继续重新执行代码块...如此循环直到条件表达式的值为假(False),才终止循环
assert 表达式
assert断言函数
选择/分支结构 if else 语句
my_char=\"http://c.biancheng.net/python/\
while 循环
for 循环
当循环条件为 False 跳出循环时,程序会最先执行 else 代码块中的代码
else 代码块
当 2 个(甚至多个)循环结构相互嵌套时位于外层的循环结构常简称为外层循环或外循环位于内层的循环结构常简称为内层循环或内循环
当外层循环条件为 True 时,则执行外层循环结构中的循环体; 外层循环体中包含了普通程序和内循环,当内层循环的循环条件为 True 时会执行此循环中的循环体直到内层循环条件为 False,跳出内循环如果此时外层循环的条件仍为 True,则返回第 2 步,继续执行外层循环体,直到外层循环的循环条件为 False; 当内层循环的循环条件为 False,且外层循环的循环条件也为 False,则整个嵌套循环才算执行完毕。
使用 for 循环实现用冒泡排序算法
嵌套循环
循环结构
add = \
for 循环后也可以配备一个 else 语句。这种情况下,如果使用 break 语句跳出循环体,不会执行 else 中包含的代码
借用一个 bool 类型的变量,同时跳出内层循环和外层循环:
终止循环break
终止执行本次循环,下一次循环继续执行continue
流程控制
函数就是一段封装好的,可以重复使用的代码,它使得我们的程序更加模块化,不需要编写大量重复的代码。函数可以提前保存起来,并给它起一个独一无二的名字,只要知道它的名字就能使用这段代码。函数还可以接收数据,并根据数据的不同做出不同的操作,最后再把处理结果反馈给我们。
压缩zip()
对于给定的序列(包括列表、元组、字符串以及 range(n) 区间),该函数可以返回一个逆序序列的迭代器(用于遍历该逆序序列)
reversed(seq)seq 可以是列表,元素,字符串以及 range() 生成的区间列表
reserved()逆序
sorted()排序
可以执行一个字符串形式的 Python 代码(代码以字符串的形式提供),相当于一个 Python 的解释器
expression:这个参数是一个字符串,代表要执行的语句 。该语句受后面两个字典类型参数 globals 和 locals 的限制,只有在 globals 字典和 locals 字典作用域内的函数和变量才能被执行。globals:这个参数管控的是一个全局的命名空间,即 expression 可以使用全局命名空间中的函数。如果只是提供了 globals 参数,而没有提供自定义的 __builtins__,则系统会将当前环境中的 __builtins__ 复制到自己提供的 globals 中,然后才会进行计算;如果连 globals 这个参数都没有被提供,则使用 Python 的全局命名空间。locals:这个参数管控的是一个局部的命名空间,和 globals 类似,当它和 globals 中有重复或冲突时,以 locals 的为准。如果 locals 没有被提供,则默认为 globals。
a = 1exec(\"a = 2\") #相当于直接执行 a=2print(a)a = exec(\"2+3\") #相当于直接执行 2+3,但是并没有返回值,a 应为 Noneprint(a)a = eval('2+3') #执行 2+3,并把结果返回给 aprint(a)
在编写代码时,一般会使 repr() 数来生成动态的字符串,再传入到 eval() 或 exec() 函数内,实现动态执行代码的功能
eval()执行并返回
执行后不返回结果
exec() 执行
内置函数
函数名:其实就是一个符合 Python 语法的标识符
#自定义 len() 函数def my_len(str): length = 0 for c in str: length = length + 1 return length
def 函数名(参数列表): //实现特定功能的多行代码 [return [返回值]]
def 函数名(...,形参名,形参名=默认值): 代码块
指定有默认值的形式参数必须在所有没默认值参数的最后,否则会产生语法错误
print(dis_str.__defaults__)
Pyhton 中,可以使用“函数名.__defaults__”查看函数的默认值参数的当前值,其返回值是一个元组。
*args是用来传递一个非键值变长参数列表功能。**kwargs通常用来传递关键字变长参数。
默认值参数
在参数前面添加两个星号(**), 该参数支持关键字参数收集,收集的参数别当成 dict 处理一个函数可同时支持普通参数收集和关键字参数收集
在形参前面添加一个星号(*),意味着该参数可接受多个参数值Python 将传给带 * 参数的多个值收集成一个元组Python 允许参数收集的形参位于形参列表的任意位置,但只能带一个支持“普通”参数收集的形参若支持“普通”参数收集的形参位于前面,后面的参数则需要使用关键字参数传值
参数收集
return 语句在同一函数中可以出现多次,但只要有一个得到执行,就会直接结束函数的执行
def isGreater0(x): if x > 0: return True else: return Falseprint(isGreater0(5))print(isGreater0(0))
class Test: def __init__(self): self.str = \"hello world!\" self.x = 20 # 返回一个对象def fun(): return Test()t = fun() print(t.str)print(t.x)
使用Object
# 返回一个列表def fun(): str = \"hello\
使用列表
# 返回一个元组def fun(): str = \"你好!\
使用元组
# 返回一个字典def fun(): d = dict(); d['name'] = \"欧阳克\" d['age'] = 25 return dd = fun() print(d)
使用词典
多个返回值
return 函数返回值
创建函数有多少个形参,那么调用时就需要传入多少个值,且顺序必须和创建函数时一致即便该函数没有参数,函数名后的小括号也不能省略。
在调用函数时,传入实际参数的位置必须和形式参数位置一一对应
当实际参数类型和形式参数类型不一致,并且在函数中,这两种类型之间不能正常转换,此时就会抛出 TypeError 异常。
[返回值] = 函数名([形参值])
指使用形式参数的名字来确定输入的参数值。通过此方式指定函数实参时,不再需要与形参的位置完全一致,只要将参数名写正确即可。
混合传参时关键字参数必须位于所有的位置参数之后
关键字参数
在列表、元组前添加 *,在字典前添加 **
逆向参数收集
def my_def (): print(\"正在执行 my_def 函数\")#将函数赋值给其他变量 other = my_def#间接调用 my_def() 函数other()
直接将函数赋值给其它变量
将函数以参数的形式传入其他函数中
def my_def (): #局部函数 def indef(): print(\"调用局部函数\") #调用局部函数 return indefother_def = my_def()#调用局部的 indef() 函数other_def()
函数的返回值也为函数
调用自定义函数
'''猴子吃桃问题:猴子第一天摘下若干个桃子,当即吃了一半,还不瘾,又多吃了一个第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半零一个。到第10天早上想再吃时,见只剩下一个桃子了。求第一天共摘了多少?'''def monkey(n): if n == 1: return 1 else: return (monkey(n - 1) + 1) * 2print(monkey(10))
递归函数实例
将现有函数的部分参数预先绑定为指定值,从而得到一个新的函数
partial偏函数
Python 支持在函数内部定义函数,此类函数又称为局部函数默认情况下局部函数只能在其所在函数的作用域内使用
#全局函数def outdef (): #局部函数 def indef(): print(\"http://c.biancheng.net/python/\") #调用局部函数 indef()#调用全局函数outdef()
#全局函数def outdef (): #局部函数 def indef(): print(\"调用局部函数\") #调用局部函数 return indef#调用全局函数new_indef = outdef()调用全局函数中的局部函数new_indef()
局部函数
和嵌套函数类似,不同之处在于,闭包中外部函数返回的不是一个具体的值,而是一个函数一般情况下,返回的函数会赋值给一个变量,这个变量可以在后面被继续执行调用。
#闭包函数,其中 exponent 称为自由变量def nth_power(exponent): def exponent_of(base): return base ** exponent return exponent_of # 返回值是 exponent_of 函数square = nth_power(2) # 计算一个数的平方cube = nth_power(3) # 计算一个数的立方print(square(2)) # 计算 2 的平方print(cube(2)) # 计算 2 的立方外部函数 nth_power() 的返回值是函数 exponent_of(),而不是一个具体的数值
闭合函数
常用来表示内部仅包含 1 行表达式的函数。如果一个函数的函数体仅有 1 行表达式,则该函数就可以用 lambda 表达式来代替。
name = lambda [list] : 表达式必须使用 lambda 关键字[list] 作为可选参数,等同于定义函数是指定的参数列表value 为该表达式的名称。
对于单行函数,使用 lambda 表达式可以省去定义函数的过程,让代码更加简洁;对于不需要多次复用的函数,使用 lambda 表达式可以在用完之后立即释放,提高程序执行的性能
匿名函数lambda表达式
自定义函数def
代码中每一块都是不可变的,都由纯函数的形式组成
对可迭代对象中的每个元素,都调用指定的函数,并返回一个 map 对象
可以接受多个可迭代对象
function 参数表示要传入一个函数,其可以是内置函数、自定义函数或者 lambda 匿名函数iterable 表示一个或多个可迭代对象,可以是列表、字符串等
map()
对 iterable 中的每个元素,都使用 function 函数判断,并返回 True 或者 False,最后将返回 True 的元素组成一个新的可遍历的集合
filter()
用来对一个集合做一些累积操作
function 规定必须是一个包含 2 个参数的函数;iterable 表示可迭代对象
reduce() 函数在 Python 3.x 中已经被移除,放入了 functools 模块,因此在使用该函数之前,需先导入 functools 模块
reduce()
函数式编程
给函数中的参数做注解的方法是在形参后添加冒号“:”,后接需添加的注解(可以是类(如 str、int 等),也可以是字符串或者表示式);给返回值做注解的方法是将注解添加到 def 语句结尾的冒号和 -> 之间
如果参数有默认值,参数注解位于冒号和等号之间。比如 eggs:str='eggs',它表示 eggs 参数的默认值为 'eggs',添加的注解为 str。
def square(number:\"一个数字\")->\"返回number的平方\": return number**2print(square(10))print(square.__annotations__)
函数注解
函数
诸多容器,例如列表、元组、字符串、字典等,它们都是对数据的封装;函数是对 Python 代码的封装;类是对方法和属性的封装,也可以说是对函数和数据的封装。
模块,是对代码更高级的封装即把能够实现某一特定功能的代码编写在同一个 .py 文件中,并将其作为一个独立的模块这样既可以方便其它程序或脚本导入并使用,同时还能有效避免函数名和变量名发生冲突
封装特性的结构
name = \"Python教程\"add = \"http://c.biancheng.net/python\
'''demo 模块中包含以下内容:name 字符串变量:初始值为“Python教程”add 字符串变量:初始值为“http://c.biancheng.net/python”say() 函数CLanguage类:包含 name 和 add 属性和 say() 方法。'''
可以通过模板的 __doc__ 属性,来访问模板的说明文档 import demoprint(demo.__doc__)
说明文档
当直接运行一个模块时,name 变量的值为 __main__;而将模块被导入其他程序中并运行该程序时,处于模块中的 __name__ 变量的值就变成了模块名。因此,如果希望测试函数只有在直接运行模块文件时才执行,则可在调用测试函数时增加判断即只有当 __name__ =='__main__' 时才调用测试函数
一般情况下,当我们写完自定义的模块之后,都会写一个测试代码,检验一些模块中各个功能是否能够成功运行例如,创建一个 candf.py 文件,并编写如下代码:纯文本复制'''摄氏度和华氏度的相互转换模块'''def c2f(cel): fah = cel * 1.8 + 32 return fahdef f2c(fah): cel = (fah - 32) / 1.8 return celdef test(): print(\"测试数据:0 摄氏度 = %.2f 华氏度\" % c2f(0)) print(\"测试数据:0 华氏度 = %.2f 摄氏度\" % f2c(0))test()
__name__ 变量
自定义一个模块
当我们向文件导入某个模块时,导入的是该模块中那些名称不以下划线(单下划线“_”或者双下划线“__”)开头的变量、函数和类因此,如果我们不想模块文件中的某个成员被引入到其它文件中使用,可以在其名称前添加下划线。
# 导入sys整个模块import sys# 使用sys模块名作为前缀来访问模块中的成员print(sys.argv[0])
导入整个模块时,也可以为模块指定别名。 # 导入sys整个模块,并指定别名为simport sys as s# 使用s模块别名作为前缀来访问模块中的成员print(s.argv[0])
使用 from...import 最简单的语法来导入指定成员: # 导入sys模块的argv成员from sys import argv# 使用导入成员的语法,直接使用成员名访问print(argv[0])
导入模块成员时,也可以为成员指定别名:纯文本复制# 导入sys模块的argv成员,并为其指定别名vfrom sys import argv as v# 使用导入成员(并指定别名)的语法,直接使用成员的别名访问print(v[0])
main.py# import module_testfrom module_test import * #这种是把模块中的代码复制到了这个py脚本中
示例
如果模块中包含空格或者以数字开头,就需要使用 Python 提供的 __import__() 内置函数引入模块
__import__(\"demo text\")
__import__(\"1demo\")
使用 __import__() 函数引入模块名时,要以字符串的方式将模块名引入,否则会报 SyntaxError 错误
__import__
通常情况下,当使用 import 语句导入模块后,Python 会按照以下顺序查找指定的模块文件:在当前目录,即当前执行的程序文件所在目录下查找;到 PYTHONPATH(环境变量)下的每个目录中查找;到 Python 默认的安装目录下查找。
模块文件的存储位置,可以临时添加到 sys.path 变量中即向 sys.path 中添加 D:\\python_module(hello.py 所在目录),在 say.py 中的开头位置添加如下代码:import syssys.path.append('D:\\\\python_module')注意:在添加完整路径中,路径中的 '\\' 需要使用 \\ 进行转义,否则会导致语法错误。
通过该方法添加的目录,只能在执行当前文件的窗口中有效,窗口关闭后即失效
import sysprint(sys.path) #python会去哪些目录下找模块,是一个列表Module_Dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) #获取到模块目录sys.path.append(Module_Dir)#把模块目录加到sys.path列表中import 要导入的模块
向 sys.path 中临时添加模块文件存储位置的完整路径
将模块放在 sys.path 变量中已包含的模块加载路径中
PYTHONPATH 环境变量(简称 path 变量)的值是很多路径组成的集合Python 解释器会按照 path 包含的路径进行一次搜索,直到找到指定要加载的模块当然,如果最终依旧没有找到,则 Python 就报 ModuleNotFoundError 异常。
设置 path 系统环境变量
Python找不到指定模块
该变量的值是一个列表,存储的是当前模块中一些成员(变量、函数或者类)的名称通过在模块文件中设置 __all__ 变量,当其它文件以“from 模块名 import *”的形式导入该模块时,该文件中只能使用 __all__ 列表中指定的成员
def say(): print(\"人生苦短,我学Python!\")def CLanguage(): print(\"C语言中文网:http://c.biancheng.net\")def disPython(): print(\"Python教程:http://c.biancheng.net/python\")__all__ = [\"say\
__all__ 变量仅限于在其它文件中以“from 模块名 import *”的方式引入
以“import 模块名”的形式导入模块。通过该方式导入模块后总可以通过模块名前缀(如果为模块指定了别名,则可以使用模快的别名作为前缀)来调用模块内的所有成员(除了以下划线开头命名的成员)
以“from 模块名 import 成员”的形式直接导入指定成员使用此方式导入的模块,__all__ 变量即便设置,也形同虚设
__all__变量
import 导入模块
存放多个模块的文件夹必须带有一个__init__.py文件(这是 Python 2.x 的规定,而在 Python 3.x 中,__init__.py 对包来说,并不是必须的)
包的本质依然是模块,包可以包含包
新建一个文件夹,文件夹的名称就是新建包的包名;在该文件夹中,创建一个 __init__.py 文件(前后各有 2 个下划线‘_’),该文件中可以不编写任何代码。也可以编写一些 Python 初始化代码,则当有其它程序文件导入包时,会自动执行该文件中的代码
创建一个包
import my_package.module1my_package.module1.display(\"http://c.biancheng.net/java/\")
通过此语法格式导入包中的指定模块后,在使用该模块中的成员(变量、函数、类)时,需添加“包名.模块名”为前缀
import my_package.module1 as modulemodule.display(\"http://c.biancheng.net/python/\")
直接导入包名,并不会将包中所有模块全部导入到程序中
import 包名[.模块名 [as 别名]]用 [] 括起来的部分,是可选部分,即可以使用,也可以直接忽略
from my_package import module1module1.display(\"http://c.biancheng.net/golang/\")
使用此语法格式导入包中模块后,在使用其成员时不需要带包名前缀,但需要带模块名前缀
from 包名 import 模块名 [as 别名]
from my_package.module1 import displaydisplay(\"http://c.biancheng.net/shell/\")
通过该方式导入的变量(函数、类),在使用时可以直接使用变量名(函数名、类名)调用
加载该模块下的所有成员from my_package.module1 import *display(\"http://c.biancheng.net/python\")
from 包名.模块名 import 成员名 [as 别名]
导入包的同时,会在包目录下生成一个含有 __init__.cpython-36.pyc 文件的 __pycache__ 文件夹
可以被import语句导入的对象是以下类型:模块文件(.py文件)C或C++扩展(已编译为共享库或DLL文件)包(包含多个模块)内建模块(使用C编写并已链接到Python解释器中)
导入包
import stringprint(dir(string))
dir()函数查看模块成员
import stringprint(string.__all__)
和 dir() 函数相比,__all__ 变量在查看指定模块成员时,它不会显示模块中的特殊成员,同时还会根据成员的名称进行排序显示
并非所有的模块都支持使用 __all__ 变量,因此对于获取有些模块的成员,就只能使用 dir() 函数
获取指定成员(甚至是该模块)的帮助信息
#***__init__.py 文件中的内容***from my_package.module1 import *from my_package.module2 import *#***module1.py 中的内容***#module1.py模块文件def display(arc): ''' 直接输出指定的参数 ''' print(arc)#***module2.py中的内容***#module2.py 模块文件class CLanguage: ''' CLanguage是一个类,其包含: display() 方法 ''' def display(self): print(\"http://c.biancheng.net/python/\")
help() 函数
import my_packageprint(my_package.module1.display.__doc__)
__doc__属性:查看文档
import my_packageprint(my_package.__file__)
因为当引入 my_package 包时,其实际上执行的是 __init__.py 文件因此这里查看 my_package 包的存储路径,输出的 __init__.py 文件的存储路径
import stringprint(string.__file__)
并不是所有模块都提供 __file__ 属性,因为并不是所有模块的实现都采用 Python 语言有些模块采用的是其它编程语言(如 C 语言)
__file__属性查看模块的源文件路径
https://pypi.org/
可以使用 Python 提供的 pip 命令实现。pip 命令的语法格式如下:pip install|uninstall|list 模块名其中,install、uninstall、list 是常用的命令参数,各自的含义为:install:用于安装第三方模块,当 pip 使用 install 作为参数时,后面的模块名不能省略。uninstall:用于卸载已经安装的第三方模块,选择 uninstall 作为参数时,后面的模块名也不能省略。list:用于显示已经安装的第三方模块。
以安装 numpy 模块为例(该模块用于进行科学计算),可以在命令行窗口中输入以下代码:pip install numpy执行此代码,它会在线自动安装 numpy 模块
pip 命令会将下载完成的第三方模块,默认安装到 Python 安装目录中的 \\Lib\\site-packages 目录下
#直接导入 numpy 模块即可import numpy as nu#用 numpy 模块中的开发函数print(nu.sqrt(16))
如果想要查看 Python 中目前有哪些模块(包括标准模块和第三方模块),可以在 IDLE 中输入以下命令:help('modules')在此基础上,如果只是想要查看已经安装的第三方模块,可以在使用如下命令:pip list
第三方库(模块)下载和安装使用pip命令
包
库:相比模块和包,库是一个更大的概念例如在 Python 标准库中的每个库都有好多个包,而每个包中都有若干个模块
库
模块和包
在 Windows 中,根文件夹名为 D:\\,也称为 D: 盘。在 OS X 和 Linux 中,根文件夹是 /
将单个文件和路径上的文件夹名称的字符串传递给它os.path.join() 就会返回一个文件路径的字符串,包含正确的路径分隔符
os.path.join()
os.getcwd() 取得当前工作路径的字符串
>>> import os>>> os.getcwd()'C:\\\\Users\\\\mengma\\\\Desktop'>>> os.chdir('C:\\\\Windows\\\\System32')>>> os.getcwd()'C:\\\\Windows\\\\System32'
os.chdir()改变当前工作路径的字符串
os.path.split()获得一个路径的目录名称和基本名称
如果提供的路径不存在,许多 Python 函数就会崩溃并报错,但好在 os.path 模块提供了以下函数用于检测给定的路径是否存在,以及它是文件还是文件夹:如果 path 参数所指的文件或文件夹存在,调用 os.path.exists(path) 将返回 True,否则返回 False。如果 path 参数存在,并且是一个文件,调用 os.path.isfile(path) 将返回 True,否则返回 False。如果 path 参数存在,并且是一个文件夹,调用 os.path.isdir(path) 将返回 True,否则返回 False。
路径
文件的应用级操作可以分为以下 3 步,每一步都需要借助对应的函数实现:打开文件:使用 open() 函数,该函数会返回一个文件对象;对已打开文件做读/写操作:读取文件内容可使用 read()、readline() 以及 readlines() 函数;向文件中写入内容,可以使用 write() 函数。关闭文件:完成对文件的读/写操作之后,最后需要关闭文件,可以使用 close() 函数。
操作步骤
open() 函数用于创建或打开指定文件
用 [] 括起来的部分为可选参数,即可以使用也可以省略。其中,各个参数所代表的含义如下:file:表示要创建的文件对象。file_name:要创建或打开文件的文件名称,该名称要用引号(单引号或双引号都可以)括起来。需要注意的是,如果要打开的文件和当前执行的代码文件位于同一目录,则直接写文件名即可;否则,此参数需要指定打开文件所在的完整路径。mode:可选参数,用于指定文件的打开模式。可选的打开模式如表 1 所示。如果不写,则默认以只读(r)模式打开文件。buffering:可选参数,用于指定对文件做读写操作时,是否使用缓冲区(本节后续会详细介绍)。encoding:手动设定打开文件时所使用的编码格式,不同平台的 ecoding 参数值也不同,以 Windows 为例,其默认为 cp936(实际上就是 GBK 编码)
#当前程序文件同目录下没有 a.txt 文件file = open(\"a.txt\")print(file)
file = open(\"a.txt\
使用 open() 打开文件时,默认采用 GBK 编码但当要打开的文件不是 GBK 编码格式时,可以在使用 open() 函数时,手动指定打开文件的编码格式
建议大家在使用 open() 函数时打开缓冲区,即不需要修改 buffing 参数的值。如果 buffing 参数的值为 0(或者 False),则表示在打开指定文件时不使用缓冲区;如果 buffing 参数值为大于 1 的整数,该整数用于指定缓冲区的大小(单位是字节);如果 buffing 参数的值为负数,则代表使用默认的缓冲区大小。
缓冲区
file.name:返回文件的名称;file.mode:返回打开文件时,采用的文件打开模式;file.encoding:返回打开文件时使用的编码格式;file.closed:判断文件是否己经关闭。
# 以默认方式打开文件f = open('my_file.txt')# 输出文件是否已经关闭print(f.closed)# 输出访问模式print(f.mode)#输出编码格式print(f.encoding)# 输出文件名print(f.name)
常用属性
使用 open() 函数打开的文件对象,必须手动进行关闭Python 垃圾回收机制无法自动回收打开文件所占用的资源
文本文件通常用来保存肉眼可见的字符,比如 .txt 文件、.c 文件、.dat 文件等二进制文件通常用来保存视频、图片、音频等不可阅读的内容
open()函数打开文件
read() 函数:逐个字节或者字符读取文件中的内容;readline() 函数:逐行读取文件中的内容;readlines() 函数:一次性读取文件中多行内容。
按字节(字符)读取文件
如果文件是以文本模式(非二进制模式)打开的,则 read() 函数会逐个字符进行读取如果文件以二进制模式打开,则 read() 函数会逐个字节进行读取
#以 utf-8 的编码格式打开指定文件f = open(\"my_file.txt\
#以二进制形式打开指定文件f = open(\"my_file.txt\
file.read([size])其中,file 表示已打开的文件对象;size 作为一个可选参数,用于指定一次最多可读取的字符(字节)个数,如果省略,则默认一次性读取所有内容。
read()函数读取文件
每次都读取目标文件中的一行。对于读取以二进制格式打开的文件,它们会以“\”作为读取一行的标志
size 为可选参数,用于指定读取每一行时,一次最多读取的字符(字节)数
readline() 函数在读取文件中一行的内容时,会读取最后的换行符“\”再加上 print() 函数输出内容时默认会换行,所以输出结果中会看到多出了一个空行
f = open(\"my_file.txt\")读取一行数据byt = f.readline()print(byt)
file.readline([size])
readline()读取目标文件中的一行
readlines() 函数用于读取文件中的所有行,它和调用不指定 size 参数的 read() 函数类似,只不过该函数返回是一个字符串列表,其中每个元素为文件中的一行内容
f = open(\"my_file.txt\
file.readlines()其中,file 为打开的文件对象。和 read()、readline() 函数一样,它要求打开文件的模式必须为可读模式(包括 r、rb、r+、rb+ 4 种)。
readlines()读取文件中的所有行
打开文件模式中包含 w(写入),那么向文件中写入内容时,会先清空原文件中的内容,然后再写入新的内容
f = open(\"a.txt\
打开文件模式中包含 a(追加),则不会清空原有内容,而是将新写入的内容会添加到原内容后边
file.write(string)其中,file 表示已经打开的文件对象;string 表示要写入文件的字符串(或字节串,仅适用写入二进制文件中)
在写入文件完成后,一定要调用 close() 函数将打开的文件关闭,否则写入的内容不会保存到文件中
span style=\
write()写入文件
需要在将数据成功写入到文件中,但并不想关闭文件
flush() 函数将缓冲区的数据写入文件中
将 a.txt 文件中的数据复制到其它文件中
使用 writelines() 函数向文件中写入多行数据时,不会自动给各行添加换行符
writelines()将字符串列表写入文件中
file.close()
import osf = open(\"my_file.txt\
close()函数关闭文件
seek()移动文件指针到文件的指定位置
file.tell()
当使用 read() 函数从文件中读取 3 个字符之后,文件指针同时向后移动了 3 个字符的位置
tell()判断文件指针当前所处的位置
pickle 模块提供了以下 4 个函数供我们使用:dumps():将 Python 中的对象序列化成二进制对象,并返回;loads():读取给定的二进制对象数据,并将其转换为 Python 对象;dump():将 Python 中的对象序列化成二进制对象,并写入文件;load():读取指定的序列化数据文件,并返回对象。
实现任意对象与文本之间的相互转化,也可以实现任意对象与二进制之间的相互转化
pickle.dumps()函数
pickle.loads()函数
pickle.dump()函数
pickle.load()函数
pickle序列化过程
input() 函数
fileinput.input(files=\
读取文件内容的次序,取决于 input() 函数中文件名的先后次序
fileinput模块逐行读取多个文件
linecache 模块常用来读取 Python 源文件中的代码,它使用的是 UTF-8 编码格式来读取文件内容
linecache 模块读取指定文件中的指定行
写入、读取作用于文件的内容,属于应用级操作
在打开文件或文件操作过程中抛出了异常,无法及时关闭文件使用 with as 语句操作上下文管理器(context manager)能够帮助我们自动分配并且释放资源
http://c.biancheng.net/view/5319.html
同时包含 __enter__() 和 __exit__() 方法的对象就是上下文管理器
with 表达式 [as target]: 代码块此格式中,用 [] 括起来的部分可以使用,也可以省略。其中,target 参数用于指定一个变量,该语句会将 expression 指定的结果保存到该变量中。with as 语句中的代码块如果不想执行任何语句,可以直接使用 pass 语句代替
通过使用 with as 语句,即便最终没有关闭文件,修改文件内容的操作也能成功
with as 语句
import os print (os.sep)print (os.name)print (os.getenv('path'))print (os.getcwd())
系统操作
dirs=\"D:\\\\Release\\\\bin\"files= os.listdir(dirs)print files
目录下必须是空的才能删除import osmy_dir=\"D:\\\\liangmx\\\\LR\\zl\\\\123\"if os.path.exists(my_dir): os.rmdir(my_dir)
删除目录
打印当前目录中包含homeword的文件,已经打印出绝对路径思路:第一步:获取当前路径路径,获取当前路径下的文件或者文件夹第二步:循环文件,判断是否问文件,如果是文件,就判断是否包含 字符串,然后打印import os#coding=utf-8'''编写程序:1:能在当前目录下查找文件名包含指定字符串的文件2:并打印出绝对路径'''sub_str=\"homework\
目录操作
判断
import os#coding:utf-8#列出当前目录下的所有文件dirs=\"D:\\\\Release\\\\bin\
path模块
from os import path# 获取绝对路径print(path.abspath(\"my_file.txt\
os.path 模块
OS模块
两种方式来创建临时文件:第一种方式是手动创建临时文件,读写临时文件后需要主动关闭它,当程序关闭该临时文件时,该文件会被自动删除。第二种方式则是使用 with 语句创建临时文件,这样 with 语句会自动关闭临时文件
tempfile模块创建临时文件和临时目录
import osos.remove(\"a.txt\")
删除
pathlib 模块的操作对象是各种操作系统中使用的路径(例如指定文件位置的路径,包括绝对路径和相对路径)。这里简单介绍一下图 1 中包含的几个类的具体功能:PurePath 类会将路径看做是一个普通的字符串,它可以实现将多个指定的字符串拼接成适用于当前操作系统的路径格式,同时还可以判断任意两个路径是否相等。注意,使用 PurePath 操作的路径,它并不会关心该路径是否真实有效。PurePosixPath 和 PureWindowsPath 是 PurePath 的子类,前者用于操作 UNIX(包括 Mac OS X)风格的路径,后者用于操作 Windows 风格的路径。Path 类和以上 3 个类不同,它操作的路径一定是真实有效的。Path 类提供了判断路径是否真实存在的方法。PosixPath 和 WindowPath 是 Path 的子类,分别用于操作 Unix(Mac OS X)风格的路径和 Windows 风格的路径。
from pathlib import *# 创建PurePath,实际上使用PureWindowsPathpath = PurePath('my_file.txt')print(type(path))
在使用 PurePath 类构造方法时,不传入任何参数,则等同于传入点‘.’(表示当前路径)作为参数。
如果传入 PurePath 构造方法中的多个参数中,包含多个根路径,则只会有最后一个根路径及后面的子路径生效
如果传给 PurePath 构造方法的参数中包含有多余的斜杠或者点( . ,表示当前路径),会直接被忽略( .. 不会被忽略)
对余同种风格的路径字符串来说,可以判断是否相等,也可以比较大小(实际上就是比较字符串的大小)from pathlib import *# Unix风格的路径区分大小写print(PurePosixPath('C://my_file.txt') == PurePosixPath('c://my_file.txt'))# Windows风格的路径不区分大小写print(PureWindowsPath('C://my_file.txt') == PureWindowsPath('c://my_file.txt'))
PurePath 类
支持对路径的真实性进行判断
Path 类
pathlib模块
fnmatch 模块匹配文件名的模式使用的就是 UNIX shell 风格,其支持使用如下几个通配符:*:可匹配任意个任意字符。?:可匹配一个任意字符。[字符序列]:可匹配中括号里字符序列中的任意字符。该字符序列也支持中画线表示法。比如 [a-c] 可代表 a、b 和 c 字符中任意一个。[!字符序列]:可匹配不在中括号里字符序列中的任意字符。
fnmatch模块文件名称的匹配
ZODB 是一个健壮的、多用户的和面向对象的数据库系统,专门用于存储 Python 语言中的对象数据,它能够存储和管理任意复杂的 Python 对象,并支持事务操作和并发控制
ZODB
文件操作
含负数
含0
整数
int()
3.14
浮点数的指数写法
314e-2/314E-2
浮点数
示例:12.3 * 0.1
小数的计算可能是不精确的
float()
转义:'I\\'m a great coder!'
换行
\\
单引号或双引号效果一致
可以换行
内容中的引号不需要转义
换行、空格、缩进等空白符都会原样输出
长字符串,连续三个单引号
rstr = r'D:\\Program Files\\Python 3.8\\python.exe'
r'原始字符串'
原始字符串中的/不需要转义
引号或双引号仍需要转义
原始字符串
str() 用于将数据转换成适合人类阅读的字符串形式。 repr() 用于将数据转换成适合解释器阅读的字符串形式(Python 表达式的形式),适合在开发和调试阶段使用;如果没有等价的语法,则会发生 SyntaxError 异常。
在 Python 交互式编程环境中输入一个表达式(变量、加减乘除、逻辑运算等)时,Python 会自动使用 repr() 函数处理该表达式
repr()
常规用法
只能拼接字符串常量
strname = \"str1\" \"str2\"
变量拼接
strname = str1 + str2
str() 和 repr() 函数将数字转换为字符串
字符串和数字的拼接
拼接字符串
获取单个字符
index 表示索引值
strname[index]
获取字符串
start:表示要截取的第一个字符所在的索引(截取时包含该字符)。如果不指定,默认为 0,也就是从字符串的开头截取;end:表示要截取的最后一个字符所在的索引(截取时不包含该字符)。如果不指定,默认为字符串的长度;step:指的是从 start 索引处的字符开始,每 step 个距离获取一个字符,直至 end 索引出的字符。step 默认值为 1,当省略该值时,最后一个冒号也可以省略。
strname[start : end : step]
字符串切片
计算字符串的长度
len(string)
将字符串进行编码后再获取它的字节数
len(str1.encode())
采用 GBK 编码的字符串的长度
len(str1.encode('gbk'))
encode()
获取字符串长度或字节数
split()
sep:用于指定分隔符,可以包含多个字符。此参数默认为 None,表示所有空字符,包括空格、换行符“\”、制表符“\\t”等
maxsplit:可选参数,用于指定分割的次数,最后列表中子串的个数最多为 maxsplit+1。如果不指定或者指定为 -1,则表示分割次数没有限制
如果不指定 sep 参数,那么也不能指定 maxsplit 参数
将一个字符串按照指定的分隔符切分成多个子串,这些子串会被保存到列表中(不包含分隔符),作为方法的返回值反馈回来
分割字符串
split() 方法的逆方法
str:用于指定合并时的分隔符
iterable:做合并操作的源字符串数据,允许以列表、元组等形式提供
newstr = str.join(iterable)
join()
合并字符串
count()
检索指定字符串在另一字符串中出现的次数,如果检索的字符串不存在,则返回 0,否则返回出现的次数
str:表示原字符串; sub:表示要检索的字符串; start:指定检索的起始位置,也就是从什么位置开始检测。如果不指定,默认从头开始检索; end:指定检索的终止位置,如果不指定,则表示一直检索到结尾。
统计字符串出现的次数
检索字符串中是否包含目标字符串,如果包含,则返回第一次出现该字符串的索引;反之,则返回 -1
str:表示原字符串; sub:表示要检索的目标字符串; start:表示开始检索的起始位置。如果不指定,则默认从头开始检索; end:表示结束检索的结束位置。如果不指定,则默认一直检索到结尾。
find()
rfind() 是从字符串右边开始检索
rfind()
str:表示原字符串; sub:表示要检索的子字符串; start:表示检索开始的起始位置,如果不指定,默认从头开始检索; end:表示检索的结束位置,如果不指定,默认一直检索到结尾。
当指定的字符串不存在时,index() 方法会抛出异常
index()
作用和 index() 方法类似,不同之处在于它是从右边开始检索
rindex()
检测字符串中是否包含某子串
向指定字符串的右侧填充指定字符,从而达到左对齐文本的目的
S:表示要进行填充的字符串;width:表示包括 S 本身长度在内,字符串要占的总长度;fillchar:作为可选参数,用来指定填充字符串时所用的字符,默认情况使用空格
ljust()
和 ljust() 方法类似,唯一的不同在于,rjust() 方法是向字符串的左侧填充指定字符,从而达到右对齐文本的目的
rjust()
center()
字符串对齐方法
检索字符串是否以指定字符串开头,如果是返回 True;反之返回 False
str:表示原字符串; sub:要检索的子串; start:指定检索开始的起始位置索引,如果不指定,则默认从头开始检索; end:指定检索的结束位置索引,如果不指定,则默认一直检索在结束。
startswith()
str:表示原字符串;sub:表示要检索的字符串;start:指定检索开始时的起始位置索引(字符串第一个字符对应的索引值为 0),如果不指定,默认从头开始检索。end:指定检索的结束位置索引,如果不指定,默认一直检索到结束
endswith()
起始和结尾判断
将字符串中每个单词的首字母转为大写,其他字母全部转为小写
str.title()
title()
将字符串中的所有大写字母转换为小写字母
str.lower()
lower()
将字符串中的所有小写字母转换为大写字母
str.upper()
upper()
字符串大小写转换
制表符(\\t)、回车符(\)、换行符(\)
str.strip([chars])
str 表示原字符串,[chars] 用来指定要删除的字符,可以同时指定多个,如果不手动指定,则默认会删除空格以及制表符、回车符、换行符等特殊字符
strip():删除字符串前后(左右两侧)的空格或特殊字符
lstrip():删除字符串前面(左边)的空格或特殊字符
rstrip():删除字符串后面(右边)的空格或特殊字符
Python 的 str 是不可变的(不可变的意思是指,字符串一旦形成,它所包含的字符序列就不能发生任何改变),因此这三个方法只是返回字符串前面或后面空白被删除之后的副本,并不会改变字符串本身
删除指定字符
format()
str.format(args)
str 用于指定字符串的显示样式;args 用于指定要进行格式转换的项,如果有多项,之间有逗号进行分割
格式中用 [] 括起来的参数都是可选参数,即可以使用,也可以不使用
width:指定输出数据时所占的宽度。.precision:指定保留的小数位数。
str 显示样式的书写格式 { [index][ : [ [fill] align] [sign] [#] [width] [.precision] [type] ] }
#以货币形式显示 print(\
格式化输出
Python 3.x 默认采用 UTF-8 编码格式
在 Python 中,有 2 种常用的字符串类型,分别为 str 和 bytes 类型其中 str 用来表示 Unicode 字符bytes 用来表示二进制数据str 类型和 bytes 类型之间就需要使用 encode() 和 decode() 方法进行转换
格式中用 [] 括起来的参数为可选参数
str.encode([encoding=\"utf-8\
将 str 类型转换成 bytes 类型,这个过程也称为“编码”
bytes.decode([encoding=\"utf-8\
将 bytes 类型的二进制数据转换为 str 类型,这个过程也称为“解码”
decode()
字符串编码转换
函数用来列出某个类或者某个模块中的全部内容,包括变量、方法、函数和类等
dir()
查看某个函数或者模块的帮助文档
help()
帮助函数
str()
查询变量类型
type()
以字节序列的形式(二进制形式)存储数据
如果字符串的内容都是 ASCII 字符,那么直接在字符串前面添加b前缀就可以转换成 bytes
如果不指定字符集encode(),那么默认采用 UTF-8
bytes()
具体格式为:a + bj
可计算
复数(Complex)
常用数据类型转换函数
变量的有效范围,就是变量可以在哪个范围以内使用。有些变量可以在整段代码的任意位置使用有些变量只能在函数内部使用有些变量只能在 for 循环内部使用
当函数执行完毕后,其内部定义的变量会被销毁并回收
def demo(): add = \"http://c.biancheng.net/python/\" print(\"函数内部 add =\
#全局变量Pyname = \"Python教程\"Pyadd = \"http://c.biancheng.net/python/\"def text(): #局部变量 Shename = \"shell教程\" Sheadd= \"http://c.biancheng.net/shell/\" print(\"函数内部的 locals:\") print(locals())text()print(\"函数外部的 locals:\")print(locals())
可以通过指定键访问对应的变量值,但无法对变量值做修改
locals()函数
返回一个指定 object 对象范围内所有变量组成的字典。如果不传入object 参数,vars() 和 locals() 的作用完全相同
#全局变量Pyname = \"Python教程\"Pyadd = \"http://c.biancheng.net/python/\"class Demo: name = \"Python 教程\" add = \"http://c.biancheng.net/python/\"print(\"有 object:\")print(vars(Demo))print(\"无 object:\")print(vars())
vars(object)
局部变量(Local Variable)
在函数体外定义的变量,一定是全局变量
def text(): global add add= \"http://c.biancheng.net/java/\" print(\"函数体内访问:\
在函数体内定义全局变量。即使用 global 关键字对变量进行修饰后,该变量就会变为全局变量
返回一个包含全局范围内所有变量的字典,该字典中的每个键值对,键为变量名,值为该变量的值
#全局变量Pyname = \"Python教程\"Pyadd = \"http://c.biancheng.net/python/\"def text(): #局部变量 Shename = \"shell教程\" Sheadd= \"http://c.biancheng.net/shell/\"print(globals())
访问指定变量,并赋值print(globals()['Pyname'])globals()['Pyname'] = \"Python入门教程\"print(Pyname)
h4 style=\
全局变量(Global Variable)
全局变量默认可以在所有函数内被访问但是,如果当函数中定义了与全局变量同名的变量时,就会发生局部变量遮蔽(hide)全局变量的情形
name = 'Charlie' def test (): # 声明name是全局变量,后面的赋值语句不会重新定义局部变量 global name # 直接访问name全局变量 print(name) # Charlie name = '孙悟空' test() print(name) # 孙悟空
在函数中使用同名的全局变量
作用域(Scope)
变量
使用负值作为列序中各元素的索引值时,是从 -1 开始,而不是从 0 开始
序列索引
sname[start : end : step]
sname:表示序列的名称; start:表示切片的开始索引位置(包括该位置),此参数也可以不指定,会默认为 0,也就是从序列的开头进行切片; end:表示切片的结束索引位置(不包括该位置),如果不指定,则默认为序列的长度; step:表示在切片过程中,隔几个存储位置(包含当前位置)取一次元素,也就是说,如果 step 的值大于 1,则在进行切片去序列元素时,会“跳跃式”的取元素。如果省略设置 step 的值,则最后一个冒号就可以省略。
序列切片
序列相加
序列相乘
检查元素是否包含在序列中
not in
in
序列相关的内置函数
序列 Sequence
多个数据挨个存储到一起
通常同一列表中只放入同一类型的数据,这样可以提高程序的可读性
emptylist = [ ] 创建一个空列表
转化为列表
list()
新建[]
listname.append(obj)listname 表示要添加元素的列表;obj 表示到添加到列表末尾的数据,它可以是单个元素,也可以是列表、元组等
append()
listname.extend(obj)listname 指的是要添加元素的列表;obj 表示到添加到列表末尾的数据,它可以是单个元素,也可以是列表、元组等,但不能是单个的数字
extend() 和 append() 的不同之处在于:extend() 不会把列表或者元祖视为一个整体,而是把它们包含的元素逐个添加到列表中
extend()
insert()
修改单个元素
指定步长(step 参数)
修改一组元素
编辑
listname[i]
listname[start : end : step]
正数序列从0开始,负数序列从-1开始
切片起始位不包含在切片范围中
通过索引访问列表中的某个元素
如果该元素不存在,则会导致 ValueError 错误
用来统计某个元素在列表中出现的次数
listname.count(obj)listname 代表列表名,obj 表示要统计的元素。
count()
查找
如果不写 index 参数,默认会删除列表中的最后一个元素
listname.pop(index)
pop()
清空列表
clear()
只会删除第一个和指定值相同的元素,而且必须保证该元素是存在的
remove()
del listname[index]listname 表示列表名称,index 表示元素的索引值。
删除中间一段连续的元素:del listname[start : end]start 表示起始索引,end 表示结束索引。del 会删除从索引 start 到 end 之间的元素,不包括 end 位置的元素。
删除变量时不会删除数据,数据仍储存在内存中
del
回收系统中的无效内存
系统为了提升性能,会将一部分变量驻留在内存中。这个机制对于,多线程并发时程序产生大量占用内存的变量无法得到释放,或者某些不再需要使用的全局变量占用着大的内存,导致后续运行中出现内存不足的情况,此时就可以使用 del 关键字来回收内存,使系统的性能得以提升。同时,它可以为团队省去扩充大量内存的成本。
collect()
快速初始化数字列表
range()
先存入的数据最先取出,即“先进先出”
队列
#定义一个空 list 当做栈 stack = [] stack.append(1) stack.append(2) stack.append(\"hello\") print(stack) print(\"取一个元素:\
最后存入的数据最先取出,即“后进先出”
栈
使用标准库的 collections 模块中的 deque 结构体,它被设计成在两端存入和读取都很快的特殊 list,可以用来实现栈和队列的功能
queueAndStack = deque() queueAndStack.append(1) queueAndStack.append(2) queueAndStack.append(\"hello\") print(list(queueAndStack)) #实现队列功能,从队列中取一个元素,根据先进先出原则,这里应输出 1 print(queueAndStack.popleft()) #实现栈功能,从栈里取一个元素,根据后进先出原则,这里应输出 hello print(queueAndStack.pop()) #再次打印列表 print(list(queueAndStack))
deque
模拟两种数据结构
列表(list)
但小括号不是必须的,只要将各元素用逗号隔开,Python 就会将其视为元组
元组是 tuple 类型
元组是不可变序列,元组中的元素不能被修改
元组的性能速度要优于列表
#将字符串转换成元组 tup1 = tuple(\"hello\
tuple()
新建()
通过=重新赋值一个新的元组
通过+连接两个元组形成一个新元组
元组(tuple)
是 Python 中唯一的映射类型
习惯将各元素对应的索引称为键(key),各个键对应的元素称为值(value),键及其关联的值称为“键值对”
字典特征
一种无序的、可变的序列
同一字典中的各个键必须唯一,不能重复
初始化字典,设置 value 的默认值
dictname = dict.fromkeys(list,value=None)list 参数表示字典中所有键的列表(list);value 参数表示默认值,如果不写,则为空值 None
fromkeys()
创建字典
dict()
新建{ }
dictname[key]dictname 表示字典变量的名字,key 表示键名
get()
判断字典中是否有对应的键
in 或 not in
返回字典中的所有键(key)
keys()
返回字典中所有键对应的值(value)
values()
返回字典中所有的键值对(key-value)
items()
来返回某个 key 对应的 value
当指定的 key 不存在时,setdefault() 会先为这个不存在的 key 设置一个默认的 defaultvalue,然后再返回 defaultvalue
setdefault() 方法总能返回指定 key 对应的 value: 如果该 key 存在,那么直接返回该 key 对应的 value; 如果该 key 不存在,那么先为该 key 设置默认的 defaultvalue,然后再返回该 key 对应的 defaultvalue。
setdefault()
dictname[key] = value dictname 表示字典名称。 key 表示新的键。 value 表示新的值,只要是 Python 支持的数据类型都可以。
添加键值对
一个具有相同键值对的新字典
指的是重新分配一块内存,创建一个新的对象,但里面的元素是原对象中各个子对象的引用
变量赋值
copy.copy() 函数
浅拷贝
重新分配一块内存,创建一个新的对象,并且将原对象中的元素,以递归的方式,通过创建新的子对象拷贝到新对象中
copy.deepcopy()
深拷贝
copy()
使用一个字典所包含的键值对来更新己有的字典
update()
del
删除指定的键值对
dictname.pop(key)dictname.popitem()dictname 表示字典名称,key 表示键。
随机删除一个键值对
popitem()
字典(dict)
同一集合中,只能存储不可变的数据类型,包括整形、浮点型、字符串、元组,无法存储列表、字典、集合这些可变的数据类型
不可以做添加、删除元素的操作
另一种 frozenset 类型的集合
用来保存不重复的元素,即集合中的元素都是唯一的,互不相同
{}赋值
setname = set(iteration)iteration 就表示字符串、列表、元组、range 对象等数据
如果要创建空集合,只能使用 set() 函数实现。因为直接使用一对 {},Python 解释器会将其视为一个空字典
set()
新建{}
for循环语句
setname.add(element)setname 表示要添加元素的集合,element 表示要添加的元素内容
add()
删除元素
setname.remove(element)
如果被删除元素本就不包含在集合中,则此方法会抛出 KeyError 错误
remove()
交集、并集、差集
集合运算
总表
frozenset 集合是不可变序列,程序不能改变序列中的元素
set 集合中所有能改变集合本身的方法,比如 remove()、discard()、add() 等,frozenset 都不支持;set 集合中不改变集合本身的方法,fronzenset 都支持
frozenset集合
集合(set)
集合和字典不支持索引、切片、相加和相乘操作。
数据
variable = [out_exp_res for out_exp in input_list if out_exp == 2]
out_exp_res:列表生成元素表达式,可以是有返回值的函数。 for out_exp in input_list:迭代input_list将out_exp传入out_exp_res表达式中。 if out_exp == 2:根据条件过滤哪些值可以
基本格式
multiples = (i for i in range(30) if i % 3 is 0)print(type(multiples))# Output: <type 'generator'>
使用()生成generator
例
列表推导式/列表生成式
字典推导和列表推导的使用方法是类似的,中括号该改成大括号
大小写key合并
快速更换key和value
字典推导式
集合推导式
推导式
class tortoise: bodyColor = \"绿色\" footNum = 4 weight = 10 hasShell = True #会爬 def crawl(self): print(\"乌龟会爬\") #会吃东西 def eat(self): print(\"乌龟吃东西\") #会睡觉 def sleep(self): print(\"乌龟在睡觉\") #会缩到壳里 def protect(self): print(\"乌龟缩进了壳里\")
比如,前面编写的 tortoise 表示的只是乌龟这个物种,通过它可以创建出无数个实例来代表各种不同特征的乌龟(这一过程又称为类的实例化)。
类:可以理解是一个模板,通过它可以创建出无数个具体实例。
这有点像汽车图纸和汽车的关系,图纸本身(类)并不能为人们使用,通过图纸创建出的一辆辆车(对象)才能使用。
对象:类并不能直接使用,通过类创建出的实例(又称对象)才能使用。
例如,tortoise 这个类中,bodyColor、footNum、weight、hasShell 都是这个类拥有的属性。
属性:类中的所有变量称为属性。
和函数所有不同的是,类方法至少要包含一个 self 参数。例如,tortoise 类中,crawl()、eat()、sleep()、protect() 都是这个类所拥有的方法,类方法无法单独使用,只能和类的对象一起使用。
方法:类中的所有函数通常称为方法。
概要
在创建类对象时,无需给 self 传参
创建类对象的过程,又称为类的实例化
定义在各个类方法之外(包含在类中)的变量为类变量(或者类属性)定义在类方法中的变量为实例变量(或者实例属性)
类变量和实例变量
类名通用习惯为首字母大写
类是模板,而实例则是根据类创建的对象
class 类名: 多个(≥0)类属性... 多个(≥0)类方法...
脑图参考
circle1 = Circle(1) # 创建实例时直接给定实例属性,self不算在内circle2 = Circle(2)print(circle1.r) # 实例名.属性名 访问属性print(circle2.r) # 我们调用实例属性的名称就统一了
class Circle(object): # 创建Circle类,Circle为类名 pass # 此处可添加属性和方法# 创建两个Circle类的实例circle1= Circle()circle2= Circle()# 为circle1、circle2 圆实例添加半径 r 这个属性并赋值circle1.r = 1 # r为实例属性circle2.R= 2 print(circle1.r) # 使用 实例名.属性名 可以访问我们的属性print(circle2.R)
用于区分不同的实例
每次在创建类后,再为实例添加属性会比较麻烦创建实例时给类初始属性,_init__() 方法被自动调用为创建的实例增加实例属性
__init__() 方法可以包含多个参数,但必须包含一个名为 self 的参数,且必须作为第一个参数类的构造方法最少也要有一个 self 参数
__init__() 方法的第一个参数必须是 self(self代表类的实例,可以用别的名字,但建议使用约定成俗的self)后续参数则可以自由指定,和定义函数没有任何区别
self 代表类的实例,是通过类创建的实例
class TheFirstDemo: '''这是一个学习Python定义的第一个类''' #构造方法 def __init__(self): print(\"调用构造方法\
__init__() 方法构造方法(或构造函数)
实例属性
每个实例的共有属性
实例属性访问优先级比类属性高
类体中、所有函数之外:此范围定义的变量,称为类属性或类变量;类体中,所有函数内部:以“self.变量名”的方式定义的变量,称为实例属性或实例变量;类体中,所有函数内部:以“变量名=变量值”的方式定义的变量,称为局部变量
Python 类中如果有属性不希望被外部访问,我们可以在属性命名时以双下划线开头( __ ),那么该属性就不能使用原变量名访问,使得该属性变为本类私有的(伪私有)但,如果一个属性以\"__xxx__\"的形式定义,那么它可以被外部访问。以\"__xxx__\"定义的属性在 Python 的类中是特殊属性有很多预定义的特殊属性都是以“__xxx__”定义,所以我们不要把普通属性用\"__xxx__\" 定义
类属性
实例属性每个实例各自拥有,互相独立,而类属性有且只有一份
表明这个类用是来做什么
实例方法
参数传递图
class 定义类
字段的访问级别:Python中以双下划线开头的字段访问级别是private;Python中以下划线开头的字段访问级别是protected;Python中未以下划线开头的字段的访问级别是public上述访问级别更多的是一种编程约定,即便是以双下划线开头的字段,在类的外部也是可以访问的,但不建议这么做
class Person(): age = 24 _name = 'person' __family_name = 'securate' def __init__(self): print('Person init')
类中的字段
Python类中没有方法的重载,对于具有相同名称的方法,后面的定义会覆盖掉前面的定义;子类会覆盖父类中同名的方法。在Person类中定义两个同名方法say
方法的覆盖
特殊方法以双下划线开头和结尾的方法属于特殊方法,如:__init__(self)、__call__(self)等内置方法。在我们自己定义方法时不建议采取这种方式
方法的访问级别Python中以双下划线开头的方法访问级别是private;Python中以下划线开头的方法访问级别是protected;Python中未以下划线开头的方法的访问级别是public;和字段类似,上述访问级别也只是一种编程约定,即便是以双下划线开头的方法,在类的外部也是可以访问的,但不建议这么做 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
特殊方法
在引用一个对象属性时自定义要完成的工作
描述符是 Python 中复杂属性访问的基础,它在内部被用于实现 property、方法、类方法、静态方法和 super 类型。
描述符
在不破坏类封装原则的前提下,让开发者依旧使用“类对象.属性”的方式操作类中的属性
get 参数用于指定获取该属性值的类方法,fset 参数用于指定设置该属性值的方法,fdel 参数用于指定删除该属性值的方法,最后的 doc 是一个文档字符串,用于说明此函数的作用
在使用 property() 函数时,以上 4 个参数可以仅指定第 1 个、或者前 2 个、或者前 3 个,当前也可以全部指定
property() 函数
直接通过方法名来访问方法,不需要在方法名后添加一对“()”小括号
@propertydef 方法名(self) 代码块
@property 装饰器
删除指定属性
@方法名.deleterdef 方法名(self): 代码块
@area.deleterdef area(self): self.__area = 0 del rect.areaprint(\"删除后的area值为:\
@deleter 装饰器
class People: def say(self): print(\"我是一个人,名字是:\
如果该类没有显式指定继承自哪个类,则默认继承 object 类(object 类是 Python 中所有类的父类,即要么是直接父类,要么是间接父类)。另外,Python 的继承是多继承机制(和 C++ 一样),即一个子类可以同时拥有多个直接父类。
根据子类继承多个父类时这些父类的前后次序决定,即排在前面父类中的类方法会覆盖排在后面父类中的同名类方法
class People: def __init__(self): self.name = People def say(self): print(\"People类\
子类还会继承父类中的函数,若子类没有实现自己的构造函数(__init__(self)),那么在实例化子类时会调用父类的构造函数。
子类
Python 发展至今,经历了以下 3 种 MRO 算法,分别是:从左往右,采用深度优先搜索(DFS)的算法,称为旧式类的 MRO;自 Python 2.2 版本开始,新式类在采用深度优先搜索算法的基础上,对其做了优化;自 Python 2.3 版本,对新式类采用了 C3 算法。由于 Python 3.x 仅支持新式类,所以该版本只使用 C3 算法
方法解析顺序(Method Resolution Order),简称 MRO
鸟通常是有翅膀的,也会飞,因此我们可以像如下这样定义个和鸟相关的类: class Bird: #鸟有翅膀 def isWing(self): print(\"鸟有翅膀\") #鸟会飞 def fly(self): print(\"鸟会飞\")
对于鸵鸟来说,它虽然也属于鸟类,也有翅膀,但是它只会奔跑,并不会飞。针对这种情况,可以这样定义鸵鸟类:class Ostrich(Bird): # 重写Bird类的fly()方法 def fly(self): print(\"鸵鸟不会飞\")
重写,有时又称覆盖,是一个意思,指的是对类中已有方法的内部实现进行修改
类的多态特性,还要满足以下 2 个前提条件:继承:多态一定是发生在子类和父类之间;重写:子类重写了父类的方法。
class CLanguage: def say(self): print(\"调用的是 Clanguage 类的say方法\")class CPython(CLanguage): def say(self): print(\"调用的是 CPython 类的say方法\")class CLinux(CLanguage): def say(self): print(\"调用的是 CLinux 类的say方法\")a = CLanguage()a.say()a = CPython()a.say()a = CLinux()a.say()
通过给 WhoSay 类中的 say() 函数添加一个 who 参数,其内部利用传入的 who 调用 say() 方法。这意味着,当调用 WhoSay 类中的 say() 方法时,我们传给 who 参数的是哪个类的实例对象,它就会调用那个类中的 say() 方法。 Python 这种由多态衍生出的更灵活的编程机制,又称为“鸭子模型”或“鸭子类型”
父类方法重写
自定义一个新类,使其继承有类似行为的内置类,通过重定义这个新类实现指定的功能
list 类型用来管理序列,如果一个类需要在内部处理序列,那么就可以对 list 进行子类化
内置类型子类化
子类中的构造方法中,调用父类构造方法的方式有 2 种,分别是:类可以看做一个独立空间,在类的外部调用其中的实例方法,可以向调用普通函数那样,只不过需要额外备注类名(此方式又称为未绑定方法);使用 super() 函数。但如果涉及多继承,该函数只能调用第一个直接父类的构造方法
尽可能避免使用多继承,可以使用一些设计模式来替代它;super 的使用必须一致,即在类的层次结构中,要么全部使用 super,要么全不用。混用 super 和传统调用是一种混乱的写法;如果代码需要兼容 Python 2.x,在 Python 3.x 中应该显式地继承自 object。在 Python 2.x 中,没有指定任何祖先地类都被认定为旧式类。调用父类时应提前查看类的层次结构,也就是使用类的 __mro__ 属性或者 mro() 方法查看有关类的 MRO
super()函数调用父类的构造方法
type()函数动态创建类
MetaClass元类
from enum import Enumclass Color(Enum): # 为序列值指定value值 red = 1 green = 2 blue = 3
Enum 枚举类
一种负责创建类实例的静态方法,它无需使用 staticmethod 装饰器修饰,且该方法会优先 __init__() 初始化方法被调用
__new__()
class CLanguage: def __init__(self): self.name = \"C语言中文网\" self.add = \"http://c.biancheng.net\" def __repr__(self): return \"CLanguage[name=\"+ self.name +\
__repr__()方法显示属性
如果之前创建的类实例化对象后续不再使用,最好在适当位置手动将其销毁,释放其占用的内存空间(整个过程称为垃圾回收(简称GC))
Python 采用自动引用计数(简称 ARC)的方式实现垃圾回收机制。该方法的核心思想是:每个 Python 对象都会配置一个计数器,初始 Python 实例对象的计数器值都为 0,如果有变量引用该实例对象,其计数器的值会加 1,依次类推;反之,每当一个变量取消对该实例对象的引用,计数器会减 1。如果一个 Python 对象的的计数器值为 0,则表明没有变量引用该 Python 对象,即证明程序不再需要它,此时 Python 就会自动调用 __del__() 方法将其回收。
__del__()方法销毁对象
通过此函数可以某个对象拥有的所有的属性名和方法名,该函数会返回一个包含有所有属性名和方法名的有序列表
__dir__()用法列出对象的所有属性(方法)名
该属性可以用类名或者类的实例对象来调用,用类名直接调用 __dict__,会输出该由类中所有类属性组成的字典而使用类的实例对象调用 __dict__,会输出由类中所有实例属性组成的字典
class CLanguage: a = 1 b = 2 def __init__ (self): self.name = \"C语言中文网\" self.add = \"http://c.biancheng.net\" class CL(CLanguage): c = 1 d = 2 def __init__ (self): self.na = \"Python教程\" self.ad = \"http://c.biancheng.net/python\"#父类名调用__dict__print(CLanguage.__dict__)#子类名调用__dict__print(CL.__dict__)#父类实例对象调用 __dict__clangs = CLanguage()print(clangs.__dict__)#子类实例对象调用 __dict__cl = CL()print(cl.__dict__)
对于具有继承关系的父类和子类来说,父类有自己的 __dict__,同样子类也有自己的 __dict__,它不会包含父类的 __dict__
借助由类实例对象调用 __dict__ 属性获取的字典,可以使用字典的方式对其中实例属性的值进行修改
class CLanguage: a = \"aaa\" b = 2 def __init__ (self): self.name = \"C语言中文网\" self.add = \"http://c.biancheng.net\"#通过类实例对象调用 __dict__clangs = CLanguage()print(clangs.__dict__)clangs.__dict__['name'] = \"Python教程\"print(clangs.name)
__dict__属性查看对象内部所有属性名和属性值组成的字典
判断某个类实例对象是否包含指定名称的属性或方法
class CLanguage: def __init__ (self): self.name = \"C语言中文网\" self.add = \"http://c.biancheng.net\" def say(self): print(\"我正在学Python\
setattr()
获取某个类实例对象中指定属性的值
对于类中已有的属性,getattr() 会返回它们的值,而如果该名称为方法名,则返回该方法的状态信息;反之,如果该明白不为类对象所有,要么返回默认的参数,要么程序报 AttributeError 错误
getattr()
功能相对比较复杂,它最基础的功能是修改类实例对象中的属性值。其次,它还可以实现为实例对象动态添加属性或者方法
def say(self): print(\"我正在学Python\")class CLanguage: def __init__ (self): self.name = \"C语言中文网\" self.add = \"http://c.biancheng.net\
利用 setattr() 函数,还可以将类属性修改为一个类方法,同样也可以将类方法修改成一个类属性
def say(self): print(\"我正在学Python\
使用 setattr() 函数对实例对象中执行名称的属性或方法进行修改时,如果该名称查找失败,Python 解释器不会报错,而是会给该实例对象动态添加一个指定名称的属性或方法
hasattr()
# 定义一个字符串hello = \"Hello\";# \"Hello\"是str类的实例,输出Trueprint('\"Hello\
issubclass() 和 isinstance() 两个函数的用法差不多,区别只是 issubclass() 的第一个参数是类名,而 isinstance() 的第一个参数是变量,这也与两个函数的意义对应:issubclass 用于判断是否为子类,而 isinstance() 用于判断是否为该类或子类的实例
issubclass() 和 isinstance() 两个函数的第二个参数都可使用元组
Python 为所有类都提供了一个 __bases__ 属性,通过该属性可以查看该类的所有直接父类,该属性返回所有直接父类组成的元组
检查类型
该方法的功能类似于在类中重载 () 运算符,使得类实例对象可以像调用普通函数那样,以“对象名()”的形式使用
Python 中,凡是可以将 () 直接应用到自身并执行,都称为可调用对象。可调用对象包括自定义的函数、Python 内置函数以及本节所讲的类实例对象。
__call__()方法
在类中定义并实现一个与运算符对应的处理方法,这样当类对象在进行运算符操作时,系统就会调用类中相应的方法来处理
在 Python 内部,每种序列类型都是 Python 的一个类,例如列表是 list 类,字典是 dict 类等,这些序列类的内部使用了一个叫作“重载运算符”的技术来实现不同运算符所对应的操作
常用重载运算符
运算符重载
列表(list)、元组(tuple)、字典(dict)、集合(set)序列式容器有一个共同的特性它们都支持使用 for 循环遍历存储的元素,都是可迭代的因此它们又有一个别称,即迭代器
如果要自定义实现一个迭代器,则类中必须实现如下 2 个方法:__next__(self):返回容器的下一个元素。__iter__(self):该方法返回一个迭代器(iterator)
可调用对象,指的是该类的实例对象可以像函数那样,直接以“对象名()”的形式被使用。通过在类中添加 __call__() 方法,就可以将该类的实例对象编程可调用对象
iter() 函数第 2 个参数如果使用该参数,则要求第一个 obj 参数必须传入可调用对象(可以不支持迭代)当使用返回的迭代器调用 __next__() 方法时,它会通过执行 obj() 调用 __call__() 方法如果该方法的返回值和第 2 个参数值相同,则输出 StopInteration 异常;反之,则输出 __call__() 方法的返回值
编写迭代器最容易忽视的一个环节,就是在自定义类中加入对循环结束的判断,并抛出 StopIteration 异常只有这么做了,for 循环才会接收到 StopIteration 异常,并当做终止信号来结束循环
iter() 函数
迭代器
生成器本质上也是迭代器,不过它比较特殊。以 list 容器为例,在使用该容器迭代一组数据时,必须事先将所有数据存储到容器中,才能开始迭代;而生成器却不同,它可以实现在迭代的同时生成元素。也就是说,对于可以用某种算法推算得到的多个数据,生成器并不会一次性生成它们,而是什么时候需要,才什么时候生成。不仅如此,生成器的创建方式也比迭代器简单很多,大体分为以下 2 步:定义一个以 yield 关键字标识返回值的函数调用刚刚创建的函数,即可创建一个生成器
def intNum(): print(\"开始执行\") for i in range(5): yield i print(\"继续执行\")num = intNum()
intNum() 函数的返回值用的是 yield 关键字,而不是 return 关键字,此类函数又成为生成器函数。和 return 相比,yield 除了可以返回相应的值,还有一个更重要的功能,即每当程序执行完该语句时,程序就会暂停执行。不仅如此,即便调用生成器函数,Python 解释器也不会执行函数中的代码,它只会返回一个生成器(对象)。要想使生成器函数得以执行,或者想使执行完 yield 语句立即暂停的程序得以继续执行,有以下 2 种方式:通过生成器(上面程序中的 num)调用 next() 内置函数或者 __next__() 方法;通过 for 循环遍历生成器。
分析一个程序的执行流程:1) 首先,在创建有 num 生成器的前提下,通过其调用 next() 内置函数,会使 Python 解释器开始执行 intNum() 生成器函数中的代码,因此会输出“开始执行”,程序会一直执行到yield i,而此时的 i==0,因此 Python 解释器输出“0”。由于受到 yield 的影响,程序会在此处暂停。2) 然后,我们使用 num 生成器调用 __next__() 方法,该方法的作用和 next() 函数完全相同(事实上,next() 函数的底层执行的也是 __next__() 方法),它会是程序继续执行,即输出“继续执行”,程序又会执行到yield i,此时 i==1,因此输出“1”,然后程序暂停。3) 最后,我们使用 for 循环遍历 num 生成器,之所以能这么做,是因为 for 循环底层会不断地调用 next() 函数,使暂停的程序继续执行,因此会输出后续的结果
#调用 next() 内置函数print(next(num))#调用 __next__() 方法print(num.__next__())#通过for循环遍历生成器for i in num: print(i)
def intNum(): print(\"开始执行\") for i in range(5): yield i print(\"继续执行\")num = intNum()print(num.send(None))print(num.send(None))
通过调用 next() 或者 __next__() 方法,可以实现从外界控制生成器的执行。除此之外,通过 send() 方法,还可以向生成器中传值。值得一提的是,send() 方法可带一个参数,也可以不带任何参数(用 None 表示)。其中,当使用不带参数的 send() 方法时,它和 next() 函数的功能完全相同
虽然 send(None) 的功能是 next() 完全相同,但更推荐使用 next(),不推荐使用 send(None)
此程序的执行流程:1) 首先,构建生成器函数,并利用器创建生成器(对象)f 。2) 使用生成器 f 调用无参的 send() 函数,其功能和 next() 函数完全相同,因此开始执行生成器函数,即执行到第一个 yield \"hello\" 语句,该语句会返回 \"hello\" 字符串,然后程序停止到此处(注意,此时还未执行对 bar_a 的赋值操作)。3) 下面开始使用生成器 f 调用有参的 send() 函数,首先它会将暂停的程序开启,同时还会将其参数“C语言中文网”赋值给当前 yield 语句的接收者,也就是 bar_a 变量。程序一直执行完 yield bar_a 再次暂停,因此会输出“C语言中文网”。4) 最后依旧是调用有参的 send() 函数,同样它会启动餐厅的程序,同时将参数“http://c.biancheng.net”传给 bar_b,然后执行完 yield bar_b 后(输出 http://c.biancheng.net),程序执行再次暂停。
def foo(): bar_a = yield \"hello\" bar_b = yield bar_a yield bar_bf = foo()print(f.send(None))print(f.send(\"C语言中文网\"))print(f.send(\"http://c.biancheng.net\"))
send()
当程序在生成器函数中遇到 yield 语句暂停运行时,此时如果调用 close() 方法,会阻止生成器函数继续执行,该函数会在程序停止运行的位置抛出 GeneratorExit 异常
def foo(): try: yield 1 except GeneratorExit: print('捕获到 GeneratorExit')f = foo()print(next(f))f.close()
虽然通过捕获 GeneratorExit 异常,可以继续执行生成器函数中剩余的代码,带这部分代码中不能再包含 yield 语句,否则程序会抛出 RuntimeError 异常
def foo(): try: yield 1 except GeneratorExit: print('捕获到 GeneratorExit') yield 2 #抛出 RuntimeError 异常f = foo()print(next(f))f.close()
生成器函数一旦使用 close() 函数停止运行,后续将无法再调用 next() 函数或者 __next__() 方法启动执行,否则会抛出 StopIteration 异常
def foo(): yield \"c.biancheng.net\" print(\"生成器停止执行\")f = foo()print(next(f)) #输出 \"c.biancheng.net\"f.close()next(f) #原本应输出\"生成器停止执行\"
close()
在生成器函数执行暂停处,抛出一个指定的异常,之后程序会继续执行生成器函数中后续的代码,直到遇到下一个 yield 语句。需要注意的是,如果到剩余代码执行完毕没有遇到下一个 yield 语句,则程序会抛出 StopIteration 异常。
def foo(): try: yield 1 except ValueError: print('捕获到 ValueError')f = foo()print(next(f))f.throw(ValueError)
throw()
yield
函数装饰器,就是通过装饰器函数,在不修改原函数的前提下,来对函数的功能进行合理的扩充。
#funA 作为装饰器函数def funA(fn): #... fn() # 执行传入的fn参数 #... return '...'@funAdef funB(): #...
使用函数装饰器 A() 去装饰另一个函数 B(),其底层执行了如下 2 步操作:将 B 作为参数传给 A() 函数;将 A() 函数执行完成的返回值反馈回 B
用 funA() 函数装饰器去装饰 funB() 函数
@funA@funB@funCdef fun(): #...上面程序的执行顺序是里到外,所以它等效于下面这行代码:fun = funA( funB ( funC (fun) ) )
@函数装饰器
生成器
类和对象
语法错误,也就是解析代码时出现的错误。当代码不符合 Python 语法规则时,Python解释器在解析时就会报出 SyntaxError 语法错误,与此同时还会明确指出最早探测到错误的语句。
语法错误
序在语法上都是正确的,但在运行时发生了错误
AssertionError\t当 assert 关键字后的条件为假时,程序运行会停止并抛出 AssertionError 异常\tAttributeError\t当试图访问的对象属性不存在时抛出的异常\tIndexError\t索引超出序列范围会引发此异常\tKeyError\t字典中查找一个不存在的关键字时引发此异常\tNameError\t尝试访问一个未声明的变量时,引发此异常\tTypeError\t 不同类型数据之间的无效操作\tZeroDivisionError\t除法运算中除数为 0 引发此异常
异常(Exceptions)运行时错误
常见异常情况
异常情况类型
首先执行 try 中的代码块,如果执行过程中出现异常,系统会自动生成一个异常类型,并将该异常提交给 Python 解释器,此过程称为捕获异常。当 Python 解释器收到异常对象时,会寻找能处理该异常对象的 except 块,如果找到合适的 except 块,则把该异常对象交给该 except 块处理,这个过程被称为处理异常。如果 Python 解释器找不到处理异常的 except 块,则程序运行终止,Python 解释器也将退出。
try except 语句的执行流程
try: 1/0except Exception as e: # 访问异常的错误编号和详细信息 print(e.args) print(str(e)) print(repr(e))
每种异常类型都提供了如下几个属性和方法,通过调用它们,就可以获取当前处理异常类型的相关信息:args:返回异常的错误编号和描述字符串;str(e):返回异常信息,但不包括异常信息的类型;repr(e):返回较全的异常信息,包括异常信息的类型
异常处理机制还提供了一个 else 块,也就是原有 try except 语句的基础上再添加一个 else 块,即try except else结构。使用 else 包裹的代码,只有当 try 块没有捕获到任何异常时,才会得到执行;反之,如果 try 块捕获到异常,即便调用对应的 except 处理完异常,else 块中的代码也不会得到执行
else
异常处理机制还提供了一个 finally 语句,通常用来为 try 块中的程序做扫尾清理工作。注意,和 else 语句不同,finally 只要求和 try 搭配使用,而至于该结构中是否包含 except 以及 else,对于 finally 不是必须的(else 必须和 try except 搭配使用)。在整个异常处理机制中,finally 语句的功能是:无论 try 块是否发生异常,最终都要进入 finally 语句,并执行其中的代码块。当 try 块中的程序打开了一些物理资源(文件、数据库连接等)时,由于这些资源必须手动回收,而回收工作通常就放在 finally 块中。Python 垃圾回收机制,只能帮我们回收变量、类对象占用的内存,而无法自动完成类似关闭文件、数据库连接等这些的工作。
try: a = int(input(\"请输入 a 的值:\")) print(20/a)except: print(\"发生异常!\")else: print(\"执行 else 块中的代码\") finally : print(\"执行 finally 块中的代码\")
当 try 块中代码发生异常,导致程序崩溃时,在崩溃前 Python 解释器也会执行 finally 块中的代码
如果在 finally 块里也使用了 return 或 raise 等导致方法中止的语句,finally 块己经中止了方法,系统将不会跳回去执行 try 块、except 块里的任何代码尽量避免在 finally 块里使用 return 或 raise 等导致方法中止的语句,否则可能出现一些很奇怪的情况
finally
通过在 try 块中判断用户的输入数据是否合理,如果不合理,程序受 raise 的影响会进行到 except 代码块,对用户的错误输出进行处理,然后会继续执行正常的业务代码;反之,如果用户输入合理,那么程序将直接执行正常的业务代码。try except 是 Python 实现异常处理机制的核心结构
try: if(用户输入不合理): raise 异常except Exception: alert 输入不合法 goto retry#正常的业务代码
try: a = int(input(\"输入被除数:\")) b = int(input(\"输入除数:\")) c = a / b print(\"您输入的两个数相除的结果是:\
对于 try 块中可能出现的任何异常,Python 解释器都会交给仅有的这个 except 块处理因为它的参数是 Exception,表示可以接收任何类型的异常
try: #...except Exception: #...
根据用户输入 a 和 b 值的不同,可能会导致 ValueError、ArithmeticError 异常:如果用户输入的 a 或者 b 是其他字符,而不是数字,会发生 ValueError 异常,try 块会捕获到该类型异常,同时 Python 解释器会调用第一个 except 块处理异常;如果用户输入的 a 和 b 是数字,但 b 的值为 0,由于在进行除法运算时除数不能为 0,因此会发生 ArithmeticError 异常,try 块会捕获该异常,同时 Python 解释器会调用第二个 except 块处理异常;当然,程序运行过程中,还可能由于其他因素出现异常,try 块都可以捕获,同时 Python 会调用最后一个 except 块来处理。
try: a = int(input(\"输入 a:\")) b = int(input(\"输入 b:\")) print( a/b )except ValueError: print(\"数值错误:程序只能接收整数参数\")except ArithmeticError: print(\"算术错误\")except Exception: print(\"未知异常\")
try except异常处理 示例
raise [exceptionName [(reason)]]其中,用 [] 括起来的为可选参数,其作用是指定抛出的异常名称,以及异常信息的相关描述。如果可选参数全部省略,则 raise 会把当前错误原样抛出;如果仅省略 (reason),则在抛出异常时,将不附带任何的异常描述信息。
raise 语句有如下三种常用的用法:raise:单独一个 raise。该语句引发当前上下文中捕获的异常(比如在 except 块中),或默认引发 RuntimeError 异常。raise 异常类名称:raise 后带一个异常类名称,表示引发执行类型的异常。raise 异常类名称(描述信息):在引发指定类型的异常的同时,附带异常的描述信息。
try: a = input(\"输入一个数:\") #判断用户输入的是否为数字 if(not a.isdigit()): raise ValueError(\"a 必须是数字\")except ValueError as e: print(\"引发异常:\
raise手动引发的异常
捕获异常时,有 2 种方式可获得更多的异常信息,分别是:使用 sys 模块中的 exc_info 方法;使用 traceback 模块中的相关函数。
exc_info() 方法会将当前的异常信息以元组的形式返回该元组中包含 3 个元素,分别为 type、value 和 traceback,它们的含义分别是:type:异常类型的名称,它是 BaseException 的子类value:捕获到的异常实例。traceback:是一个 traceback 对象。
sys.exc_info()方法获取异常信息
class SelfExceptionError(Exception): passtry: raise SelfExceptionError()except SelfExceptionError as err: print(\"捕捉到自定义异常\")
自定义异常类型
logging日志级别
在调试完程序后,可能并不希望所有这些日志消息出现在屏幕上,这时就可以使用 logging.disable() 函数禁用这些日志消息,从而不必进入到程序中,手工删除所有的日志调用
logging.disable() 函数的用法是,向其传入一个日志级别,它会禁止该级别以及更低级别的所有日志消息。因此,如果想要禁用所有日志,只要在程序中添加 logging.disable(logging.CRITICAL) 即可
logging.disable()
IDLE 调试程序
assert 可以和 try except 异常处理语句配合使用:纯文本复制try: s_age = input(\"请输入您的年龄:\
当在命令行模式运行 Python 程序时,传入 -O(注意是大写)参数,可以禁用程序中包含的 assert 语句。
异常处理机制
Python
0 条评论
回复 删除
下一页