python学习笔记
2021-08-24 10:25:50 0 举报
AI智能生成
python快速入门,一张图看懂如何写python
作者其他创作
大纲/内容
基础命令<br>
print()
“ ”
' '
''' ‘''<br>
多行自动换行
,<br>
英文逗号<br>
在print命令中输入多个变量
输出时默认为空格间隔
sep=' '
指定间隔符
end=" "
默认\n,换行<br>
通过end参数定义更换print输出完成后
file=
输出目标指定,默认值为 sys.stdout输出到屏幕
先将文件打开,变量赋值后,即可写入文件
flush
用于控制输出缓存,该参数一般保持默认 False 即可
%
转换说明符(Conversion Specifier)
实例 :<br>age = 8<br> print("C语言中文网已经%d岁了!" % age)<br>
实例:<br> name = "C语言中文网"<br> age = 8<br> url = "http://c.biancheng.net/"<br> print("%s已经%d岁了,它的网址是%s。" % (name, age, url))
指定最小输出宽度
%10d 表示输出的整数宽度至少为 10
对于整数和字符串,当数据的实际宽度小于指定宽度时,会默认在左侧以空格补齐;当数据的实际宽度大于指定宽度时,会按照数据的实际宽度输出。
指定对齐方式
Python 允许在最小宽度之前增加一个标志来改变对齐方式
子主题
实例:<br>n = 123456<br> # %09d 表示最小宽度为9,左边补0<br> print("n(09):%09d" % n)<br> # %+9d 表示最小宽度为9,带上符号<br> print("n(+9):%+9d" % n)<br> f = 140.5<br> # %-+010f 表示最小宽度为10,左对齐,带上符号<br> print("f(-+0):%-+010f" % f)<br> s = "Hello"<br> # %-10s 表示最小宽度为10,左对齐<br> print("s(-10):%-10s." % s)<br>
指定小数精度
精度值需要放在最小宽度之后,中间用点号.隔开;也可以不写最小宽度,只写精度。
%m.nf<br>%.nf<br>m 表示最小宽度,n 表示输出精度,.是必须存在的。
实例:<br> f = 3.141592653<br> # 最小宽度为8,小数点后保留3位<br> print("%8.3f" % f)<br> # 最小宽度为8,小数点后保留3位,左边补0<br> print("%08.3f" % f)<br> # 最小宽度为8,小数点后保留3位,左边补0,带符号<br> print("%+08.3f" % f)
#
单行注释<br>
''' '''<br>
多行注释<br>
_<br>
数字分隔符
作为数字(包括整数和小数)的分隔符
提高数字的的可读性
通常每隔三个数字添加一个下划线,类似于英文数字中的逗号。下划线不会影响数字本身的值。
input()
从控制台读取用户输入的内容
input(显示在控制台的提示信息)
以字符串的形式来处理用户输入的内容
\ 转义字符<br>
<br>
\n在输出时换行,\在书写字符串时换行
算术运算符
常用算术运算符
当+用于数字时表示加法,但是当+用于字符串时,它还有拼接字符串(将两个字符串连接为一个)的作用
*除了可以用作乘法运算,还可以用来重复字符串
实例<br>str1 = "hello "<br>print(str1 * 4)<br>
求余结果的正负和第一个数字没有关系,只由第二个数字决定
两边的数字都是整数时,求余的结果也是整数;但是只要有一个数字是小数,求余的结果就是小数。
开方运算
实例:<br>print('81**(1/4) =', 81**(1/4))<br>print('32**(1/5) =', 32**(1/5))
= 赋值运算符
== 用来判断两边的值是否相等
扩展赋值运算符
位运算符
比较运算符(关系运算符)
比较运算符汇总
is 用来比对两个变量引用的是否是同一个对象
两个对象的内存地址相同,说明两个对象使用的是同一块内存,就是同一个对象
逻辑运算符<br>
逻辑运算符
and 和 or 不一定会计算右边表达式的值,有时候只计算左边表达式的值就能得到最终结果
and 和 or 运算符会将其中一个表达式的值作为最终结果,而不是将 True 或者 False 作为最终结果
对于 and 运算符,两边的值都为真时最终结果才为真,但是只要其中有一个值为假,那么最终结果就是假,所以 Python 按照下面的规则执行 and 运算:<br> 如果左边表达式的值为假,那么就不用计算右边表达式的值了,因为不管右边表达式的值是什么,都不会影响最终结果,最终结果都是假,此时 and 会把左边表达式的值作为最终结果。<br> 如果左边表达式的值为真,那么最终值是不能确定的,and 会继续计算右边表达式的值,并将右边表达式的值作为最终结果。<br><br>对于 or 运算符,情况是类似的,两边的值都为假时最终结果才为假,只要其中有一个值为真,那么最终结果就是真,所以 Python 按照下面的规则执行 or 运算:<br> 如果左边表达式的值为真,那么就不用计算右边表达式的值了,因为不管右边表达式的值是什么,都不会影响最终结果,最终结果都是真,此时 or 会把左边表达式的值作为最终结果。<br> 如果左边表达式的值为假,那么最终值是不能确定的,or 会继续计算右边表达式的值,并将右边表达式的值作为最终结果。<br>
三目运算符(三元运算符)
使用 if else 实现三目运算符(条件运算符)的格式如下:<br><br>exp1 if contion else exp2<br>condition 是判断条件,exp1 和 exp2 是两个表达式。如果 condition 成立(结果为真),就执行 exp1,并把 exp1 的结果作为整个表达式的结果;如果 condition 不成立(结果为假),就执行 exp2,并把 exp2 的结果作为整个表达式的结果。<br><br>前面的语句max = a if a>b else b的含义是:<br><br> 如果 a>b 成立,就把 a 作为整个表达式的值,并赋给变量 max;<br> 如果 a> b 不成立,就把 b 作为整个表达式的值,并赋给变量 max。<br>
计算优先级
应尽量使用( )来控制表达式的执行顺序
当一个表达式中出现多个运算符时,Python 会先比较各个运算符的优先级,按照优先级从高到低的顺序依次执行;当遇到优先级相同的运算符时,再根据结合性决定先执行哪个运算符:如果是左结合性就先执行左边的运算符,如果是右结合性就先执行右边的运算符。
常量 None<br>(N 必须大写)<br>
它不表示 0,也不表示空字符串,而表示没有值,也就是空值
>>> type(None)<br><class 'NoneType'>
流程控制
选择/分支结构 <br> if else 语句
if 语句
<br>
if else 语句
<br>
if elif else 语句
<br>
注意<br>
Python 是以缩进来标记代码块的<br>代码块一定要有缩进,没有缩进的不是代码块<br>另外,同一个代码块的缩进量要相同,缩进量不同的不属于同一个代码块
if、elif、else 语句的最后都有冒号:
Python 会把 True 当做“真”,把 False 当做“假”<br>对于数字,Python 会把 0 和 0.0 当做“假”,把其它值当做“真”<br>对于其它类型,当对象为空或者为 None 时,Python 会把它们当做“假”,其它情况当做真。
b = False<br> if b:<br> print('b是True')<br> else:<br> print('b是False')<br> n = 0<br> if n:<br> print('n不是零值')<br> else:<br> print('n是零值')<br> s = ""<br> if s:<br> print('s不是空字符串')<br> else:<br> print('s是空字符串')<br> l = []<br> if l:<br> print('l不是空列表')<br> else:<br> print('l是空列表')<br> d = {}<br> if d:<br> print('d不是空字典')<br> else:<br> print('d是空字典')<br> def func():<br> print("函数被调用")<br> if func():<br> print('func()返回值不是空')<br> else:<br> print('func()返回值为空')
pass
pass 是 Python 中的关键字,用来让解释器跳过此处,什么都不做
assert<br>断言函数
能缩小版的 if 语句<br>它用于判断某个表达式的值,如果值为真,则程序可以继续往下执行<br>反之,Python 解释器会报 AssertionError 错误
assert 表达式
首先判断条件表达式的值,其值为真(True)时,则执行代码块中的语句<br>当执行完毕后,再回过头来重新判断条件表达式的值是否为真<br>若仍为真,则继续重新执行代码块...如此循环<br>直到条件表达式的值为假(False),才终止循环
循环结构<br>
while 循环
<br>
my_char="http://c.biancheng.net/python/"<br> i = 0;<br> while i<len(my_char):<br> print(my_char[i],end="")<br> i = i + 1
for 循环
<br>
my_list = [1,2,3,4,5]<br> for ele in my_list:<br> print('ele =', ele)
else 代码块
当循环条件为 False 跳出循环时,程序会最先执行 else 代码块中的代码
嵌套循环
当 2 个(甚至多个)循环结构相互嵌套时<br>位于外层的循环结构常简称为外层循环或外循环<br>位于内层的循环结构常简称为内层循环或内循环
当外层循环条件为 True 时,则执行外层循环结构中的循环体;<br> 外层循环体中包含了普通程序和内循环,当内层循环的循环条件为 True 时会执行此循环中的循环体<br>直到内层循环条件为 False,跳出内循环<br>如果此时外层循环的条件仍为 True,则返回第 2 步,继续执行外层循环体,直到外层循环的循环条件为 False;<br> 当内层循环的循环条件为 False,且外层循环的循环条件也为 False,则整个嵌套循环才算执行完毕。<br>
使用 for 循环实现用冒泡排序算法
data = [5,8,4,1]<br> #实现冒泡排序<br> for i in range(len(data)-1):<br> for j in range(len(data)-i-1):<br> if(data[j]>data[j+1]):<br> data[j],data[j+1] = data[j+1],data[j]<br> print("排序后:",data)
终止循环<br>break
add = "http://c.biancheng.net/python/,http://c.biancheng.net/shell/"<br> # 一个简单的for循环<br> for i in add:<br> if i == ',' :<br> #终止循环<br> break<br> print(i,end="")<br> print("\n执行循环体外的代码")
for 循环后也可以配备一个 else 语句。这种情况下,如果使用 break 语句跳出循环体,不会执行 else 中包含的代码
借用一个 bool 类型的变量,同时跳出内层循环和外层循环:
add = "http://c.biancheng.net/python/,http://c.biancheng.net/shell/"<br> #提前定义一个 bool 变量,并为其赋初值<br> flag = False<br> for i in range(3):<br> for j in add:<br> if j == ',':<br> #在 break 前,修改 flag 的值<br> flag = True<br> break <br> print(j,end="")<br> print("\n跳出内循环")<br> #在外层循环体中再次使用 break<br> if flag == True:<br> print("跳出外层循环")<br> break
终止执行本次循环,下一次循环继续执行<br>continue
函数<br>
函数就是一段封装好的,可以重复使用的代码,它使得我们的程序更加模块化,不需要编写大量重复的代码。<br>函数可以提前保存起来,并给它起一个独一无二的名字,只要知道它的名字就能使用这段代码。<br>函数还可以接收数据,并根据数据的不同做出不同的操作,最后再把处理结果反馈给我们。
内置函数
压缩<br>zip()
zip(iterable, ...)<br> iterable,... 表示多个列表、元组、字典、集合、字符串,甚至还可以为 range() 区间
my_list = [11,12,13]<br> my_tuple = (21,22,23)<br> print([x for x in zip(my_list,my_tuple)])<br> my_dic = {31:2,32:4,33:5}<br> my_set = {41,42,43,44}<br> print([x for x in zip(my_dic)])<br> my_pychar = "python"<br> my_shechar = "shell"<br> print([x for x in zip(my_pychar,my_shechar)])
reserved()<br>逆序<br>
对于给定的序列(包括列表、元组、字符串以及 range(n) 区间),该函数可以返回一个逆序序列的迭代器(用于遍历该逆序序列)
reversed(seq)<br>seq 可以是列表,元素,字符串以及 range() 生成的区间列表
sorted()<br>排序
list = sorted(iterable, key=None, reverse=False) <br>iterable 表示指定的序列<br>key 参数可以自定义排序规则<br>reverse 参数指定以升序(False,默认)还是降序(True)进行排序<br>sorted() 函数会返回一个排好序的列表<br>key 参数和 reverse 参数是可选参数
#对列表进行排序<br> a = [5,3,4,2,1]<br> print(sorted(a))<br> #对元组进行排序<br> a = (5,4,3,1,2)<br> print(sorted(a))<br> #字典默认按照key进行排序<br> a = {4:1,\<br> 5:2,\<br> 3:3,\<br> 2:6,\<br> 1:8}<br> print(sorted(a.items()))<br> #对集合进行排序<br> a = {1,5,3,2,4}<br> print(sorted(a))<br> #对字符串进行排序<br> a = "51423"<br> print(sorted(a))
#对列表进行排序<br> a = [5,3,4,2,1]<br> print(sorted(a,reverse=True))
chars=['http://c.biancheng.net',\<br> 'http://c.biancheng.net/python/',\<br> 'http://c.biancheng.net/shell/',\<br> 'http://c.biancheng.net/java/',\<br> 'http://c.biancheng.net/golang/']<br> #默认排序<br> print(sorted(chars))<br> #自定义按照字符串长度排序<br> print(sorted(chars,key=lambda x:len(x)))
eval()<br>执行并返回
可以执行一个字符串形式的 Python 代码(代码以字符串的形式提供),相当于一个 Python 的解释器
eval(source, globals=None, locals=None, /)
expression:这个参数是一个字符串,代表要执行的语句 。该语句受后面两个字典类型参数 globals 和 locals 的限制,只有在 globals 字典和 locals 字典作用域内的函数和变量才能被执行。<br>globals:这个参数管控的是一个全局的命名空间,即 expression 可以使用全局命名空间中的函数。如果只是提供了 globals 参数,而没有提供自定义的 __builtins__,则系统会将当前环境中的 __builtins__ 复制到自己提供的 globals 中,然后才会进行计算;如果连 globals 这个参数都没有被提供,则使用 Python 的全局命名空间。<br>locals:这个参数管控的是一个局部的命名空间,和 globals 类似,当它和 globals 中有重复或冲突时,以 locals 的为准。如果 locals 没有被提供,则默认为 globals。
a = 1<br>exec("a = 2") #相当于直接执行 a=2<br>print(a)<br>a = exec("2+3") #相当于直接执行 2+3,但是并没有返回值,a 应为 None<br>print(a)<br>a = eval('2+3') #执行 2+3,并把结果返回给 a<br>print(a)
在编写代码时,一般会使 repr() 数来生成动态的字符串,再传入到 eval() 或 exec() 函数内,实现动态执行代码的功能
exec() <br>执行
可以执行一个字符串形式的 Python 代码(代码以字符串的形式提供),相当于一个 Python 的解释器
exec(source, globals=None, locals=None, /)<br>
expression:这个参数是一个字符串,代表要执行的语句 。该语句受后面两个字典类型参数 globals 和 locals 的限制,只有在 globals 字典和 locals 字典作用域内的函数和变量才能被执行。<br>globals:这个参数管控的是一个全局的命名空间,即 expression 可以使用全局命名空间中的函数。如果只是提供了 globals 参数,而没有提供自定义的 __builtins__,则系统会将当前环境中的 __builtins__ 复制到自己提供的 globals 中,然后才会进行计算;如果连 globals 这个参数都没有被提供,则使用 Python 的全局命名空间。<br>locals:这个参数管控的是一个局部的命名空间,和 globals 类似,当它和 globals 中有重复或冲突时,以 locals 的为准。如果 locals 没有被提供,则默认为 globals。
执行后不返回结果
自定义函数<br>def
def 函数名(参数列表):<br> //实现特定功能的多行代码<br> [return [返回值]]
函数名:其实就是一个符合 Python 语法的标识符
形参列表:设置该函数可以接收多少个参数,多个参数之间用逗号( , )分隔
#定义一个比较字符串大小的函数<br>def str_max(str1,str2):<br> str = str1 if str1 > str2 else str2<br> return str
#自定义 len() 函数<br>def my_len(str):<br> length = 0<br> for c in str:<br> length = length + 1<br> return length
默认值参数
def 函数名(...,形参名,形参名=默认值):<br> 代码块
指定有默认值的形式参数必须在所有没默认值参数的最后,否则会产生语法错误
Pyhton 中,可以使用“函数名.__defaults__”查看函数的默认值参数的当前值,其返回值是一个元组。
print(dis_str.__defaults__)
def func(required_arg, default_arg=None, *args, **kwargs):<br> pass<br> # required_arg 必传位置参数<br> # default_arg 默认参数<br> # *args 非键值可变参数<br> # **kwargs 键值可变参数
*args是用来传递一个非键值变长参数列表功能。<br>**kwargs通常用来传递关键字变长参数。
参数收集
在参数前面添加两个星号(**), 该参数支持关键字参数收集,收集的参数别当成 dict 处理<br>一个函数可同时支持普通参数收集和关键字参数收集
在形参前面添加一个星号(*),意味着该参数可接受多个参数值<br>Python 将传给带 * 参数的多个值收集成一个元组<br>Python 允许参数收集的形参位于形参列表的任意位置,但只能带一个支持“普通”参数收集的形参<br>若支持“普通”参数收集的形参位于前面,后面的参数则需要使用关键字参数传值
def test(*books, num, **scores):<br> print('books:', books)<br> print('num:', num)<br> print('scores:', scores)<br> <br>test('python', 'java', 'c', num=3, py=90, ja=80)
return <br>函数返回值<br>
return 语句在同一函数中可以出现多次,但只要有一个得到执行,就会直接结束函数的执行
def isGreater0(x):<br> if x > 0:<br> return True<br> else:<br> return False<br>print(isGreater0(5))<br>print(isGreater0(0))
多个返回值
使用Object
class Test:<br> def __init__(self):<br> self.str = "hello world!"<br> self.x = 20 <br><br># 返回一个对象<br>def fun():<br> return Test()<br><br>t = fun() <br>print(t.str)<br>print(t.x)
使用列表
# 返回一个列表<br>def fun():<br> str = "hello"<br> x = 20 <br> return [str, x]; <br><br>list = fun() <br>print(list)
使用元组
# 返回一个元组<br>def fun():<br> str = "你好!"<br> x = 2019<br> return str, x;<br><br>str, x = fun() # Assign returned tuple<br>print(str)<br>print(x)
使用词典
# 返回一个字典<br>def fun():<br> d = dict(); <br> d['name'] = "欧阳克"<br> d['age'] = 25<br> return d<br><br>d = fun() <br>print(d)
调用自定义函数<br>
[返回值] = 函数名([形参值])
创建函数有多少个形参,那么调用时就需要传入多少个值,且顺序必须和创建函数时一致<br>即便该函数没有参数,函数名后的小括号也不能省略。
在调用函数时,传入实际参数的位置必须和形式参数位置一一对应
当实际参数类型和形式参数类型不一致,<br>并且在函数中,这两种类型之间不能正常转换,此时就会抛出 TypeError 异常。<br>
关键字参数<br>
指使用形式参数的名字来确定输入的参数值。<br>通过此方式指定函数实参时,不再需要与形参的位置完全一致,只要将参数名写正确即可。
def dis_str(str1,str2):<br> print("str1:",str1)<br> print("str2:",str2)<br>#位置参数<br>dis_str("http://c.biancheng.net/python/","http://c.biancheng.net/shell/")<br>#关键字参数<br>dis_str("http://c.biancheng.net/python/",str2="http://c.biancheng.net/shell/")<br>dis_str(str2="http://c.biancheng.net/python/",str1="http://c.biancheng.net/shell/")
混合传参时关键字参数必须位于所有的位置参数之后
逆向参数收集
在列表、元组前添加 *,在字典前添加 **
def test(a, b):<br> print(a)<br> print(b)<br><br>vals_1 = (10, 20)<br><br># 调用函数时,Python 不会对元组自动解包(默认情况下,元组是一个整体)<br># * 对元组进行解包(逆向参数收集)<br>test(*vals_1)
直接将函数赋值给其它变量
def my_def ():<br> print("正在执行 my_def 函数")<br>#将函数赋值给其他变量 <br>other = my_def<br>#间接调用 my_def() 函数<br>other()
将函数以参数的形式传入其他函数中
def add (a,b):<br> return a+b<br>def multi(a,b):<br> return a*b<br>def my_def(a,b,dis):<br> return dis(a,b)<br> <br>#求 2 个数的和<br>print(my_def(3,4,add))<br>#求 2 个数的乘积<br>print(my_def(3,4,multi))
函数的返回值也为函数
def my_def ():<br> #局部函数<br> def indef():<br> print("调用局部函数")<br> #调用局部函数<br> return indef<br>other_def = my_def()<br>#调用局部的 indef() 函数<br>other_def()
递归函数实例
一球从100米高度自由落下,每次落地后反跳回原高度的一半;<br>再落下,求它在第10次落地时,共经过多少米?第10次反弹多高?<br><br>def heigthM(num, heigth, sum):<br> sum += heigth <br> heigth /= 2 #第一次返回高度50<br> print(heigth, sum) # 查看每次返回的高度和经过多少米<br> if num == 1:<br> return heigth ,sum<br> else:<br> sum += heigth # 返回到最高点时,经过多少米需要加上高度<br> return heigthM(num - 1, heigth, sum)<br>print(heigthM(10, 100, 0)) #num是次数,heigth是高度,sum是经过多少米
'''<br>猴子吃桃问题:猴子第一天摘下若干个桃子,<br>当即吃了一半,还不瘾,又多吃了一个第二天早上又将剩下的桃子吃掉一半,<br>又多吃了一个。以后每天早上都吃了前一天剩下的一半零一个。<br>到第10天早上想再吃时,见只剩下一个桃子了。求第一天共摘了多少?<br>'''<br><br>def monkey(n):<br> if n == 1:<br> return 1<br> else:<br> return (monkey(n - 1) + 1) * 2<br><br>print(monkey(10))
partial<br>偏函数<br>
将现有函数的部分参数预先绑定为指定值,从而得到一个新的函数
定义偏函数,需使用 partial 关键字(位于 functools 模块中),其语法格式如下:<br>偏函数名 = partial(func, *args, **kwargs)<br><br>其中,func 指的是要封装的原函数,*args 和 **kwargs 分别用于接收无关键字实参和关键字实参。
from functools import partial<br>def mod( n, m ):<br> return n % m<br>#定义偏函数,并设置参数 n 对应的实参值为 100<br>mod_by_100 = partial( mod, 100 )<br>print(mod( 100, 7 ))<br>print(mod_by_100( 7 ))
局部函数
Python 支持在函数内部定义函数,此类函数又称为局部函数<br>默认情况下局部函数只能在其所在函数的作用域内使用<br>
#全局函数<br>def outdef ():<br> #局部函数<br> def indef():<br> print("http://c.biancheng.net/python/")<br> #调用局部函数<br> indef()<br>#调用全局函数<br>outdef()
#全局函数<br>def outdef ():<br> #局部函数<br> def indef():<br> print("调用局部函数")<br> #调用局部函数<br> return indef<br>#调用全局函数<br>new_indef = outdef()<br>调用全局函数中的局部函数<br>new_indef()
闭合函数
和嵌套函数类似,不同之处在于,闭包中外部函数返回的不是一个具体的值,而是一个函数<br>一般情况下,返回的函数会赋值给一个变量,这个变量可以在后面被继续执行调用。<br>
#闭包函数,其中 exponent 称为自由变量<br>def nth_power(exponent):<br> def exponent_of(base):<br> return base ** exponent<br> return exponent_of # 返回值是 exponent_of 函数<br>square = nth_power(2) # 计算一个数的平方<br>cube = nth_power(3) # 计算一个数的立方<br>print(square(2)) # 计算 2 的平方<br>print(cube(2)) # 计算 2 的立方<br><br>外部函数 nth_power() 的返回值是函数 exponent_of(),而不是一个具体的数值<br>
匿名函数<br>lambda表达式<br>
常用来表示内部仅包含 1 行表达式的函数<br>。如果一个函数的函数体仅有 1 行表达式,则该函数就可以用 lambda 表达式来代替。<br>
name = lambda [list] : 表达式<br>必须使用 lambda 关键字<br>[list] 作为可选参数,等同于定义函数是指定的参数列表<br>value 为该表达式的名称。
对于单行函数,使用 lambda 表达式可以省去定义函数的过程,让代码更加简洁;<br>对于不需要多次复用的函数,使用 lambda 表达式可以在用完之后立即释放,提高程序执行的性能
add = lambda x,y:x+y<br>print(add(3,4))
函数式编程
代码中每一块都是不可变的,都由纯函数的形式组成
map()
对可迭代对象中的每个元素,都调用指定的函数,并返回一个 map 对象
可以接受多个可迭代对象
map(function, iterable)
function 参数表示要传入一个函数,其可以是内置函数、自定义函数或者 lambda 匿名函数<br>iterable 表示一个或多个可迭代对象,可以是列表、字符串等
listDemo1 = [1, 2, 3, 4, 5]<br>listDemo2 = [3, 4, 5, 6, 7]<br>new_list = map(lambda x,y: x + y, listDemo1,listDemo2)<br>print(list(new_list))
filter()
对 iterable 中的每个元素,都使用 function 函数判断,并返回 True 或者 False,最后将返回 True 的元素组成一个新的可遍历的集合
可以接受多个可迭代对象
filter(function, iterable)<br>funcition 参数表示要传入一个函数,iterable 表示一个可迭代对象。
返回一个列表中的所有偶数。<br>listDemo = [1, 2, 3, 4, 5]<br>new_list = filter(lambda x: x % 2 == 0, listDemo)<br>print(list(new_list))
reduce()
用来对一个集合做一些累积操作
reduce(function, iterable)
function 规定必须是一个包含 2 个参数的函数;iterable 表示可迭代对象
reduce() 函数在 Python 3.x 中已经被移除,放入了 functools 模块,因此在使用该函数之前,需先导入 functools 模块
计算某个列表元素的乘积。<br> <br>import functools<br>listDemo = [1, 2, 3, 4, 5]<br>product = functools.reduce(lambda x, y: x * y, listDemo)<br>print(product)
函数注解
def f(ham:str,egg:str='eggs')->str:<br> pass<br>print(f.__annotations__)
给函数中的参数做注解的方法是在形参后添加冒号“:”,后接需添加的注解(可以是类(如 str、int 等),也可以是字符串或者表示式);给返回值做注解的方法是将注解添加到 def 语句结尾的冒号和 -> 之间
如果参数有默认值,参数注解位于冒号和等号之间。比如 eggs:str='eggs',它表示 eggs 参数的默认值为 'eggs',添加的注解为 str。
def square(number:"一个数字")->"返回number的平方":<br> return number**2<br>print(square(10))<br>print(square.__annotations__)
模块和包
封装特性的结构
诸多容器,例如列表、元组、字符串、字典等,它们都是对数据的封装;<br>函数是对 Python 代码的封装;<br>类是对方法和属性的封装,也可以说是对函数和数据的封装。
模块,是对代码更高级的封装<br>即把能够实现某一特定功能的代码编写在同一个 .py 文件中,并将其作为一个独立的模块<br>这样既可以方便其它程序或脚本导入并使用,同时还能有效避免函数名和变量名发生冲突<br>
自定义一个模块
name = "Python教程"<br>add = "http://c.biancheng.net/python"<br>print(name,add)<br>def say():<br> print("人生苦短,我学Python!")<br>class CLanguage:<br> def __init__(self,name,add):<br> self.name = name<br> self.add = add<br> def say(self):<br> print(self.name,self.add)
说明文档
'''<br>demo 模块中包含以下内容:<br>name 字符串变量:初始值为“Python教程”<br>add 字符串变量:初始值为“http://c.biancheng.net/python”<br>say() 函数<br>CLanguage类:包含 name 和 add 属性和 say() 方法。<br>'''
可以通过模板的 __doc__ 属性,来访问模板的说明文档 <br>import demo<br>print(demo.__doc__)
__name__ 变量
当直接运行一个模块时,name 变量的值为 __main__;<br>而将模块被导入其他程序中并运行该程序时,处于模块中的 __name__ 变量的值就变成了模块名。<br>因此,如果希望测试函数只有在直接运行模块文件时才执行,则可在调用测试函数时增加判断<br>即只有当 __name__ =='__main__' 时才调用测试函数<br>
一般情况下,当我们写完自定义的模块之后,都会写一个测试代码,检验一些模块中各个功能是否能够成功运行<br>例如,创建一个 candf.py 文件,并编写如下代码:<br>纯文本复制<br>'''<br>摄氏度和华氏度的相互转换模块<br>'''<br>def c2f(cel):<br> fah = cel * 1.8 + 32<br> return fah<br>def f2c(fah):<br> cel = (fah - 32) / 1.8<br> return cel<br>def test():<br> print("测试数据:0 摄氏度 = %.2f 华氏度" % c2f(0))<br> print("测试数据:0 华氏度 = %.2f 摄氏度" % f2c(0))<br>test()<br>
import <br>导入模块<br>
import 模块名1 [as 别名1], 模块名2 [as 别名2],…<br>使用这种语法格式的 import 语句,会导入指定模块中的所有成员(包括变量、函数、类等)。<br>不仅如此,当需要使用模块中的成员时,需用该模块名(或别名)作为前缀,否则 Python 解释器会报错。<br><br>from 模块名 import 成员名1 [as 别名1],成员名2 [as 别名2],…<br> 使用这种语法格式的 import 语句,只会导入模块中指定的成员,而不是全部成员。<br>同时,当程序中使用该成员时,无需附加任何前缀,直接使用成员名(或别名)即可。<br>
当我们向文件导入某个模块时,导入的是该模块中那些名称不以下划线(单下划线“_”或者双下划线“__”)开头的变量、函数和类<br>因此,如果我们不想模块文件中的某个成员被引入到其它文件中使用,可以在其名称前添加下划线。<br>
示例
# 导入sys整个模块<br>import sys<br># 使用sys模块名作为前缀来访问模块中的成员<br>print(sys.argv[0])
导入整个模块时,也可以为模块指定别名。 <br># 导入sys整个模块,并指定别名为s<br>import sys as s<br># 使用s模块别名作为前缀来访问模块中的成员<br>print(s.argv[0])
一次导入多个模块,多个模块之间用逗号隔开 <br> <br># 导入sys、os两个模块<br>import sys,os<br># 使用模块名作为前缀来访问模块中的成员<br>print(sys.argv[0])<br># os模块的sep变量代表平台上的路径分隔符<br>print(os.sep)
在导入多个模块的同时,也可以为模块指定别名 <br># 导入sys、os两个模块,并为sys指定别名s,为os指定别名o<br>import sys as s,os as o<br># 使用模块别名作为前缀来访问模块中的成员<br>print(s.argv[0])<br>print(o.sep)
使用 from...import 最简单的语法来导入指定成员:<br> <br># 导入sys模块的argv成员<br>from sys import argv<br># 使用导入成员的语法,直接使用成员名访问<br>print(argv[0])
form...import 导入模块成员时,支持一次导入多个成员:<br>纯文本复制<br># 导入sys模块的argv,winver成员<br>from sys import argv, winver<br># 使用导入成员的语法,直接使用成员名访问<br>print(argv[0])<br>print(winver)
导入模块成员时,也可以为成员指定别名:<br>纯文本复制<br># 导入sys模块的argv成员,并为其指定别名v<br>from sys import argv as v<br># 使用导入成员(并指定别名)的语法,直接使用成员的别名访问<br>print(v[0])
main.py<br><br># import module_test<br>from module_test import * #这种是把模块中的代码复制到了这个py脚本中
__import__<br>
如果模块中包含空格或者以数字开头,就需要使用 Python 提供的 __import__() 内置函数引入模块
__import__("demo text")
__import__("1demo")
使用 __import__() 函数引入模块名时,要以字符串的方式将模块名引入,否则会报 SyntaxError 错误
Python找不到指定模块
通常情况下,当使用 import 语句导入模块后,Python 会按照以下顺序查找指定的模块文件:<br>在当前目录,即当前执行的程序文件所在目录下查找;<br>到 PYTHONPATH(环境变量)下的每个目录中查找;<br>到 Python 默认的安装目录下查找。
向 sys.path 中临时添加模块文件存储位置的完整路径<br>
模块文件的存储位置,可以临时添加到 sys.path 变量中<br>即向 sys.path 中添加 D:\python_module(hello.py 所在目录),在 say.py 中的开头位置添加如下代码:<br>import sys<br>sys.path.append('D:\\python_module')<br>注意:在添加完整路径中,路径中的 '\' 需要使用 \ 进行转义,否则会导致语法错误。<br>
通过该方法添加的目录,只能在执行当前文件的窗口中有效,窗口关闭后即失效
import sys<br>print(sys.path) #python会去哪些目录下找模块,是一个列表<br>Module_Dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) #获取到模块目录<br>sys.path.append(Module_Dir)#把模块目录加到sys.path列表中<br>import 要导入的模块
将模块放在 sys.path 变量中已包含的模块加载路径中
Python 程序默认的模块加载路径保存在 sys.path 变量中,因此,我们可以在 say.py 程序文件中先看看 sys.path 中保存的默认加载路径,向 say.py 文件中输出 sys.path 的值,如下所示:<br>['C:\\Users\\mengma\\Desktop', 'D:\\python3.6\\Lib\\idlelib', 'D:\\python3.6\\python36.zip', 'D:\\python3.6\\DLLs', 'D:\\python3.6\\lib', 'D:\\python3.6', 'C:\\Users\\mengma\\AppData\\Roaming\\Python\\Python36\\site-packages', 'D:\\python3.6\\lib\\site-packages', 'D:\\python3.6\\lib\\site-packages\\win32', 'D:\\python3.6\\lib\\site-packages\\win32\\lib', 'D:\\python3.6\\lib\\site-packages\\Pythonwin']<br><br>上面的运行结果中,列出的所有路径都是 Python 默认的模块加载路径,但通常来说,我们默认将 Python 的扩展模块添加在 lib\site-packages 路径下,它专门用于存放 Python 的扩展模块和包。<br><br>所以,我们可以直接将我们已编写好的 hello.py 文件添加到 lib\site-packages 路径下,就相当于为 Python 扩展了一个 hello 模块,这样任何 Python 程序都可使用该模块。
设置 path 系统环境变量
PYTHONPATH 环境变量(简称 path 变量)的值是很多路径组成的集合<br>Python 解释器会按照 path 包含的路径进行一次搜索,直到找到指定要加载的模块<br>当然,如果最终依旧没有找到,则 Python 就报 ModuleNotFoundError 异常。<br>
__all__变量
该变量的值是一个列表,存储的是当前模块中一些成员(变量、函数或者类)的名称<br>通过在模块文件中设置 __all__ 变量,当其它文件以“from 模块名 import *”的形式导入该模块时,该文件中只能使用 __all__ 列表中指定的成员<br>
def say():<br> print("人生苦短,我学Python!")<br>def CLanguage():<br> print("C语言中文网:http://c.biancheng.net")<br>def disPython():<br> print("Python教程:http://c.biancheng.net/python")<br>__all__ = ["say","CLanguage"]
__all__ 变量仅限于在其它文件中以“from 模块名 import *”的方式引入
以“import 模块名”的形式导入模块。通过该方式导入模块后<br>总可以通过模块名前缀(如果为模块指定了别名,则可以使用模快的别名作为前缀)来调用模块内的所有成员(除了以下划线开头命名的成员)<br>
以“from 模块名 import 成员”的形式直接导入指定成员<br>使用此方式导入的模块,__all__ 变量即便设置,也形同虚设<br>
包
存放多个模块的文件夹<br>必须带有一个__init__.py文件<br>(这是 Python 2.x 的规定,而在 Python 3.x 中,__init__.py 对包来说,并不是必须的)<br>
包的本质依然是模块,包可以包含包
创建一个包
新建一个文件夹,文件夹的名称就是新建包的包名;<br>在该文件夹中,创建一个 __init__.py 文件(前后各有 2 个下划线‘_’),该文件中可以不编写任何代码。<br>也可以编写一些 Python 初始化代码,则当有其它程序文件导入包时,会自动执行该文件中的代码<br>
导入包
import 包名[.模块名 [as 别名]]<br>用 [] 括起来的部分,是可选部分,即可以使用,也可以直接忽略
import my_package.module1<br>my_package.module1.display("http://c.biancheng.net/java/")
通过此语法格式导入包中的指定模块后,在使用该模块中的成员(变量、函数、类)时,需添加“包名.模块名”为前缀
import my_package.module1 as module<br>module.display("http://c.biancheng.net/python/")
直接导入包名,并不会将包中所有模块全部导入到程序中
from 包名 import 模块名 [as 别名]<br>
from my_package import module1<br>module1.display("http://c.biancheng.net/golang/")
使用此语法格式导入包中模块后,在使用其成员时不需要带包名前缀,但需要带模块名前缀
from 包名.模块名 import 成员名 [as 别名]
from my_package.module1 import display<br>display("http://c.biancheng.net/shell/")
通过该方式导入的变量(函数、类),在使用时可以直接使用变量名(函数名、类名)调用
加载该模块下的所有成员<br>from my_package.module1 import *<br>display("http://c.biancheng.net/python")<br>
导入包的同时,会在包目录下生成一个含有 __init__.cpython-36.pyc 文件的 __pycache__ 文件夹
可以被import语句导入的对象是以下类型:<br><br>模块文件(.py文件)<br>C或C++扩展(已编译为共享库或DLL文件)<br>包(包含多个模块)<br>内建模块(使用C编写并已链接到Python解释器中)
dir()函数<br>查看模块成员<br>
import string<br>print(dir(string))
__all__变量
import string<br>print(string.__all__)
和 dir() 函数相比,__all__ 变量在查看指定模块成员时,它不会显示模块中的特殊成员,同时还会根据成员的名称进行排序显示
并非所有的模块都支持使用 __all__ 变量,因此对于获取有些模块的成员,就只能使用 dir() 函数
__doc__属性:查看文档
help() 函数
获取指定成员(甚至是该模块)的帮助信息
#***__init__.py 文件中的内容***<br>from my_package.module1 import *<br>from my_package.module2 import *<br>#***module1.py 中的内容***<br>#module1.py模块文件<br>def display(arc):<br> '''<br> 直接输出指定的参数<br> '''<br> print(arc)<br>#***module2.py中的内容***<br>#module2.py 模块文件<br>class CLanguage:<br> '''<br> CLanguage是一个类,其包含:<br> display() 方法<br> '''<br> def display(self):<br> print("http://c.biancheng.net/python/")
import my_package<br>print(my_package.module1.display.__doc__)
__file__属性<br>查看模块的源文件路径<br>
import my_package<br>print(my_package.__file__)
因为当引入 my_package 包时,其实际上执行的是 __init__.py 文件<br>因此这里查看 my_package 包的存储路径,输出的 __init__.py 文件的存储路径<br>
import string<br>print(string.__file__)
并不是所有模块都提供 __file__ 属性,因为并不是所有模块的实现都采用 Python 语言<br>有些模块采用的是其它编程语言(如 C 语言)<br>
第三方库(模块)下载和安装<br>使用pip命令<br>
https://pypi.org/
可以使用 Python 提供的 pip 命令实现。pip 命令的语法格式如下:<br>pip install|uninstall|list 模块名<br><br>其中,install、uninstall、list 是常用的命令参数,各自的含义为:<br>install:用于安装第三方模块,当 pip 使用 install 作为参数时,后面的模块名不能省略。<br>uninstall:用于卸载已经安装的第三方模块,选择 uninstall 作为参数时,后面的模块名也不能省略。<br>list:用于显示已经安装的第三方模块。
以安装 numpy 模块为例(该模块用于进行科学计算),可以在命令行窗口中输入以下代码:<br>pip install numpy<br><br>执行此代码,它会在线自动安装 numpy 模块
pip 命令会将下载完成的第三方模块,默认安装到 Python 安装目录中的 \Lib\site-packages 目录下
#直接导入 numpy 模块即可<br>import numpy as nu<br>#用 numpy 模块中的开发函数<br>print(nu.sqrt(16))
如果想要查看 Python 中目前有哪些模块(包括标准模块和第三方模块),可以在 IDLE 中输入以下命令:<br>help('modules')<br><br>在此基础上,如果只是想要查看已经安装的第三方模块,可以在使用如下命令:<br>pip list
库
库:相比模块和包,库是一个更大的概念<br>例如在 Python 标准库中的每个库都有好多个包,而每个包中都有若干个模块<br>
文件操作
路径
在 Windows 中,根文件夹名为 D:\,也称为 D: 盘。在 OS X 和 Linux 中,根文件夹是 /
Python os.path 模块提供了一些函数,可以实现绝对路径和相对路径之间的转换,以及检查给定的路径是否为绝对路径,比如说:<br>调用 os.path.abspath(path) 将返回 path 参数的绝对路径的字符串,这是将相对路径转换为绝对路径的简便方法。<br>调用 os.path.isabs(path),如果参数是一个绝对路径,就返回 True,如果参数是一个相对路径,就返回 False。<br>调用 os.path.relpath(path, start) 将返回从 start 路径到 path 的相对路径的字符串。如果没有提供 start,就使用当前工作目录作为开始路径。<br>调用 os.path.dirname(path) 将返回一个字符串,它包含 path 参数中最后一个斜杠之前的所有内容;调用 os.path.basename(path) 将返回一个字符串,它包含 path 参数中最后一个斜杠之后的所有内容。
os.path.join()
将单个文件和路径上的文件夹名称的字符串传递给它<br>os.path.join() 就会返回一个文件路径的字符串,包含正确的路径分隔符<br>
>>> import os<br>>>> os.path.join('demo', 'exercise')<br>'demo\\exercise'
os.getcwd() <br>取得当前工作路径的字符串<br>
os.chdir()<br>改变当前工作路径的字符串
>>> import os<br>>>> os.getcwd()<br>'C:\\Users\\mengma\\Desktop'<br>>>> os.chdir('C:\\Windows\\System32')<br>>>> os.getcwd()<br>'C:\\Windows\\System32'
os.path.split()<br>获得一个路径的目录名称和基本名称
>>> path = 'C:\\Windows\\System32\\calc.exe'<br>>>> os.path.split(path)<br>('C:\\Windows\\System32', 'calc.exe')
如果提供的路径不存在,许多 Python 函数就会崩溃并报错,但好在 os.path 模块提供了以下函数用于检测给定的路径是否存在,以及它是文件还是文件夹:<br>如果 path 参数所指的文件或文件夹存在,调用 os.path.exists(path) 将返回 True,否则返回 False。<br>如果 path 参数存在,并且是一个文件,调用 os.path.isfile(path) 将返回 True,否则返回 False。<br>如果 path 参数存在,并且是一个文件夹,调用 os.path.isdir(path) 将返回 True,否则返回 False。
写入、读取<br>作用于文件的内容,属于应用级操作<br>
操作步骤
文件的应用级操作可以分为以下 3 步,每一步都需要借助对应的函数实现:<br>打开文件:使用 open() 函数,该函数会返回一个文件对象;<br>对已打开文件做读/写操作:读取文件内容可使用 read()、readline() 以及 readlines() 函数;向文件中写入内容,可以使用 write() 函数。<br>关闭文件:完成对文件的读/写操作之后,最后需要关闭文件,可以使用 close() 函数。
open()函数<br>打开文件
open() 函数用于创建或打开指定文件
file = open(file_name [, mode='r' [ , buffering=-1 [ , encoding = None ]]])
用 [] 括起来的部分为可选参数,即可以使用也可以省略。其中,各个参数所代表的含义如下:<br>file:表示要创建的文件对象。<br>file_name:要创建或打开文件的文件名称,该名称要用引号(单引号或双引号都可以)括起来。需要注意的是,如果要打开的文件和当前执行的代码文件位于同一目录,则直接写文件名即可;否则,此参数需要指定打开文件所在的完整路径。<br>mode:可选参数,用于指定文件的打开模式。可选的打开模式如表 1 所示。如果不写,则默认以只读(r)模式打开文件。<br>buffering:可选参数,用于指定对文件做读写操作时,是否使用缓冲区(本节后续会详细介绍)。<br>encoding:手动设定打开文件时所使用的编码格式,不同平台的 ecoding 参数值也不同,以 Windows 为例,其默认为 cp936(实际上就是 GBK 编码)
#当前程序文件同目录下没有 a.txt 文件<br>file = open("a.txt")<br>print(file)
使用 open() 打开文件时,默认采用 GBK 编码<br>但当要打开的文件不是 GBK 编码格式时,可以在使用 open() 函数时,手动指定打开文件的编码格式<br>
file = open("a.txt",encoding="utf-8")
缓冲区
建议大家在使用 open() 函数时打开缓冲区,即不需要修改 buffing 参数的值。<br>如果 buffing 参数的值为 0(或者 False),则表示在打开指定文件时不使用缓冲区;<br>如果 buffing 参数值为大于 1 的整数,该整数用于指定缓冲区的大小(单位是字节);<br>如果 buffing 参数的值为负数,则代表使用默认的缓冲区大小。<br>
常用属性
file.name:返回文件的名称;<br>file.mode:返回打开文件时,采用的文件打开模式;<br>file.encoding:返回打开文件时使用的编码格式;<br>file.closed:判断文件是否己经关闭。
# 以默认方式打开文件<br>f = open('my_file.txt')<br># 输出文件是否已经关闭<br>print(f.closed)<br># 输出访问模式<br>print(f.mode)<br>#输出编码格式<br>print(f.encoding)<br># 输出文件名<br>print(f.name)
使用 open() 函数打开的文件对象,必须手动进行关闭<br>Python 垃圾回收机制无法自动回收打开文件所占用的资源<br>
文本文件通常用来保存肉眼可见的字符,比如 .txt 文件、.c 文件、.dat 文件等<br>二进制文件通常用来保存视频、图片、音频等不可阅读的内容<br>
read()函数<br>读取文件
按字节(字符)读取文件
read() 函数:逐个字节或者字符读取文件中的内容;<br>readline() 函数:逐行读取文件中的内容;<br>readlines() 函数:一次性读取文件中多行内容。<br>
如果文件是以文本模式(非二进制模式)打开的,则 read() 函数会逐个字符进行读取<br>如果文件以二进制模式打开,则 read() 函数会逐个字节进行读取<br>
file.read([size])<br><br>其中,file 表示已打开的文件对象;<br>size 作为一个可选参数,用于指定一次最多可读取的字符(字节)个数,<br>如果省略,则默认一次性读取所有内容。<br>
#以 utf-8 的编码格式打开指定文件<br>f = open("my_file.txt",encoding = "utf-8")<br>#输出读取到的数据<br>print(f.read())<br>#关闭文件<br>f.close()
#以 utf-8 的编码格式打开指定文件<br>f = open("my_file.txt",encoding = "utf-8")<br>#输出读取到的数据<br>print(f.read(6))<br>#关闭文件<br>f.close()
#以二进制形式打开指定文件<br>f = open("my_file.txt",'rb+')<br>#输出读取到的数据<br>print(f.read())<br>#关闭文件<br>f.close()
readline()<br>读取目标文件中的一行<br>
每次都读取目标文件中的一行。<br>对于读取以二进制格式打开的文件,它们会以“\n”作为读取一行的标志<br>
file.readline([size])
size 为可选参数,用于指定读取每一行时,一次最多读取的字符(字节)数
f = open("my_file.txt")<br>读取一行数据<br>byt = f.readline()<br>print(byt)
readline() 函数在读取文件中一行的内容时,会读取最后的换行符“\n”<br>再加上 print() 函数输出内容时默认会换行,<br>所以输出结果中会看到多出了一个空行<br>
#以二进制形式打开指定文件<br>f = open("my_file.txt",'rb')<br>byt = f.readline(6)<br>print(byt)
readlines()<br>读取文件中的所有行<br>
readlines() 函数用于读取文件中的所有行,<br>它和调用不指定 size 参数的 read() 函数类似,<br>只不过该函数返回是一个字符串列表,<br>其中每个元素为文件中的一行内容<br>
file.readlines()<br><br>其中,file 为打开的文件对象。<br>和 read()、readline() 函数一样,<br>它要求打开文件的模式必须为可读模式(包括 r、rb、r+、rb+ 4 种)。<br>
f = open("my_file.txt",'rb')<br>byt = f.readlines()<br>print(byt)
write()<br>写入文件<br>
file.write(string)<br><br>其中,file 表示已经打开的文件对象;<br>string 表示要写入文件的字符串<br>(或字节串,仅适用写入二进制文件中)<br>
f = open("a.txt", 'w')<br>f.write("写入一行新数据")<br>f.close()
打开文件模式中包含 w(写入),那么向文件中写入内容时,会先清空原文件中的内容,然后再写入新的内容
f = open("a.txt", 'a')<br>f.write("\n写入一行新数据")<br>f.close()
打开文件模式中包含 a(追加),则不会清空原有内容,而是将新写入的内容会添加到原内容后边
在写入文件完成后,一定要调用 close() 函数将打开的文件关闭,否则写入的内容不会保存到文件中
<span style="font-family: "Helvetica Neue", 微软雅黑, "Microsoft Yahei", Helvetica, Arial, sans-serif; font-size: 14px; background-color: rgb(249, 249, 249);">当向文件中写入数据时,如果不是文件的尾部,写入位置的原有数据不会自行向后移动,<br>新写入的数据会将文件中处于该位置的数据直接覆盖掉</span><br>
flush() 函数<br>将缓冲区的数据写入文件中<br>
f = open("a.txt", 'w')<br>f.write("写入一行新数据")<br>f.flush()
需要在将数据成功写入到文件中,但并不想关闭文件
writelines()<br>将字符串列表写入文件中<br>
将 a.txt 文件中的数据复制到其它文件中
f = open('a.txt', 'r')<br>n = open('b.txt','w+')<br>n.writelines(f.readlines())<br>n.close()<br>f.close()
使用 writelines() 函数向文件中写入多行数据时,不会自动给各行添加换行符
close()函数<br>关闭文件<br>
file.close()
import os<br>f = open("my_file.txt",'w')<br>#...<br>os.remove("my_file.txt")
import os<br>f = open("my_file.txt",'w')<br>f.close()<br>#...<br>os.remove("my_file.txt")
seek()<br>移动文件指针到文件的指定位置<br>
file.seek(offset[, whence])<br><br>其中,各个参数的含义如下:<br>file:表示文件对象;<br>whence:作为可选参数,用于指定文件指针要放置的位置,该参数的参数值有 3 个选择:0 代表文件头(默认值)、1 代表当前位置、2 代表文件尾。<br>offset:表示相对于 whence 位置文件指针的偏移量,正数表示向后偏移,负数表示向前偏移。例如,当whence == 0 &&offset == 3(即 seek(3,0) ),表示文件指针移动至距离文件开头处 3 个字符的位置;当whence == 1 &&offset == 5(即 seek(5,1) ),表示文件指针向后移动,移动至距离当前位置 5 个字符处。<br>注意,当 offset 值非 0 时,Python 要求文件必须要以二进制格式打开,否则会抛出 io.UnsupportedOperation 错误。
f = open('a.txt', 'rb')<br># 判断文件指针的位置<br>print(f.tell())<br># 读取一个字节,文件指针自动后移1个数据<br>print(f.read(1))<br>print(f.tell())<br># 将文件指针从文件开头,向后移动到 5 个字符的位置<br>f.seek(5)<br>print(f.tell())<br>print(f.read(1))<br># 将文件指针从当前位置,向后移动到 5 个字符的位置<br>f.seek(5, 1)<br>print(f.tell())<br>print(f.read(1))<br># 将文件指针从文件结尾,向前移动到距离 2 个字符的位置<br>f.seek(-1, 2)<br>print(f.tell())<br>print(f.read(1))
tell()<br>判断文件指针当前所处的位置<br>
file.tell()
f = open("a.txt",'r')<br>print(f.tell())<br>print(f.read(3))<br>print(f.tell())
当使用 read() 函数从文件中读取 3 个字符之后,文件指针同时向后移动了 3 个字符的位置
pickle<br>序列化过程<br>
实现任意对象与文本之间的相互转化,<br>也可以实现任意对象与二进制之间的相互转化<br>
pickle 模块提供了以下 4 个函数供我们使用:<br>dumps():将 Python 中的对象序列化成二进制对象,并返回;<br>loads():读取给定的二进制对象数据,并将其转换为 Python 对象;<br>dump():将 Python 中的对象序列化成二进制对象,并写入文件;<br>load():读取指定的序列化数据文件,并返回对象。
pickle.dumps()函数
将 Python 对象转为二进制对象,其语法格式如下:<br>dumps(obj, protocol=None, *, fix_imports=True)<br><br>此格式中各个参数的含义为:<br>obj:要转换的 Python 对象;<br>protocol:pickle 的转码协议,取值为 0、1、2、3、4,<br>其中 0、1、2 对应 Python 早期的版本,3 和 4 则对应 Python 3.x 版本及之后的版本。<br>未指定情况下,默认为 3。<br>
import pickle<br>tup1 = ('I love Python', {1,2,3}, None)<br>#使用 dumps() 函数将 tup1 转成 p1<br>p1 = pickle.dumps(tup1)<br>print(p1)
pickle.loads()函数
将二进制对象转换成 Python 对象,其基本格式如下:<br>loads(data, *, fix_imports=True, encoding='ASCII', errors='strict')<br><br>其中,data 参数表示要转换的二进制对象
import pickle<br>tup1 = ('I love Python', {1,2,3}, None)<br>p1 = pickle.dumps(tup1)<br>#使用 loads() 函数将 p1 转成 Python 对象<br>t2 = pickle.loads(p1)<br>print(t2)
pickle.dump()函数
将 Python 对象转换成二进制文件,其基本语法格式为:<br>dump (obj, file,protocol=None, *, fix mports=True)<br><br>其中各个参数的具体含义如下:<br>obj:要转换的 Python 对象。<br>file:转换到指定的二进制文件中,要求该文件必须是以"wb"的打开方式进行操作。<br>protocol:和 dumps() 函数中 protocol 参数的含义完全相同
import pickle<br>tup1 = ('I love Python', {1,2,3}, None)<br>#使用 dumps() 函数将 tup1 转成 p1<br>with open ("a.txt", 'wb') as f: #打开文件<br> pickle.dump(tup1, f) #用 dump 函数将 Python 对象转成二进制对象文件
pickle.load()函数
将二进制对象文件转换成 Python 对象。该函数的基本语法格式为:<br>load(file, *, fix_imports=True, encoding='ASCII', errors='strict')<br><br>其中,file 参数表示要转换的二进制对象文件(必须以 "rb" 的打开方式操作文件)
import pickle<br>tup1 = ('I love Python', {1,2,3}, None)<br>#使用 dumps() 函数将 tup1 转成 p1<br>with open ("a.txt", 'wb') as f: #打开文件<br> pickle.dump(tup1, f) #用 dump 函数将 Python 对象转成二进制对象文件<br>with open ("a.txt", 'rb') as f: #打开文件<br> t3 = pickle.load(f) #将二进制文件对象转换成 Python 对象<br> print(t3)
fileinput模块<br>逐行读取多个文件<br>
input() 函数
fileinput.input(files="filename1, filename2, ...", inplace=False, backup='', bufsize=0, mode='r', openhook=None)<br><br>此函数会返回一个 FileInput 对象,它可以理解为是将多个指定文件合并之后的文件对象。其中,各个参数的含义如下:<br>files:多个文件的路径列表;<br>inplace:用于指定是否将标准输出的结果写回到文件,此参数默认值为 False;<br>backup:用于指定备份文件的扩展名;<br>bufsize:指定缓冲区的大小,默认为 0;<br>mode:打开文件的格式,默认为 r(只读格式);<br>openhook:控制文件的打开方式,例如编码格式等。<br>注意,和 open() 函数不同,input() 函数不能指定打开文件的编码格式,<br>这意味着使用该函数读取的所有文件,除非以二进制方式进行读取,<br>否则该文件编码格式都必须和当前操作系统默认的编码格式相同,不然 Python 解释器可能会提示 UnicodeDecodeError 错误。<br>
import fileinput<br>#使用for循环遍历 fileinput 对象<br>for line in fileinput.input(files=('my_file.txt', 'file.txt')):<br> # 输出读取到的内容<br> print(line)<br># 关闭文件流<br>fileinput.close()
读取文件内容的次序,取决于 input() 函数中文件名的先后次序
linecache 模块<br>读取指定文件中的指定行<br>
linecache 模块常用来读取 Python 源文件中的代码,它使用的是 UTF-8 编码格式来读取文件内容
import linecache<br>import string<br>#读取string模块中第 3 行的数据<br>print(linecache.getline(string.__file__, 3))<br># 读取普通文件的第2行<br>print(linecache.getline('my_file.txt', 2))
with as 语句
在打开文件或文件操作过程中抛出了异常,无法及时关闭文件<br>使用 with as 语句操作上下文管理器(context manager)<br>能够帮助我们自动分配并且释放资源<br>
同时包含 __enter__() 和 __exit__() 方法的对象就是上下文管理器
__enter__(self):进入上下文管理器自动调用的方法,该方法会在 with as 代码块执行之前执行。如果 with 语句有 as子句,那么该方法的返回值会被赋值给 as 子句后的变量;该方法可以返回多个值,因此在 as 子句后面也可以指定多个变量(多个变量必须由“()”括起来组成元组)。<br>__exit__(self, exc_type, exc_value, exc_traceback):退出上下文管理器自动调用的方法。该方法会在 with as 代码块执行之后执行。如果 with as 代码块成功执行结束,程序自动调用该方法,调用该方法的三个参数都为 None:如果 with as 代码块因为异常而中止,程序也自动调用该方法,使用 sys.exc_info 得到的异常信息将作为调用该方法的参数。
http://c.biancheng.net/view/5319.html
with 表达式 [as target]:<br> 代码块<br><br>此格式中,用 [] 括起来的部分可以使用,也可以省略。<br>其中,target 参数用于指定一个变量,该语句会将 expression 指定的结果保存到该变量中。<br>with as 语句中的代码块如果不想执行任何语句,可以直接使用 pass 语句代替<br>
with open('a.txt', 'a') as f:<br> f.write("\nPython教程")
通过使用 with as 语句,即便最终没有关闭文件,修改文件内容的操作也能成功
OS模块
系统操作
子主题
<br>import os<br> <br>print (os.sep)<br>print (os.name)<br>print (os.getenv('path'))<br>print (os.getcwd())
目录操作
<br>dirs="D:\\Release\\bin"<br>files= os.listdir(dirs)<br>print files
删除目录
目录下必须是空的才能删除<br><br>import os<br>my_dir="D:\\liangmx\\LR\zl\\123"<br>if os.path.exists(my_dir):<br> os.rmdir(my_dir)
打印当前目录中包含homeword的文件,已经打印出绝对路径<br><br>思路:<br><br>第一步:获取当前路径路径,获取当前路径下的文件或者文件夹<br><br>第二步:循环文件,判断是否问文件,如果是文件,就判断是否包含 字符串,然后打印<br><br>import os<br>#coding=utf-8<br>'''编写程序:<br>1:能在当前目录下查找文件名包含指定字符串的文件<br>2:并打印出绝对路径<br>'''<br>sub_str="homework"<br>cur_dir=os.getcwd()<br>files=os.listdir(cur_dir)<br>for item in files:<br> print item<br> if os.path.isfile(os.path.join(cur_dir,item)):<br> if item.find(sub_str) != -1:<br> print (os.path.join(cur_dir,item))
判断
path模块
<br>import os<br>#coding:utf-8<br>#列出当前目录下的所有文件<br>dirs="D:\\Release\\bin"<br>if os.path.exists(dirs):<br> files= os.listdir(dirs)<br> print files<br> #拼接了路径<br> fullpath=os.path.join(dirs,files[0])<br> print fullpath<br> #判断一个路径是否是一个文件,是否目录<br> if os.path.isfile(fullpath):<br> print '我是一个文件'<br> elif os.path.isdir(fullpath):<br>
os.path 模块
from os import path<br># 获取绝对路径<br>print(path.abspath("my_file.txt"))<br># 获取共同前缀<br>print(path.commonprefix(['C://my_file.txt', 'C://a.txt']))<br># 获取共同路径<br>print(path.commonpath(['http://c.biancheng.net/python/', 'http://c.biancheng.net/shell/']))<br># 获取目录<br>print(path.dirname('C://my_file.txt'))<br># 判断指定目录是否存在<br>print(path.exists('my_file.txt'))
tempfile模块<br>创建临时文件和临时目录<br>
import tempfile<br># 创建临时文件<br>fp = tempfile.TemporaryFile()<br>print(fp.name)<br>fp.write('两情若是久长时,'.encode('utf-8'))<br>fp.write('又岂在朝朝暮暮。'.encode('utf-8'))<br># 将文件指针移到开始处,准备读取文件<br>fp.seek(0)<br>print(fp.read().decode('utf-8')) # 输出刚才写入的内容<br># 关闭文件,该文件将会被自动删除<br>fp.close()<br># 通过with语句创建临时文件,with会自动关闭临时文件<br>with tempfile.TemporaryFile() as fp:<br> # 写入内容<br> fp.write(b'I Love Python!')<br> # 将文件指针移到开始处,准备读取文件<br> fp.seek(0)<br> # 读取文件内容<br> print(fp.read()) # b'I Love Python!'<br># 通过with语句创建临时目录<br>with tempfile.TemporaryDirectory() as tmpdirname:<br> print('创建临时目录', tmpdirname)
两种方式来创建临时文件:<br>第一种方式是手动创建临时文件,读写临时文件后需要主动关闭它,当程序关闭该临时文件时,该文件会被自动删除。<br>第二种方式则是使用 with 语句创建临时文件,这样 with 语句会自动关闭临时文件
删除
import os<br>os.remove("a.txt")
pathlib模块
pathlib 模块的操作对象是各种操作系统中使用的路径(例如指定文件位置的路径,包括绝对路径和相对路径)。<br>这里简单介绍一下图 1 中包含的几个类的具体功能:<br>PurePath 类会将路径看做是一个普通的字符串,它可以实现将多个指定的字符串拼接成适用于当前操作系统的路径格式,同时还可以判断任意两个路径是否相等。注意,使用 PurePath 操作的路径,它并不会关心该路径是否真实有效。<br>PurePosixPath 和 PureWindowsPath 是 PurePath 的子类,前者用于操作 UNIX(包括 Mac OS X)风格的路径,后者用于操作 Windows 风格的路径。<br>Path 类和以上 3 个类不同,它操作的路径一定是真实有效的。Path 类提供了判断路径是否真实存在的方法。<br>PosixPath 和 WindowPath 是 Path 的子类,分别用于操作 Unix(Mac OS X)风格的路径和 Windows 风格的路径。<br>
PurePath 类
from pathlib import *<br># 创建PurePath,实际上使用PureWindowsPath<br>path = PurePath('my_file.txt')<br>print(type(path))
from pathlib import *<br># 创建PurePath,实际上使用PureWindowsPath<br>path = PurePath('http:','c.biancheng.net','python')<br>print(path)
如果想在 Windows 系统上输出 UNIX 风格的路径字符串,就需要使用 PurePosixPath 类。例如:<br>纯文本复制<br>from pathlib import *<br>path = PurePosixPath('http:','c.biancheng.net','python')<br>print(path)
在使用 PurePath 类构造方法时,不传入任何参数,则等同于传入点‘.’(表示当前路径)作为参数。
如果传入 PurePath 构造方法中的多个参数中,包含多个根路径,则只会有最后一个根路径及后面的子路径生效
如果传给 PurePath 构造方法的参数中包含有多余的斜杠或者点( . ,表示当前路径),会直接被忽略( .. 不会被忽略)
对余同种风格的路径字符串来说,可以判断是否相等,也可以比较大小<br>(实际上就是比较字符串的大小)<br>from pathlib import *<br># Unix风格的路径区分大小写<br>print(PurePosixPath('C://my_file.txt') == PurePosixPath('c://my_file.txt'))<br># Windows风格的路径不区分大小写<br>print(PureWindowsPath('C://my_file.txt') == PureWindowsPath('c://my_file.txt'))<br>
Path 类
支持对路径的真实性进行判断
fnmatch模块<br>文件名称的匹配<br>
fnmatch 模块匹配文件名的模式使用的就是 UNIX shell 风格,其支持使用如下几个通配符:<br>*:可匹配任意个任意字符。<br>?:可匹配一个任意字符。<br>[字符序列]:可匹配中括号里字符序列中的任意字符。该字符序列也支持中画线表示法。比如 [a-c] 可代表 a、b 和 c 字符中任意一个。<br>[!字符序列]:可匹配不在中括号里字符序列中的任意字符。
import fnmatch<br>#filter()<br>print(fnmatch.filter(['dlsf', 'ewro.txt', 'te.py', 'youe.py'], '*.txt'))<br>#fnmatch()<br>for file in ['word.doc','index.py','my_file.txt']:<br> if fnmatch.fnmatch(file,'*.txt'):<br> print(file)<br>#fnmatchcase()<br>print([addr for addr in ['word.doc','index.py','my_file.txt','a.TXT'] if fnmatch.fnmatchcase(addr, '*.txt')])<br>#translate()<br>print(fnmatch.translate('a*b.txt'))
ZODB
ZODB 是一个健壮的、多用户的和面向对象的数据库系统,<br>专门用于存储 Python 语言中的对象数据,<br>它能够存储和管理任意复杂的 Python 对象,并支持事务操作和并发控制<br>
变量<br>
int()
整数
含负数<br>
含0
float()
浮点数<br>
3.14<br>
314e-2/314E-2
浮点数的指数写法<br>
小数的计算可能是不精确的
示例:12.3 * 0.1
str()
常规用法<br>
单引号或双引号效果一致
\
转义:'I\'m a great coder!'
换行
长字符串,连续三个单引号
可以换行
内容中的引号不需要转义
换行、空格、缩进等空白符都会原样输出
原始字符串
r'原始字符串'
rstr = r'D:\Program Files\Python 3.8\python.exe'
原始字符串中的/不需要转义
引号或双引号仍需要转义
repr()
str() 用于将数据转换成适合人类阅读的字符串形式。<br> repr() 用于将数据转换成适合解释器阅读的字符串形式(Python 表达式的形式),适合在开发和调试阶段使用;如果没有等价的语法,则会发生 SyntaxError 异常。<br>
在 Python 交互式编程环境中输入一个表达式(变量、加减乘除、逻辑运算等)时,Python 会自动使用 repr() 函数处理该表达式
拼接字符串<br>
strname = "str1" "str2"
只能拼接字符串常量
strname = str1 + str2
变量拼接
字符串和数字的拼接
str() 和 repr() 函数将数字转换为字符串
字符串切片
strname[index]
获取单个字符
index 表示索引值
strname[start : end : step]
获取字符串
start:表示要截取的第一个字符所在的索引(截取时包含该字符)。如果不指定,默认为 0,也就是从字符串的开头截取;<br>end:表示要截取的最后一个字符所在的索引(截取时不包含该字符)。如果不指定,默认为字符串的长度;<br>step:指的是从 start 索引处的字符开始,每 step 个距离获取一个字符,直至 end 索引出的字符。step 默认值为 1,当省略该值时,最后一个冒号也可以省略。
获取字符串长度或字节数
len(string)
计算字符串的长度
encode()
len(str1.encode())
将字符串进行编码后再获取它的字节数
len(str1.encode('gbk'))
采用 GBK 编码的字符串的长度
分割字符串
split()
str.split(sep,maxsplit)
sep:用于指定分隔符,可以包含多个字符。此参数默认为 None,表示所有空字符,包括空格、换行符“\n”、制表符“\t”等
maxsplit:可选参数,用于指定分割的次数,最后列表中子串的个数最多为 maxsplit+1。如果不指定或者指定为 -1,则表示分割次数没有限制
如果不指定 sep 参数,那么也不能指定 maxsplit 参数
将一个字符串按照指定的分隔符切分成多个子串,这些子串会被保存到列表中(不包含分隔符),作为方法的返回值反馈回来
合并字符串
join()
split() 方法的逆方法
newstr = str.join(iterable)
str:用于指定合并时的分隔符
iterable:做合并操作的源字符串数据,允许以列表、元组等形式提供
统计字符串出现的次数
count()<br>
检索指定字符串在另一字符串中出现的次数,如果检索的字符串不存在,则返回 0,否则返回出现的次数
str.count(sub[,start[,end]])
str:表示原字符串;<br> sub:表示要检索的字符串;<br> start:指定检索的起始位置,也就是从什么位置开始检测。如果不指定,默认从头开始检索;<br> end:指定检索的终止位置,如果不指定,则表示一直检索到结尾。<br>
检测字符串中是否包含某子串
find()
检索字符串中是否包含目标字符串,如果包含,则返回第一次出现该字符串的索引;反之,则返回 -1
str.find(sub[,start[,end]])
str:表示原字符串;<br> sub:表示要检索的目标字符串;<br> start:表示开始检索的起始位置。如果不指定,则默认从头开始检索;<br> end:表示结束检索的结束位置。如果不指定,则默认一直检索到结尾。<br>
rfind()
rfind() 是从字符串右边开始检索
index()
str.index(sub[,start[,end]])
str:表示原字符串;<br> sub:表示要检索的子字符串;<br> start:表示检索开始的起始位置,如果不指定,默认从头开始检索;<br> end:表示检索的结束位置,如果不指定,默认一直检索到结尾。<br>
当指定的字符串不存在时,index() 方法会抛出异常
rindex()
作用和 index() 方法类似,不同之处在于它是从右边开始检索
字符串对齐方法
ljust()
向指定字符串的右侧填充指定字符,从而达到左对齐文本的目的
S.ljust(width[, fillchar])
S:表示要进行填充的字符串;<br>width:表示包括 S 本身长度在内,字符串要占的总长度;<br>fillchar:作为可选参数,用来指定填充字符串时所用的字符,默认情况使用空格
rjust()
和 ljust() 方法类似,唯一的不同在于,rjust() 方法是向字符串的左侧填充指定字符,从而达到右对齐文本的目的
S.rjust(width[, fillchar])
center()
S.center(width[, fillchar])
起始和结尾判断<br>
startswith()
检索字符串是否以指定字符串开头,如果是返回 True;反之返回 False
str.startswith(sub[,start[,end]])
str:表示原字符串;<br> sub:要检索的子串;<br> start:指定检索开始的起始位置索引,如果不指定,则默认从头开始检索;<br> end:指定检索的结束位置索引,如果不指定,则默认一直检索在结束。<br>
endswith()
str.endswith(sub[,start[,end]])
str:表示原字符串;<br>sub:表示要检索的字符串;<br>start:指定检索开始时的起始位置索引(字符串第一个字符对应的索引值为 0),如果不指定,默认从头开始检索。<br>end:指定检索的结束位置索引,如果不指定,默认一直检索到结束
字符串大小写转换
title()
将字符串中每个单词的首字母转为大写,其他字母全部转为小写
str.title()
lower()
将字符串中的所有大写字母转换为小写字母
str.lower()
upper()
将字符串中的所有小写字母转换为大写字母
str.upper()
删除指定字符
制表符(\t)、回车符(\r)、换行符(\n)
strip():删除字符串前后(左右两侧)的空格或特殊字符<br>
str.strip([chars])
str 表示原字符串,[chars] 用来指定要删除的字符,可以同时指定多个,如果不手动指定,则默认会删除空格以及制表符、回车符、换行符等特殊字符
lstrip():删除字符串前面(左边)的空格或特殊字符<br>
rstrip():删除字符串后面(右边)的空格或特殊字符
Python 的 str 是不可变的(不可变的意思是指,字符串一旦形成,它所包含的字符序列就不能发生任何改变),因此这三个方法只是返回字符串前面或后面空白被删除之后的副本,并不会改变字符串本身
格式化输出
%
format()
str.format(args)
str 用于指定字符串的显示样式;args 用于指定要进行格式转换的项,如果有多项,之间有逗号进行分割
str 显示样式的书写格式 { [index][ : [ [fill] align] [sign] [#] [width] [.precision] [type] ] }
格式中用 [] 括起来的参数都是可选参数,即可以使用,也可以不使用
index:指定:后边设置的格式要作用到 args 中第几个数据,数据的索引值从 0 开始。如果省略此选项,则会根据 args 中数据的先后顺序自动分配。<br> fill:指定空白处填充的字符。注意,当填充字符为逗号(,)且作用于整数或浮点数时,该整数(或浮点数)会以逗号分隔的形式输出,例如(1000000会输出 1,000,000)<br>
width:指定输出数据时所占的宽度。<br>.precision:指定保留的小数位数。
子主题
子主题
子主题<br>
#以货币形式显示<br> print("货币形式:{:,d}".format(1000000))<br> #科学计数法表示<br> print("科学计数法:{:E}".format(1200.12))<br> #以十六进制表示<br> print("100的十六进制:{:#x}".format(100))<br> #输出百分比形式<br> print("0.01的百分比表示:{:.0%}".format(0.01))
字符串编码转换
Python 3.x 默认采用 UTF-8 编码格式
在 Python 中,有 2 种常用的字符串类型,分别为 str 和 bytes 类型<br>其中 str 用来表示 Unicode 字符<br>bytes 用来表示二进制数据<br>str 类型和 bytes 类型之间就需要使用 encode() 和 decode() 方法进行转换
encode()
str.encode([encoding="utf-8"][,errors="strict"])
格式中用 [] 括起来的参数为可选参数
将 str 类型转换成 bytes 类型,这个过程也称为“编码”
<br>
decode()
bytes.decode([encoding="utf-8"][,errors="strict"])
将 bytes 类型的二进制数据转换为 str 类型,这个过程也称为“解码”
<br>
帮助函数
dir()
函数用来列出某个类或者某个模块中的全部内容,包括变量、方法、函数和类等
>>> dir(set)<br>['add', 'clear', 'copy', 'difference', 'difference_update', 'discard', 'intersection', 'intersection_update', 'isdisjoint', 'issubset', 'issuperset', 'pop', 'remove', 'symmetric_difference', 'symmetric_difference_update', 'union', 'update']
help()<br>
查看某个函数或者模块的帮助文档
>>> help(str.lower)<br>Help on method_descriptor:<br><br>lower(self, /)<br> Return a copy of the string converted to lowercase.
type()
查询变量类型<br>
bytes()
以字节序列的形式(二进制形式)存储数据
如果字符串的内容都是 ASCII 字符,那么直接在字符串前面添加b前缀就可以转换成 bytes
如果不指定字符集encode(),那么默认采用 UTF-8
b4 = bytes('C语言中文网8岁了', encoding='UTF-8')
复数(Complex)
具体格式为:a + bj
可计算
常用数据类型转换函数
<br>
作用域(Scope)
变量的有效范围,就是变量可以在哪个范围以内使用。<br>有些变量可以在整段代码的任意位置使用<br>有些变量只能在函数内部使用<br>有些变量只能在 for 循环内部使用
局部变量(Local Variable)
当函数执行完毕后,其内部定义的变量会被销毁并回收
def demo():<br> add = "http://c.biancheng.net/python/"<br> print("函数内部 add =",add)<br>demo()<br>print("函数外部 add =",add)
locals()函数
#全局变量<br>Pyname = "Python教程"<br>Pyadd = "http://c.biancheng.net/python/"<br>def text():<br> #局部变量<br> Shename = "shell教程"<br> Sheadd= "http://c.biancheng.net/shell/"<br> print("函数内部的 locals:")<br> print(locals())<br>text()<br>print("函数外部的 locals:")<br>print(locals())
可以通过指定键访问对应的变量值,但无法对变量值做修改
vars(object)
#全局变量<br>Pyname = "Python教程"<br>Pyadd = "http://c.biancheng.net/python/"<br>class Demo:<br> name = "Python 教程"<br> add = "http://c.biancheng.net/python/"<br>print("有 object:")<br>print(vars(Demo))<br>print("无 object:")<br>print(vars())
返回一个指定 object 对象范围内所有变量组成的字典。<br>如果不传入object 参数,vars() 和 locals() 的作用完全相同<br>
全局变量(Global Variable)
在函数体外定义的变量,一定是全局变量
在函数体内定义全局变量。<br>即使用 global 关键字对变量进行修饰后,该变量就会变为全局变量
def text():<br> global add<br> add= "http://c.biancheng.net/java/"<br> print("函数体内访问:",add)<br>text()<br>print('函数体外访问:',add)
<h4 style="margin: 8px auto; font-size: 14px; line-height: 1.6; font-family: "Helvetica Neue", 微软雅黑, "Microsoft Yahei", Helvetica, Arial, sans-serif;"> globals()函数<br></h4>
返回一个包含全局范围内所有变量的字典,该字典中的每个键值对,键为变量名,值为该变量的值
#全局变量<br>Pyname = "Python教程"<br>Pyadd = "http://c.biancheng.net/python/"<br>def text():<br> #局部变量<br> Shename = "shell教程"<br> Sheadd= "http://c.biancheng.net/shell/"<br>print(globals())
访问指定变量,并赋值<br>print(globals()['Pyname'])<br>globals()['Pyname'] = "Python入门教程"<br>print(Pyname)<br>
在函数中使用同名的全局变量
全局变量默认可以在所有函数内被访问<br>但是,如果当函数中定义了与全局变量同名的变量时,就会发生局部变量遮蔽(hide)全局变量的情形
name = 'Charlie'<br> <br>def test ():<br> <br> # 声明name是全局变量,后面的赋值语句不会重新定义局部变量<br> <br> global name<br> <br> # 直接访问name全局变量<br> <br> print(name) # Charlie<br> <br> name = '孙悟空'<br> <br>test()<br> <br>print(name) # 孙悟空
数据
序列 Sequence
序列索引
使用负值作为列序中各元素的索引值时,是从 -1 开始,而不是从 0 开始
序列切片
sname[start : end : step]
sname:表示序列的名称;<br> start:表示切片的开始索引位置(包括该位置),此参数也可以不指定,会默认为 0,也就是从序列的开头进行切片;<br> end:表示切片的结束索引位置(不包括该位置),如果不指定,则默认为序列的长度;<br> step:表示在切片过程中,隔几个存储位置(包含当前位置)取一次元素,也就是说,如果 step 的值大于 1,则在进行切片去序列元素时,会“跳跃式”的取元素。如果省略设置 step 的值,则最后一个冒号就可以省略。<br>
序列相加
序列相乘<br>
in
检查元素是否包含在序列中
not in
序列相关的内置函数
列表(list)
列表会将所有元素都放在一对中括号[ ]里面,相邻元素之间用逗号,分隔
[element1, element2, element3, ..., elementn]
多个数据挨个存储到一起
通常同一列表中只放入同一类型的数据,这样可以提高程序的可读性
新建[]
emptylist = [ ] 创建一个空列表<br>
list()
转化为列表
编辑<br>
append()
listname.append(obj)<br>listname 表示要添加元素的列表;obj 表示到添加到列表末尾的数据,它可以是单个元素,也可以是列表、元组等
extend()
listname.extend(obj)<br>listname 指的是要添加元素的列表;obj 表示到添加到列表末尾的数据,它可以是单个元素,也可以是列表、元组等,但不能是单个的数字
extend() 和 append() 的不同之处在于:extend() 不会把列表或者元祖视为一个整体,而是把它们包含的元素逐个添加到列表中
insert()
listname.insert(index , obj)<br>index 表示指定位置的索引值。insert() 会将 obj 插入到 listname 列表第 index 个元素的位置。
修改单个元素
nums = [40, 36, 89, 2, 36, 100, 7]<br>nums[2] = -26 #使用正数索引<br>nums[-3] = -66.2 #使用负数索引
修改一组元素
nums = [40, 36, 89, 2, 36, 100, 7]<br>#修改第 1~4 个元素的值(不包括第4个元素)<br>nums[1: 4] = [45.25, -77, -52.5]
指定步长(step 参数)
nums = [40, 36, 89, 2, 36, 100, 7]<br>#步长为2,为第1、3、5个元素赋值<br>nums[1: 6: 2] = [0.025, -99, 20.5]
查找
通过索引访问列表中的某个元素
listname[i]<br>
listname[start : end : step]
正数序列从0开始,负数序列从-1开始
切片起始位不包含在切片范围中<br>
index()
listname.index(obj, start, end)<br>listname 表示列表名称,obj 表示要查找的元素,start 表示起始位置,end 表示结束位置。<br><br>start 和 end 参数用来指定检索范围:<br> start 和 end 可以都不写,此时会检索整个列表;<br> 如果只写 start 不写 end,那么表示检索从 start 到末尾的元素;<br> 如果 start 和 end 都写,那么表示检索 start 和 end 之间的元素。<br>
如果该元素不存在,则会导致 ValueError 错误
count()
用来统计某个元素在列表中出现的次数
listname.count(obj)<br>listname 代表列表名,obj 表示要统计的元素。
删除
pop()
listname.pop(index)
如果不写 index 参数,默认会删除列表中的最后一个元素
clear()
清空列表
remove()
只会删除第一个和指定值相同的元素,而且必须保证该元素是存在的
del
del listname[index]<br>listname 表示列表名称,index 表示元素的索引值。<br>
删除中间一段连续的元素:<br>del listname[start : end]<br>start 表示起始索引,end 表示结束索引。del 会删除从索引 start 到 end 之间的元素,不包括 end 位置的元素。
删除变量时不会删除数据,数据仍储存在内存中
collect()
回收系统中的无效内存
#引入gc库<br> import gc<br> tt = 'hello'<br> #定义一个包含多个类型的 list<br> list1 = [1,4,tt,3.4,"yes",[1,2]]<br> del list1<br> #回收内存地址<br> gc.collect()
系统为了提升性能,会将一部分变量驻留在内存中。这个机制对于,多线程并发时程序产生大量占用内存的变量无法得到释放,或者某些不再需要使用的全局变量占用着大的内存,导致后续运行中出现内存不足的情况,此时就可以使用 del 关键字来回收内存,使系统的性能得以提升。同时,它可以为团队省去扩充大量内存的成本。
range()
快速初始化数字列表
for value in range(1,5):
指定步长<br>even_numbers = list(range(2,11,2))<br>
模拟两种数据结构
队列
先存入的数据最先取出,即“先进先出”
#定义一个空列表,当做队列<br> queue = []<br> #向列表中插入元素<br> queue.insert(0,1)<br> queue.insert(0,2)<br> queue.insert(0,"hello")<br> print(queue)<br> print("取一个元素:",queue.pop())<br> print("取一个元素:",queue.pop())<br> print("取一个元素:",queue.pop())
栈
最后存入的数据最先取出,即“后进先出”
#定义一个空 list 当做栈<br> stack = []<br> stack.append(1)<br> stack.append(2)<br> stack.append("hello")<br> print(stack)<br> print("取一个元素:",stack.pop())<br> print("取一个元素:",stack.pop())<br> print("取一个元素:",stack.pop())
deque
使用标准库的 collections 模块中的 deque 结构体,它被设计成在两端存入和读取都很快的特殊 list,可以用来实现栈和队列的功能
queueAndStack = deque()<br> queueAndStack.append(1)<br> queueAndStack.append(2)<br> queueAndStack.append("hello")<br> print(list(queueAndStack))<br> #实现队列功能,从队列中取一个元素,根据先进先出原则,这里应输出 1<br> print(queueAndStack.popleft())<br> #实现栈功能,从栈里取一个元素,根据后进先出原则,这里应输出 hello<br> print(queueAndStack.pop())<br> #再次打印列表<br> print(list(queueAndStack))
元组(tuple)
所有元素都放在一对小括号( )中,相邻元素之间用逗号,分隔
但小括号不是必须的,只要将各元素用逗号隔开,Python 就会将其视为元组
元组是 tuple 类型
元组是不可变序列,元组中的元素不能被修改
元组的性能速度要优于列表
新建()
tuple()
#将字符串转换成元组<br> tup1 = tuple("hello")<br> print(tup1)<br> #将列表转换成元组<br> list1 = ['Python', 'Java', 'C++', 'JavaScript']<br> tup2 = tuple(list1)<br> print(tup2)<br> #将字典转换成元组<br> dict1 = {'a':100, 'b':42, 'c':9}<br> tup3 = tuple(dict1)<br> print(tup3)<br> #将区间转换成元组<br> range1 = range(1, 6)<br> tup4 = tuple(range1)<br> print(tup4)<br> #创建空元组<br> print(tuple())
查找
通过索引访问列表中的某个元素
listname[i]
listname[start : end : step]
正数序列从0开始,负数序列从-1开始
切片起始位不包含在切片范围中<br>
通过=重新赋值一个新的元组
通过+连接两个元组形成一个新元组
字典(dict)
一种无序的、可变的序列
是 Python 中唯一的映射类型
习惯将各元素对应的索引称为键(key),各个键对应的元素称为值(value),键及其关联的值称为“键值对”
字典特征
新建{ }
dictname = {'key':'value1', 'key2':'value2', ..., 'keyn':valuen}<br>dictname 表示字典变量名,keyn : valuen 表示各个元素的键值对
同一字典中的各个键必须唯一,不能重复
fromkeys()
初始化字典,设置 value 的默认值
dictname = dict.fromkeys(list,value=None)<br>list 参数表示字典中所有键的列表(list);value 参数表示默认值,如果不写,则为空值 None
dict()
创建字典
查找
dictname[key]<br>dictname 表示字典变量的名字,key 表示键名
get()
dictname.get(key[,default])<br>dictname 表示字典变量的名字;key 表示指定的键;default 用于指定要查询的键不存在时,此方法返回的默认值,如果不手动指定,会返回 None
in 或 not in
判断字典中是否有对应的键
a = {'数学': 95, '语文': 89, '英语': 90}<br> # 判断 a 中是否包含名为'数学'的key<br> print('数学' in a) # True<br> # 判断 a 是否包含名为'物理'的key<br> print('物理' in a) # False
keys()
返回字典中的所有键(key)
values()
返回字典中所有键对应的值(value)
items()
返回字典中所有的键值对(key-value)
setdefault()
来返回某个 key 对应的 value
dictname.setdefault(key, defaultvalue)<br>dictname 表示字典名称,key 表示键,defaultvalue 表示默认值(可以不写,不写的话是 None)
当指定的 key 不存在时,setdefault() 会先为这个不存在的 key 设置一个默认的 defaultvalue,然后再返回 defaultvalue
setdefault() 方法总能返回指定 key 对应的 value:<br><br> 如果该 key 存在,那么直接返回该 key 对应的 value;<br> 如果该 key 不存在,那么先为该 key 设置默认的 defaultvalue,然后再返回该 key 对应的 defaultvalue。<br>
编辑<br>
添加键值对
dictname[key] = value<br> dictname 表示字典名称。<br> key 表示新的键。<br> value 表示新的值,只要是 Python 支持的数据类型都可以。<br>
copy() <br>
一个具有相同键值对的新字典
浅拷贝
指的是重新分配一块内存,创建一个新的对象,但里面的元素是原对象中各个子对象的引用
变量赋值
list1 = [1, 2, 3]<br>list2 = list(list1)<br> <br>set1= set([1, 2, 3])<br>set2 = set(set1)
copy.copy() 函数
import copy<br>list1 = [1, 2, 3]<br>list2 = copy.copy(list1)
深拷贝
重新分配一块内存,创建一个新的对象,并且将原对象中的元素,以递归的方式,通过创建新的子对象拷贝到新对象中
copy.deepcopy()
import copy<br>list1 = [[1, 2], (30, 40)]<br>list2 = copy.deepcopy(list1)
update()
使用一个字典所包含的键值对来更新己有的字典
删除<br>
del
# 使用del语句删除键值对<br>a = {'数学': 95, '语文': 89, '英语': 90}<br>del a['语文']<br>del a['数学']
pop()
删除指定的键值对
dictname.pop(key)<br>dictname.popitem()<br>dictname 表示字典名称,key 表示键。
popitem()
随机删除一个键值对
集合(set)
用来保存不重复的元素,即集合中的元素都是唯一的,互不相同
集合会将所有元素放在一对大括号 {} 中,相邻元素之间用“,”分隔
同一集合中,只能存储不可变的数据类型,包括整形、浮点型、字符串、元组,无法存储列表、字典、集合这些可变的数据类型
另一种 frozenset 类型的集合
不可以做添加、删除元素的操作
新建{}<br>
{}赋值
a = {1,'c',1,(1,2,3),'c'}
set()
setname = set(iteration)<br>iteration 就表示字符串、列表、元组、range 对象等数据
如果要创建空集合,只能使用 set() 函数实现。因为直接使用一对 {},Python 解释器会将其视为一个空字典
查找
for循环语句
a = {1,'c',1,(1,2,3),'c'}<br> for ele in a:<br> print(ele,end=' ')
编辑
add()
setname.add(element)<br>setname 表示要添加元素的集合,element 表示要添加的元素内容
remove()
删除元素
setname.remove(element)
如果被删除元素本就不包含在集合中,则此方法会抛出 KeyError 错误
集合运算
交集、并集、差集
<br>
总表
<br>
<br>
<br>
<br>
frozenset集合
frozenset 集合是不可变序列,程序不能改变序列中的元素
set 集合中所有能改变集合本身的方法,比如 remove()、discard()、add() 等,frozenset 都不支持;set 集合中不改变集合本身的方法,fronzenset 都支持
>>> dir(frozenset)<br>['copy', 'difference', 'intersection', 'isdisjoint', 'issubset', 'issuperset', 'symmetric_difference', 'union']
集合和字典不支持索引、切片、相加和相乘操作。
推导式
列表推导式/列表生成式
基本格式
variable = [out_exp_res for out_exp in input_list if out_exp == 2]
out_exp_res:列表生成元素表达式,可以是有返回值的函数。<br> for out_exp in input_list:迭代input_list将out_exp传入out_exp_res表达式中。<br> if out_exp == 2:根据条件过滤哪些值可以
例
list3=[i for i in range(10)]<br>print(list3)<br>#[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
list4=[i for i in range(0,10,2)]<br>print(list4) #[0, 2, 4, 6, 8]
list5=[i for i in range(0,10) if i%2==0]<br>print(list5) <br>#[0, 2, 4, 6, 8]
list5=[]<br>for i in range(1,3):<br> for j in range(3):<br> list5.append((i,j))<br><br>print(list5)<br>#[(1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
list6=[(i,j) for i in range(1,3) for j in range(3)]<br>print(list6)<br>#[(1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
multiples = [i for i in range(30) if i % 3 is 0]<br>print(multiples)<br># Output: [0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
def squared(x):<br> return x*x<br>multiples = [squared(i) for i in range(30) if i % 3 is 0]<br>print multiples<br># Output: [0, 9, 36, 81, 144, 225, 324, 441, 576, 729]
使用()生成generator
multiples = (i for i in range(30) if i % 3 is 0)<br>print(type(multiples))<br># Output: <type 'generator'>
字典推导式
字典推导和列表推导的使用方法是类似的,中括号该改成大括号
例
dict1={i: i**2 for i in range(1,5)}<br>print(dict1) #{1: 1, 2: 4, 3: 9, 4: 16}
list1=['name', 'age','gender']<br>list=['Tom',20,'男']<br>dict2={list1[i]:list[i] for i in range(len(list1))}<br>print(dict2) #{'name': 'Tom', 'age': 20, 'gender': '男'}
counts={'MBP':220,'hp':123,'dell':125,'lenovo':199,'acer':99}<br><br>count1={key:value for key ,value in counts.items() if value >=200}<br>print(count1)<br> #{'MBP': 220}<br>
大小写key合并
mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3}<br>mcase_frequency = {<br> k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0)<br> for k in mcase.keys()<br> if k.lower() in ['a','b']<br>}<br>print mcase_frequency<br># Output: {'a': 17, 'b': 34}
快速更换key和value
mcase = {'a': 10, 'b': 34}<br>mcase_frequency = {v: k for k, v in mcase.items()}<br>print mcase_frequency<br># Output: {10: 'a', 34: 'b'}
集合推导式
squared = {x**2 for x in [1, 1, 2]}<br>print(squared)<br># Output: set([1, 4])
list1=[1,1,2]<br>set1={i: i**2 for i in list1}<br>print(set1) #{1: 1, 2: 4}
类和对象
概要
class tortoise:<br> bodyColor = "绿色"<br> footNum = 4<br> weight = 10<br> hasShell = True<br> #会爬<br> def crawl(self):<br> print("乌龟会爬")<br> #会吃东西<br> def eat(self):<br> print("乌龟吃东西")<br> #会睡觉<br> def sleep(self):<br> print("乌龟在睡觉")<br> #会缩到壳里<br> def protect(self):<br> print("乌龟缩进了壳里")
类:可以理解是一个模板,通过它可以创建出无数个具体实例。<br>
比如,前面编写的 tortoise 表示的只是乌龟这个物种,通过它可以创建出无数个实例来代表各种不同特征的乌龟(这一过程又称为类的实例化)。
对象:类并不能直接使用,通过类创建出的实例(又称对象)才能使用。<br>
这有点像汽车图纸和汽车的关系,图纸本身(类)并不能为人们使用,通过图纸创建出的一辆辆车(对象)才能使用。
属性:类中的所有变量称为属性。
例如,tortoise 这个类中,bodyColor、footNum、weight、hasShell 都是这个类拥有的属性。
方法:类中的所有函数通常称为方法。
和函数所有不同的是,类方法至少要包含一个 self 参数。<br>例如,tortoise 类中,crawl()、eat()、sleep()、protect() 都是这个类所拥有的方法,类方法无法单独使用,只能和类的对象一起使用。
class 定义类
在创建类对象时,无需给 self 传参
创建类对象的过程,又称为类的实例化
类变量和实例变量
定义在各个类方法之外(包含在类中)的变量为类变量(或者类属性)<br>定义在类方法中的变量为实例变量(或者实例属性)<br>
概要
类名通用习惯为首字母大写
类是模板,而实例则是根据类创建的对象
class 类名:<br> 多个(≥0)类属性...<br> 多个(≥0)类方法...
class TheFirstDemo:<br> '''这是一个学习Python定义的第一个类'''<br> # 下面定义了一个类属性<br> add = 'http://c.biancheng.net'<br> # 下面定义了一个say方法<br> def say(self, content):<br> print(content)
脑图参考
实例属性
用于区分不同的实例
class Circle(object): # 创建Circle类,Circle为类名<br> pass # 此处可添加属性和方法<br># 创建两个Circle类的实例<br>circle1= Circle()<br>circle2= Circle()<br># 为circle1、circle2 圆实例添加半径 r 这个属性并赋值<br>circle1.r = 1 # r为实例属性<br>circle2.R= 2 <br>print(circle1.r) # 使用 实例名.属性名 可以访问我们的属性<br>print(circle2.R)<br>
circle1 = Circle(1) # 创建实例时直接给定实例属性,self不算在内<br>circle2 = Circle(2)<br>print(circle1.r) # 实例名.属性名 访问属性<br>print(circle2.r) # 我们调用实例属性的名称就统一了
每次在创建类后,再为实例添加属性会比较麻烦<br>创建实例时给类初始属性,_init__() 方法被自动调用为创建的实例增加实例属性<br>
__init__() 方法<br>构造方法(或构造函数)<br>
def __init__(self,...):<br> 代码块
__init__() 方法可以包含多个参数,但必须包含一个名为 self 的参数,且必须作为第一个参数<br>类的构造方法最少也要有一个 self 参数<br>
class Circle(object): # 创建Circle类<br> def __init__(self, r): # 初始化一个属性r(不要忘记self参数,他是类下面所有方法必须的参数)<br> self.r = r # 表示给我们将要创建的实例赋予属性r赋值
__init__() 方法的第一个参数必须是 self(self代表类的实例,可以用别的名字,但建议使用约定成俗的self)<br>后续参数则可以自由指定,和定义函数没有任何区别<br>
self 代表类的实例,是通过类创建的实例
class TheFirstDemo:<br> '''这是一个学习Python定义的第一个类'''<br> #构造方法<br> def __init__(self):<br> print("调用构造方法")<br> # 下面定义了一个类属性<br> add = 'http://c.biancheng.net'<br> # 下面定义了一个say方法<br> def say(self, content):<br> print(content)
类属性
每个实例的共有属性
实例属性访问优先级比类属性高
类体中、所有函数之外:此范围定义的变量,称为类属性或类变量;<br>类体中,所有函数内部:以“self.变量名”的方式定义的变量,称为实例属性或实例变量;<br>类体中,所有函数内部:以“变量名=变量值”的方式定义的变量,称为局部变量
Python 类中如果有属性不希望被外部访问,我们可以在属性命名时以双下划线开头( __ ),那么该属性就不能使用原变量名访问,使得该属性变为本类私有的(伪私有)<br>但,如果一个属性以"__xxx__"的形式定义,那么它可以被外部访问。以"__xxx__"定义的属性在 Python 的类中是特殊属性<br>有很多预定义的特殊属性都是以“__xxx__”定义,所以我们不要把普通属性用"__xxx__" 定义
# 圆类Circle的示例,我们将pi属性开头加上双下划线变成私有属性:<br><br>class Circle(object):<br> __pi = 3.14<br><br> def __init__(self, r):<br> self.r = r<br><br> def area(self):<br> """<br>圆的面积<br> """<br> return self.r **2* self.__pi<br><br>circle1 = Circle(1)<br>print(Circle.__pi) # 抛出AttributeError异常<br>print(circle1.__pi) # 抛出AttributeError异常
实例属性每个实例各自拥有,互相独立,而类属性有且只有一份
class Circle(object):<br> pi = 3.14 # 类属性<br><br> def __init__(self, r):<br> self.r = r<br><br>circle1 = Circle(1)<br>circle2 = Circle(2)<br>print('----未修改前-----')<br>print('pi=\t', Circle.pi)<br>print('circle1.pi=\t', circle1.pi) # 3.14<br>print('circle2.pi=\t', circle2.pi) # 3.14<br>print('----通过类名修改后-----')<br>Circle.pi = 3.14159 # 通过类名修改类属性,所有实例的类属性被改变<br>print('pi=\t', Circle.pi) # 3.14159<br>print('circle1.pi=\t', circle1.pi) # 3.14159<br>print('circle2.pi=\t', circle2.pi) # 3.14159<br>print('----通过circle1实例名修改后-----')<br>circle1.pi=3.14111 # 实际上这里是给circle1创建了一个与类属性同名的实例属性<br>print('pi=\t', Circle.pi) # 3.14159<br>print('circle1.pi=\t', circle1.pi) # 实例属性的访问优先级比类属性高,所以是3.14111 <br>print('circle2.pi=\t', circle2.pi) # 3.14159<br>print('----删除circle1实例属性pi-----')
实例方法
表明这个类用是来做什么
类的内部,使用 def 关键字来定义方法,与一般函数定义不同,类方法必须第一个参数为 self, self 代表的是类的实例(即你还未创建类的实例),其他参数和普通函数是完全一样
class Circle(object):<br> pi = 3.14 # 类属性<br><br> def __init__(self, r):<br> self.r = r # 实例属性<br><br> def get_area(self):<br> """ 圆的面积 """<br> # return self.r**2 * Circle.pi # 通过实例修改pi的值对面积无影响,这个pi为类属性的值<br> return self.r**2 * self.pi # 通过实例修改pi的值对面积我们圆的面积就会改变<br><br>circle1 = Circle(2)<br>print(circle1.get_area()) # 调用方法 self不需要传入参数,不要忘记方法后的括号
参数传递图
类中的字段
字段的访问级别:<br>Python中以双下划线开头的字段访问级别是private;<br>Python中以下划线开头的字段访问级别是protected;<br>Python中未以下划线开头的字段的访问级别是public<br>上述访问级别更多的是一种编程约定,即便是以双下划线开头的字段,在类的外部也是可以访问的,但不建议这么做
class Person():<br> age = 24<br> _name = 'person'<br> __family_name = 'securate'<br><br> def __init__(self):<br> print('Person init')
方法的覆盖<br>
Python类中没有方法的重载,对于具有相同名称的方法,后面的定义会覆盖掉前面的定义;子类会覆盖父类中同名的方法。在Person类中定义两个同名方法say
def say(self, message):<br> print(message)<br> def say(self, info):<br> print('second: '+info)<br><br><br>person=Person()<br>person.say('invoke')
特殊方法
特殊方法<br>以双下划线开头和结尾的方法属于特殊方法,如:__init__(self)、__call__(self)等内置方法。在我们自己定义方法时不建议采取这种方式
方法的访问级别<br>Python中以双下划线开头的方法访问级别是private;<br>Python中以下划线开头的方法访问级别是protected;<br>Python中未以下划线开头的方法的访问级别是public;<br>和字段类似,上述访问级别也只是一种编程约定,即便是以双下划线开头的方法,在类的外部也是可以访问的,但不建议这么做<br> <br>著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
描述符
在引用一个对象属性时自定义要完成的工作
描述符是 Python 中复杂属性访问的基础,它在内部被用于实现 property、方法、类方法、静态方法和 super 类型。
3 个方法组成了描述符协议:<br>__set__(self, obj, type=None):在设置属性时将调用这一方法 ;<br>__get__(self, obj, value):在读取属性时将调用这一方法 ;<br>__delete__(self, obj):对属性调用 del 时将调用这一方法。<br>其中,实现了 setter 和 getter 方法的描述符类被称为数据描述符;反之,如果只实现了 getter 方法,则称为非数据描述符。
class CLanguage:<br> #构造函数<br> def __init__(self,name):<br> self.name = name <br> #设置 name 属性值的函数 <br> def setname(self,name):<br> self.name = name<br> #访问nema属性值的函数<br> def getname(self):<br> return self.name<br> #删除name属性值的函数<br> def delname(self):<br> self.name="xxx"
property() 函数
在不破坏类封装原则的前提下,让开发者依旧使用“类对象.属性”的方式操作类中的属性
属性名=property(fget=None, fset=None, fdel=None, doc=None)
get 参数用于指定获取该属性值的类方法,fset 参数用于指定设置该属性值的方法,fdel 参数用于指定删除该属性值的方法,最后的 doc 是一个文档字符串,用于说明此函数的作用
在使用 property() 函数时,以上 4 个参数可以仅指定第 1 个、或者前 2 个、或者前 3 个,当前也可以全部指定
@property 装饰器
直接通过方法名来访问方法,不需要在方法名后添加一对“()”小括号
@property<br>def 方法名(self)<br> 代码块
class Rect:<br> def __init__(self,area):<br> self.__area = area<br> @property<br> def area(self):<br> return self.__area<br>rect = Rect(30)<br>#直接通过方法名来访问 area 方法<br>print("矩形的面积是:",rect.area)
@deleter 装饰器
删除指定属性
@方法名.deleter<br>def 方法名(self):<br> 代码块
@area.deleter<br>def area(self):<br> self.__area = 0<br> <br>del rect.area<br>print("删除后的area值为:",rect.area)
子类
class 类名(父类1, 父类2, ...):<br> #类定义部分
class People:<br> def say(self):<br> print("我是一个人,名字是:",self.name)<br>class Animal:<br> def display(self):<br> print("人也是高级动物")<br>#同时继承 People 和 Animal 类<br>#其同时拥有 name 属性、say() 和 display() 方法<br>class Person(People, Animal):<br> pass<br>zhangsan = Person()<br>zhangsan.name = "张三"<br>zhangsan.say()<br>zhangsan.display()
如果该类没有显式指定继承自哪个类,则默认继承 object 类(object 类是 Python 中所有类的父类,即要么是直接父类,要么是间接父类)。另外,Python 的继承是多继承机制(和 C++ 一样),即一个子类可以同时拥有多个直接父类。
根据子类继承多个父类时这些父类的前后次序决定,即排在前面父类中的类方法会覆盖排在后面父类中的同名类方法
class People:<br> def __init__(self):<br> self.name = People<br> def say(self):<br> print("People类",self.name)<br>class Animal:<br> def __init__(self):<br> self.name = Animal<br> def say(self):<br> print("Animal类",self.name)<br>#People中的 name 属性和 say() 会遮蔽 Animal 类中的<br>class Person(People, Animal):<br> pass<br>zhangsan = Person()<br>zhangsan.name = "张三"<br>zhangsan.say()
子类还会继承父类中的函数,若子类没有实现自己的构造函数(__init__(self)),那么在实例化子类时会调用父类的构造函数。
方法解析顺序(Method Resolution Order),简称 MRO
Python 发展至今,经历了以下 3 种 MRO 算法,分别是:<br>从左往右,采用深度优先搜索(DFS)的算法,称为旧式类的 MRO;<br>自 Python 2.2 版本开始,新式类在采用深度优先搜索算法的基础上,对其做了优化;<br>自 Python 2.3 版本,对新式类采用了 C3 算法。由于 Python 3.x 仅支持新式类,所以该版本只使用 C3 算法
父类方法重写
鸟通常是有翅膀的,也会飞,因此我们可以像如下这样定义个和鸟相关的类:<br> <br>class Bird:<br> #鸟有翅膀<br> def isWing(self):<br> print("鸟有翅膀")<br> #鸟会飞<br> def fly(self):<br> print("鸟会飞")
对于鸵鸟来说,它虽然也属于鸟类,也有翅膀,但是它只会奔跑,并不会飞。针对这种情况,可以这样定义鸵鸟类:<br>class Ostrich(Bird):<br> # 重写Bird类的fly()方法<br> def fly(self):<br> print("鸵鸟不会飞")
重写,有时又称覆盖,是一个意思,指的是对类中已有方法的内部实现进行修改
类的多态特性,还要满足以下 2 个前提条件:<br>继承:多态一定是发生在子类和父类之间;<br>重写:子类重写了父类的方法。
class CLanguage:<br> def say(self):<br> print("调用的是 Clanguage 类的say方法")<br>class CPython(CLanguage):<br> def say(self):<br> print("调用的是 CPython 类的say方法")<br>class CLinux(CLanguage):<br> def say(self):<br> print("调用的是 CLinux 类的say方法")<br>a = CLanguage()<br>a.say()<br>a = CPython()<br>a.say()<br>a = CLinux()<br>a.say()
class WhoSay:<br> def say(self,who):<br> who.say()<br>class CLanguage:<br> def say(self):<br> print("调用的是 Clanguage 类的say方法")<br>class CPython(CLanguage):<br> def say(self):<br> print("调用的是 CPython 类的say方法")<br>class CLinux(CLanguage):<br> def say(self):<br> print("调用的是 CLinux 类的say方法")<br>a = WhoSay()<br>#调用 CLanguage 类的 say() 方法<br>a.say(CLanguage())<br>#调用 CPython 类的 say() 方法<br>a.say(CPython())<br>#调用 CLinux 类的 say() 方法<br>a.say(CLinux())
通过给 WhoSay 类中的 say() 函数添加一个 who 参数,其内部利用传入的 who 调用 say() 方法。这意味着,当调用 WhoSay 类中的 say() 方法时,我们传给 who 参数的是哪个类的实例对象,它就会调用那个类中的 say() 方法。<br> Python 这种由多态衍生出的更灵活的编程机制,又称为“鸭子模型”或“鸭子类型”
内置类型子类化
自定义一个新类,使其继承有类似行为的内置类,通过重定义这个新类实现指定的功能
list 类型用来管理序列,如果一个类需要在内部处理序列,那么就可以对 list 进行子类化
class myList(list):<br> def __init__(self,name):<br> self.name = name<br> def dir(self,nesting = 0):<br> offset = " " * nesting<br> print("%s%s/" % (offset,self.name))<br> for element in self:<br> if hasattr(element , 'dir'):<br> element.dir(nesting + 1)<br> else:<br> print("%s %s" % (offset,element))<br>demoList = myList('C语言中文网')<br>demoList.append('http://c.biancheng.net')<br>print(demoList.dir())
super()函数<br>调用父类的构造方法<br>
super().__init__(self,...)
class People:<br> def __init__(self,name):<br> self.name = name<br> def say(self):<br> print("我是人,名字为:",self.name)<br>class Animal:<br> def __init__(self,food):<br> self.food = food<br> def display(self):<br> print("我是动物,我吃",self.food)<br>class Person(People, Animal):<br> #自定义构造方法<br> def __init__(self,name,food):<br> #调用 People 类的构造方法<br> super().__init__(name)<br> #super(Person,self).__init__(name) #执行效果和上一行相同<br> #People.__init__(self,name)#使用未绑定方法调用 People 类构造方法<br> #调用其它父类的构造方法,需手动给 self 传值<br> Animal.__init__(self,food) <br>per = Person("zhangsan","熟食")<br>per.say()<br>per.display()
子类中的构造方法中,调用父类构造方法的方式有 2 种,分别是:<br>类可以看做一个独立空间,在类的外部调用其中的实例方法,可以向调用普通函数那样,只不过需要额外备注类名(此方式又称为未绑定方法);<br>使用 super() 函数。但如果涉及多继承,该函数只能调用第一个直接父类的构造方法
尽可能避免使用多继承,可以使用一些设计模式来替代它;<br>super 的使用必须一致,即在类的层次结构中,要么全部使用 super,要么全不用。混用 super 和传统调用是一种混乱的写法;<br>如果代码需要兼容 Python 2.x,在 Python 3.x 中应该显式地继承自 object。在 Python 2.x 中,没有指定任何祖先地类都被认定为旧式类。<br>调用父类时应提前查看类的层次结构,也就是使用类的 __mro__ 属性或者 mro() 方法查看有关类的 MRO
type()函数<br>动态创建类
type(obj) <br>type(name, bases, dict)<br><br>以上这 2 种语法格式,各参数的含义及功能分别是:<br>第一种语法格式用来查看某个变量(类对象)的具体类型,obj 表示某个变量或者类对象。<br>第二种语法格式用来创建类,其中 name 表示类的名称;bases 表示一个元组,其中存储的是该类的父类;dict 表示一个字典,用于表示类内定义的属性或者方法。
MetaClass元类
Enum 枚举类
from enum import Enum<br>class Color(Enum):<br> # 为序列值指定value值<br> red = 1<br> green = 2<br> blue = 3
__new__()
一种负责创建类实例的静态方法,它无需使用 staticmethod 装饰器修饰,且该方法会优先 __init__() 初始化方法被调用
class demoClass:<br> instances_created = 0<br> def __new__(cls,*args,**kwargs):<br> print("__new__():",cls,args,kwargs)<br> instance = super().__new__(cls)<br> instance.number = cls.instances_created<br> cls.instances_created += 1<br> return instance<br> def __init__(self,attribute):<br> print("__init__():",self,attribute)<br> self.attribute = attribute<br>test1 = demoClass("abc")<br>test2 = demoClass("xyz")<br>print(test1.number,test1.instances_created)<br>print(test2.number,test2.instances_created)
class nonZero(int):<br> def __new__(cls,value):<br> return super().__new__(cls,value) if value != 0 else None<br> def __init__(self,skipped_value):<br> #此例中会跳过此方法<br> print("__init__()")<br> super().__init__()<br>print(type(nonZero(-12)))<br>print(type(nonZero(0)))
__repr__()方法<br>显示属性<br>
class CLanguage:<br> def __init__(self):<br> self.name = "C语言中文网"<br> self.add = "http://c.biancheng.net"<br> def __repr__(self):<br> return "CLanguage[name="+ self.name +",add=" + self.add +"]"<br>clangs = CLanguage()<br>print(clangs)
__del__()方法<br>销毁对象<br>
如果之前创建的类实例化对象后续不再使用,最好在适当位置手动将其销毁,释放其占用的内存空间(整个过程称为垃圾回收(简称GC))
Python 采用自动引用计数(简称 ARC)的方式实现垃圾回收机制。该方法的核心思想是:每个 Python 对象都会配置一个计数器,初始 Python 实例对象的计数器值都为 0,如果有变量引用该实例对象,其计数器的值会加 1,依次类推;反之,每当一个变量取消对该实例对象的引用,计数器会减 1。如果一个 Python 对象的的计数器值为 0,则表明没有变量引用该 Python 对象,即证明程序不再需要它,此时 Python 就会自动调用 __del__() 方法将其回收。
__dir__()用法<br>列出对象的所有属性(方法)名<br>
通过此函数可以某个对象拥有的所有的属性名和方法名,该函数会返回一个包含有所有属性名和方法名的有序列表
class CLanguage:<br> def __init__ (self,):<br> self.name = "C语言中文网"<br> self.add = "http://c.biancheng.net"<br> def say():<br> pass<br>clangs = CLanguage()<br>print(dir(clangs))
class CLanguage:<br> def __init__ (self,):<br> self.name = "C语言中文网"<br> self.add = "http://c.biancheng.net"<br> def say():<br> pass<br>clangs = CLanguage()<br>print(clangs.__dir__())
__dict__属性<br>查看对象内部所有属性名和属性值组成的字典<br>
该属性可以用类名或者类的实例对象来调用,用类名直接调用 __dict__,会输出该由类中所有类属性组成的字典<br>而使用类的实例对象调用 __dict__,会输出由类中所有实例属性组成的字典 <br>
class CLanguage:<br> a = 1<br> b = 2<br> def __init__ (self):<br> self.name = "C语言中文网"<br> self.add = "http://c.biancheng.net"<br> <br>class CL(CLanguage):<br> c = 1<br> d = 2<br> def __init__ (self):<br> self.na = "Python教程"<br> self.ad = "http://c.biancheng.net/python"<br>#父类名调用__dict__<br>print(CLanguage.__dict__)<br>#子类名调用__dict__<br>print(CL.__dict__)<br>#父类实例对象调用 __dict__<br>clangs = CLanguage()<br>print(clangs.__dict__)<br>#子类实例对象调用 __dict__<br>cl = CL()<br>print(cl.__dict__)
对于具有继承关系的父类和子类来说,父类有自己的 __dict__,同样子类也有自己的 __dict__,它不会包含父类的 __dict__
借助由类实例对象调用 __dict__ 属性获取的字典,可以使用字典的方式对其中实例属性的值进行修改
class CLanguage:<br> a = "aaa"<br> b = 2<br> def __init__ (self):<br> self.name = "C语言中文网"<br> self.add = "http://c.biancheng.net"<br>#通过类实例对象调用 __dict__<br>clangs = CLanguage()<br>print(clangs.__dict__)<br>clangs.__dict__['name'] = "Python教程"<br>print(clangs.name)
setattr()
判断某个类实例对象是否包含指定名称的属性或方法
hasattr(obj, name)<br><br>其中 obj 指的是某个类的实例对象,name 表示指定的属性名或方法名。同时,该函数会将判断的结果(True 或者 False)作为返回值反馈回来
class CLanguage:<br> def __init__ (self):<br> self.name = "C语言中文网"<br> self.add = "http://c.biancheng.net"<br> def say(self):<br> print("我正在学Python")<br>clangs = CLanguage()<br>print(hasattr(clangs,"name"))<br>print(hasattr(clangs,"add"))<br>print(hasattr(clangs,"say"))
getattr()
获取某个类实例对象中指定属性的值
getattr(obj, name[, default])<br><br>其中,obj 表示指定的类实例对象,name 表示指定的属性名,而 default 是可选参数,用于设定该函数的默认返回值,即当函数查找失败时,如果不指定 default 参数,则程序将直接报 AttributeError 错误,反之该函数将返回 default 指定的值
class CLanguage:<br> def __init__ (self):<br> self.name = "C语言中文网"<br> self.add = "http://c.biancheng.net"<br> def say(self):<br> print("我正在学Python")<br>clangs = CLanguage()<br>print(getattr(clangs,"name"))<br>print(getattr(clangs,"add"))<br>print(getattr(clangs,"say"))<br>print(getattr(clangs,"display",'nodisplay'))
对于类中已有的属性,getattr() 会返回它们的值,而如果该名称为方法名,则返回该方法的状态信息;反之,如果该明白不为类对象所有,要么返回默认的参数,要么程序报 AttributeError 错误
hasattr()
功能相对比较复杂,它最基础的功能是修改类实例对象中的属性值。其次,它还可以实现为实例对象动态添加属性或者方法
setattr(obj, name, value)
class CLanguage:<br> def __init__ (self):<br> self.name = "C语言中文网"<br> self.add = "http://c.biancheng.net"<br> def say(self):<br> print("我正在学Python")<br>clangs = CLanguage()<br>print(clangs.name)<br>print(clangs.add)<br>setattr(clangs,"name","Python教程")<br>setattr(clangs,"add","http://c.biancheng.net/python")<br>print(clangs.name)<br>print(clangs.add)
利用 setattr() 函数,还可以将类属性修改为一个类方法,同样也可以将类方法修改成一个类属性
def say(self):<br> print("我正在学Python")<br>class CLanguage:<br> def __init__ (self):<br> self.name = "C语言中文网"<br> self.add = "http://c.biancheng.net"<br>clangs = CLanguage()<br>print(clangs.name)<br>print(clangs.add)<br>setattr(clangs,"name",say)<br>clangs.name(clangs)
使用 setattr() 函数对实例对象中执行名称的属性或方法进行修改时,如果该名称查找失败,Python 解释器不会报错,而是会给该实例对象动态添加一个指定名称的属性或方法
def say(self):<br> print("我正在学Python")<br>class CLanguage:<br> pass<br>clangs = CLanguage()<br>setattr(clangs,"name","C语言中文网")<br>setattr(clangs,"say",say)<br>print(clangs.name)<br>clangs.say(clangs)
检查类型
issubclass(cls, class_or_tuple):检查 cls 是否为后一个类或元组包含的多个类中任意类的子类。
isinstance(obj, class_or_tuple):检查 obj 是否为后一个类或元组包含的多个类中任意类的对象
# 定义一个字符串<br>hello = "Hello";<br># "Hello"是str类的实例,输出True<br>print('"Hello"是否是str类的实例: ', isinstance(hello, str))<br># "Hello"是object类的子类的实例,输出True<br>print('"Hello"是否是object类的实例: ', isinstance(hello, object))<br># str是object类的子类,输出True<br>print('str是否是object类的子类: ', issubclass(str, object))<br># "Hello"不是tuple类及其子类的实例,输出False<br>print('"Hello"是否是tuple类的实例: ', isinstance(hello, tuple))<br># str不是tuple类的子类,输出False<br>print('str是否是tuple类的子类: ', issubclass(str, tuple))<br># 定义一个列表<br>my_list = [2, 4]<br># [2, 4]是list类的实例,输出True<br>print('[2, 4]是否是list类的实例: ', isinstance(my_list, list))<br># [2, 4]是object类的子类的实例,输出True<br>print('[2, 4]是否是object类及其子类的实例: ', isinstance(my_list, object))<br># list是object类的子类,输出True<br>print('list是否是object类的子类: ', issubclass(list, object))<br># [2, 4]不是tuple类及其子类的实例,输出False<br>print('[2, 4]是否是tuple类及其子类的实例: ', isinstance([2, 4], tuple))<br># list不是tuple类的子类,输出False<br>print('list是否是tuple类的子类: ', issubclass(list, tuple))
issubclass() 和 isinstance() 两个函数的用法差不多,区别只是 issubclass() 的第一个参数是类名,而 isinstance() 的第一个参数是变量,这也与两个函数的意义对应:issubclass 用于判断是否为子类,而 isinstance() 用于判断是否为该类或子类的实例
issubclass() 和 isinstance() 两个函数的第二个参数都可使用元组
data = (20, 'fkit')<br>print('data是否为列表或元组: ', isinstance(data, (list, tuple))) # True<br># str不是list或者tuple的子类,输出False<br>print('str是否为list或tuple的子类: ', issubclass(str, (list, tuple)))<br># str是list或tuple或object的子类,输出True<br>print('str是否为list或tuple或object的子类 ', issubclass(str, (list, tuple, object)))
Python 为所有类都提供了一个 __bases__ 属性,通过该属性可以查看该类的所有直接父类,该属性返回所有直接父类组成的元组
class A:<br> pass<br>class B:<br> pass<br>class C(A, B):<br> pass<br>print('类A的所有父类:', A.__bases__)<br>print('类B的所有父类:', B.__bases__)<br>print('类C的所有父类:', C.__bases__)
__call__()方法
该方法的功能类似于在类中重载 () 运算符,使得类实例对象可以像调用普通函数那样,以“对象名()”的形式使用
class CLanguage:<br> # 定义__call__方法<br> def __call__(self,name,add):<br> print("调用__call__()方法",name,add)<br>clangs = CLanguage()<br>clangs("C语言中文网","http://c.biancheng.net")
Python 中,凡是可以将 () 直接应用到自身并执行,都称为可调用对象。可调用对象包括自定义的函数、Python 内置函数以及本节所讲的类实例对象。
运算符重载
在类中定义并实现一个与运算符对应的处理方法,这样当类对象在进行运算符操作时,系统就会调用类中相应的方法来处理
在 Python 内部,每种序列类型都是 Python 的一个类,例如列表是 list 类,字典是 dict 类等,这些序列类的内部使用了一个叫作“重载运算符”的技术来实现不同运算符所对应的操作
class MyClass: #自定义一个类<br> def __init__(self, name , age): #定义该类的初始化函数<br> self.name = name #将传入的参数值赋值给成员交量<br> self.age = age<br> def __str__(self): #用于将值转化为字符串形式,等同于 str(obj)<br> return "name:"+self.name+";age:"+str(self.age)<br> <br> __repr__ = __str__ #转化为供解释器读取的形式<br> <br> def __lt__(self, record): #重载 self<record 运算符<br> if self.age < record.age:<br> return True<br> else:<br> return False<br> <br> def __add__(self, record): #重载 + 号运算符<br> return MyClass(self.name, self.age+record.age)<br>myc = MyClass("Anna", 42) #实例化一个对象 Anna,并为其初始化<br>mycl = MyClass("Gary", 23) #实例化一个对象 Gary,并为其初始化<br>print(repr(myc)) #格式化对象 myc,<br>print(myc) #解释器读取对象 myc,调用 repr<br>print (str (myc)) #格式化对象 myc ,输出"name:Anna;age:42"<br>print(myc < mycl) #比较 myc<mycl 的结果,输出 False<br>print (myc+mycl) #进行两个 MyClass 对象的相加运算,输出 "name:Anna;age:65"
常用重载运算符
Python 可重载的运算符中,有如下几个和序列操作相关的特殊方法:<br>__len__(self):该方法的返回值决定序列中元素的个数。<br>__getitem__(self, key):该方法获取指定索引对应的元素。该方法的 key 应该是整数值或 slice 对象,否则该方法会引发 KeyError 异常。<br>__contains__(self, item):该方法判断序列是否包含指定元素。<br>__setitem__(self, key, value):该方法设置指定索引对应的元素。该方法的 key 应该是整数值或 slice 对象,否则该方法会引发 KeyError 异常。<br>__delitem__(self, key):该方法删除指定索引对应的元素。<br><br>在此基础上,如果根据特定的需求对这些方法进行重载,即可实现自定义一个序列类。<br>如果程序要实现不可变序列(程序只能获取序列中的元素,不能修改),只要实现上面前 3 个方法就行;如果程序要实现可变序列(程序既能获取序列中的元素,也可修改),则需要实现上面 5 个方法。
迭代器
列表(list)、元组(tuple)、字典(dict)、集合(set)序列式容器有一个共同的特性<br>它们都支持使用 for 循环遍历存储的元素,都是可迭代的<br>因此它们又有一个别称,即迭代器<br>
如果要自定义实现一个迭代器,则类中必须实现如下 2 个方法:<br>__next__(self):返回容器的下一个元素。<br>__iter__(self):该方法返回一个迭代器(iterator)
iter() 函数
iter(obj[, sentinel])<br><br>其中,obj 必须是一个可迭代的容器对象,而 sentinel 作为可选参数,如果使用此参数,要求 obj 必须是一个可调用对象
可调用对象,指的是该类的实例对象可以像函数那样,直接以“对象名()”的形式被使用。通过在类中添加 __call__() 方法,就可以将该类的实例对象编程可调用对象
# 将列表转换为迭代器<br>myIter = iter([1, 2, 3])<br># 依次获取迭代器的下一个元素<br>print(myIter.__next__())<br>print(myIter.__next__())<br>print(myIter.__next__())<br>print(myIter.__next__())
iter() 函数第 2 个参数<br>如果使用该参数,则要求第一个 obj 参数必须传入可调用对象(可以不支持迭代)<br>当使用返回的迭代器调用 __next__() 方法时,它会通过执行 obj() 调用 __call__() 方法<br>如果该方法的返回值和第 2 个参数值相同,则输出 StopInteration 异常;反之,则输出 __call__() 方法的返回值<br>
class Reverse:<br> def __init__(self, string):<br> self.__string = string<br> self.__index = len(string)<br> def __iter__(self):<br> return self<br> def __next__(self):<br> if self.__index == 0:<br> raise(StopIteration)<br> self.__index -= 1<br> return self.__string[self.__index]<br>revstr = Reverse('Python')<br>for c in revstr:<br> print(c,end=" ")
编写迭代器最容易忽视的一个环节,就是在自定义类中加入对循环结束的判断,并抛出 StopIteration 异常<br>只有这么做了,for 循环才会接收到 StopIteration 异常,并当做终止信号来结束循环<br>
生成器
生成器本质上也是迭代器,不过它比较特殊。<br><br>以 list 容器为例,在使用该容器迭代一组数据时,必须事先将所有数据存储到容器中,才能开始迭代;而生成器却不同,它可以实现在迭代的同时生成元素。<br>也就是说,对于可以用某种算法推算得到的多个数据,生成器并不会一次性生成它们,而是什么时候需要,才什么时候生成。<br><br>不仅如此,生成器的创建方式也比迭代器简单很多,大体分为以下 2 步:<br>定义一个以 yield 关键字标识返回值的函数<br>调用刚刚创建的函数,即可创建一个生成器
def intNum():<br> print("开始执行")<br> for i in range(5):<br> yield i<br> print("继续执行")<br>num = intNum()
intNum() 函数的返回值用的是 yield 关键字,而不是 return 关键字,此类函数又成为生成器函数。<br><br>和 return 相比,yield 除了可以返回相应的值,还有一个更重要的功能,即每当程序执行完该语句时,程序就会暂停执行。不仅如此,即便调用生成器函数,Python 解释器也不会执行函数中的代码,它只会返回一个生成器(对象)。<br><br>要想使生成器函数得以执行,或者想使执行完 yield 语句立即暂停的程序得以继续执行,有以下 2 种方式:<br>通过生成器(上面程序中的 num)调用 next() 内置函数或者 __next__() 方法;<br>通过 for 循环遍历生成器。
#调用 next() 内置函数<br>print(next(num))<br>#调用 __next__() 方法<br>print(num.__next__())<br>#通过for循环遍历生成器<br>for i in num:<br> print(i)
分析一个程序的执行流程:<br>1) 首先,在创建有 num 生成器的前提下,通过其调用 next() 内置函数,会使 Python 解释器开始执行 intNum() 生成器函数中的代码,因此会输出“开始执行”,程序会一直执行到yield i,而此时的 i==0,因此 Python 解释器输出“0”。由于受到 yield 的影响,程序会在此处暂停。<br><br>2) 然后,我们使用 num 生成器调用 __next__() 方法,该方法的作用和 next() 函数完全相同(事实上,next() 函数的底层执行的也是 __next__() 方法),它会是程序继续执行,即输出“继续执行”,程序又会执行到yield i,此时 i==1,因此输出“1”,然后程序暂停。<br><br>3) 最后,我们使用 for 循环遍历 num 生成器,之所以能这么做,是因为 for 循环底层会不断地调用 next() 函数,使暂停的程序继续执行,因此会输出后续的结果
send()
通过调用 next() 或者 __next__() 方法,可以实现从外界控制生成器的执行。除此之外,通过 send() 方法,还可以向生成器中传值。<br><br>值得一提的是,send() 方法可带一个参数,也可以不带任何参数(用 None 表示)。其中,当使用不带参数的 send() 方法时,它和 next() 函数的功能完全相同
def intNum():<br> print("开始执行")<br> for i in range(5):<br> yield i<br> print("继续执行")<br>num = intNum()<br>print(num.send(None))<br>print(num.send(None))
虽然 send(None) 的功能是 next() 完全相同,但更推荐使用 next(),不推荐使用 send(None)
def foo():<br> bar_a = yield "hello"<br> bar_b = yield bar_a<br> yield bar_b<br>f = foo()<br>print(f.send(None))<br>print(f.send("C语言中文网"))<br>print(f.send("http://c.biancheng.net"))
此程序的执行流程:<br>1) 首先,构建生成器函数,并利用器创建生成器(对象)f 。<br><br>2) 使用生成器 f 调用无参的 send() 函数,其功能和 next() 函数完全相同,因此开始执行生成器函数,即执行到第一个 yield "hello" 语句,该语句会返回 "hello" 字符串,然后程序停止到此处(注意,此时还未执行对 bar_a 的赋值操作)。<br><br>3) 下面开始使用生成器 f 调用有参的 send() 函数,首先它会将暂停的程序开启,同时还会将其参数“C语言中文网”赋值给当前 yield 语句的接收者,也就是 bar_a 变量。程序一直执行完 yield bar_a 再次暂停,因此会输出“C语言中文网”。<br><br>4) 最后依旧是调用有参的 send() 函数,同样它会启动餐厅的程序,同时将参数“http://c.biancheng.net”传给 bar_b,然后执行完 yield bar_b 后(输出 http://c.biancheng.net),程序执行再次暂停。
close()
当程序在生成器函数中遇到 yield 语句暂停运行时,此时如果调用 close() 方法,会阻止生成器函数继续执行,该函数会在程序停止运行的位置抛出 GeneratorExit 异常
def foo():<br> try:<br> yield 1<br> except GeneratorExit:<br> print('捕获到 GeneratorExit')<br>f = foo()<br>print(next(f))<br>f.close()
虽然通过捕获 GeneratorExit 异常,可以继续执行生成器函数中剩余的代码,带这部分代码中不能再包含 yield 语句,否则程序会抛出 RuntimeError 异常
def foo():<br> try:<br> yield 1<br> except GeneratorExit:<br> print('捕获到 GeneratorExit')<br> yield 2 #抛出 RuntimeError 异常<br>f = foo()<br>print(next(f))<br>f.close()
生成器函数一旦使用 close() 函数停止运行,后续将无法再调用 next() 函数或者 __next__() 方法启动执行,否则会抛出 StopIteration 异常
def foo():<br> yield "c.biancheng.net"<br> print("生成器停止执行")<br>f = foo()<br>print(next(f)) #输出 "c.biancheng.net"<br>f.close()<br>next(f) #原本应输出"生成器停止执行"
throw()
在生成器函数执行暂停处,抛出一个指定的异常,之后程序会继续执行生成器函数中后续的代码,直到遇到下一个 yield 语句。需要注意的是,如果到剩余代码执行完毕没有遇到下一个 yield 语句,则程序会抛出 StopIteration 异常。<br>
def foo():<br> try:<br> yield 1<br> except ValueError:<br> print('捕获到 ValueError')<br>f = foo()<br>print(next(f))<br>f.throw(ValueError)
yield
通常的for...in...循环中,in后面是一个数组,这个数组就是一个可迭代对象,类似的还有链表,字符串,文件。它可以是mylist = [1, 2, 3],也可以是mylist = [x*x for x in range(3)]。<br>它的缺陷是所有数据都在内存中,如果有海量数据的话将会非常耗内存。<br>生成器是可以迭代的,但只可以读取它一次。因为用的时候才生成。比如 mygenerator = (x*x for x in range(3)),注意这里用到了(),它就不是数组,而上面的例子是[]。<br>我理解的生成器(generator)能够迭代的关键是它有一个next()方法,工作原理就是通过重复调用next()方法,直到捕获一个异常。可以用上面的mygenerator测试。<br>带有 yield 的函数不再是一个普通函数,而是一个生成器generator,可用于迭代,工作原理同上。<br>yield 是一个类似 return 的关键字,迭代一次遇到yield时就返回yield后面(右边)的值。重点是:下一次迭代时,从上一次迭代遇到的yield后面的代码(下一行)开始执行。<br>简要理解:yield就是 return 返回一个值,并且记住这个返回的位置,下次迭代就从这个位置后(下一行)开始。<br>带有yield的函数不仅仅只用于for循环中,而且可用于某个函数的参数,只要这个函数的参数允许迭代参数。比如array.extend函数,它的原型是array.extend(iterable)。<br>send(msg)与next()的区别在于send可以传递参数给yield表达式,这时传递的参数会作为yield表达式的值,而yield的参数是返回给调用者的值。——换句话说,就是send可以强行修改上一个yield表达式值。比如函数中有一个yield赋值,a = yield 5,第一次迭代到这里会返回5,a还没有赋值。第二次迭代时,使用.send(10),那么,就是强行修改yield 5表达式的值为10,本来是5的,那么a=10<br>send(msg)与next()都有返回值,它们的返回值是当前迭代遇到yield时,yield后面表达式的值,其实就是当前迭代中yield后面的参数。<br>第一次调用时必须先next()或send(None),否则会报错,send后之所以为None是因为这时候没有上一个yield(根据第8条)。可以认为,next()等同于send(None)。<br>
@函数装饰器
函数装饰器,就是通过装饰器函数,在不修改原函数的前提下,来对函数的功能进行合理的扩充。
用 funA() 函数装饰器去装饰 funB() 函数
#funA 作为装饰器函数<br>def funA(fn):<br> #...<br> fn() # 执行传入的fn参数<br> #...<br> return '...'<br>@funA<br>def funB():<br> #...
使用函数装饰器 A() 去装饰另一个函数 B(),其底层执行了如下 2 步操作:<br>将 B 作为参数传给 A() 函数;<br>将 A() 函数执行完成的返回值反馈回 B
<span style="font-family: "Helvetica Neue", 微软雅黑, "Microsoft Yahei", Helvetica, Arial, sans-serif; font-size: 14px;">Python 也支持多个装饰器</span>
@funA<br>@funB<br>@funC<br>def fun():<br> #...<br>上面程序的执行顺序是里到外,所以它等效于下面这行代码:<br>fun = funA( funB ( funC (fun) ) )
异常处理机制
异常情况类型
语法错误
语法错误,也就是解析代码时出现的错误。当代码不符合 Python 语法规则时,Python解释器在解析时就会报出 SyntaxError 语法错误,与此同时还会明确指出最早探测到错误的语句。
异常(Exceptions)<br>运行时错误<br>
序在语法上都是正确的,但在运行时发生了错误
AssertionError 当 assert 关键字后的条件为假时,程序运行会停止并抛出 AssertionError 异常 <br><br>AttributeError 当试图访问的对象属性不存在时抛出的异常 <br><br>IndexError 索引超出序列范围会引发此异常 <br><br>KeyError 字典中查找一个不存在的关键字时引发此异常 <br><br>NameError 尝试访问一个未声明的变量时,引发此异常 <br><br>TypeError 不同类型数据之间的无效操作 <br><br>ZeroDivisionError 除法运算中除数为 0 引发此异常
常见异常情况
try:<br> 可能产生异常的代码块<br>except [ (Error1, Error2, ... ) [as e] ]:<br> 处理异常的代码块1<br>except [ (Error3, Error4, ... ) [as e] ]:<br> 处理异常的代码块2<br>except [Exception]:<br> 处理其它异常<br>
该格式中,[] 括起来的部分可以使用,也可以省略。其中各部分的含义如下:<br>(Error1, Error2,...) 、(Error3, Error4,...):其中,Error1、Error2、Error3 和 Error4 都是具体的异常类型。显然,一个 except 块可以同时处理多种异常。<br>[as e]:作为可选参数,表示给异常类型起一个别名 e,这样做的好处是方便在 except 块中调用异常类型(后续会用到)。<br>[Exception]:作为可选参数,可以代指程序可能发生的所有异常情况,其通常用在最后一个 except 块。
try except 语句的执行流程
首先执行 try 中的代码块,如果执行过程中出现异常,系统会自动生成一个异常类型,并将该异常提交给 Python 解释器,此过程称为捕获异常。<br>当 Python 解释器收到异常对象时,会寻找能处理该异常对象的 except 块,如果找到合适的 except 块,则把该异常对象交给该 except 块处理,这个过程被称为处理异常。如果 Python 解释器找不到处理异常的 except 块,则程序运行终止,Python 解释器也将退出。
每种异常类型都提供了如下几个属性和方法,通过调用它们,就可以获取当前处理异常类型的相关信息:<br>args:返回异常的错误编号和描述字符串;<br>str(e):返回异常信息,但不包括异常信息的类型;<br>repr(e):返回较全的异常信息,包括异常信息的类型
try:<br> 1/0<br>except Exception as e:<br> # 访问异常的错误编号和详细信息<br> print(e.args)<br> print(str(e))<br> print(repr(e))
else
异常处理机制还提供了一个 else 块,也就是原有 try except 语句的基础上再添加一个 else 块,即try except else结构。<br><br>使用 else 包裹的代码,只有当 try 块没有捕获到任何异常时,才会得到执行;反之,如果 try 块捕获到异常,即便调用对应的 except 处理完异常,else 块中的代码也不会得到执行
finally
异常处理机制还提供了一个 finally 语句,通常用来为 try 块中的程序做扫尾清理工作。<br>注意,和 else 语句不同,finally 只要求和 try 搭配使用,而至于该结构中是否包含 except 以及 else,对于 finally 不是必须的(else 必须和 try except 搭配使用)。<br><br>在整个异常处理机制中,finally 语句的功能是:无论 try 块是否发生异常,最终都要进入 finally 语句,并执行其中的代码块。<br>当 try 块中的程序打开了一些物理资源(文件、数据库连接等)时,由于这些资源必须手动回收,而回收工作通常就放在 finally 块中。<br>Python 垃圾回收机制,只能帮我们回收变量、类对象占用的内存,而无法自动完成类似关闭文件、数据库连接等这些的工作。<br>
try:<br> a = int(input("请输入 a 的值:"))<br> print(20/a)<br>except:<br> print("发生异常!")<br>else:<br> print("执行 else 块中的代码") <br>finally :<br> print("执行 finally 块中的代码")
当 try 块中代码发生异常,导致程序崩溃时,在崩溃前 Python 解释器也会执行 finally 块中的代码
如果在 finally 块里也使用了 return 或 raise 等导致方法中止的语句,finally 块己经中止了方法,系统将不会跳回去执行 try 块、except 块里的任何代码<br>尽量避免在 finally 块里使用 return 或 raise 等导致方法中止的语句,否则可能出现一些很奇怪的情况<br>
try except<br>异常处理 示例<br>
try:<br> if(用户输入不合理):<br> raise 异常<br>except Exception:<br> alert 输入不合法<br> goto retry<br>#正常的业务代码
通过在 try 块中判断用户的输入数据是否合理,如果不合理,程序受 raise 的影响会进行到 except 代码块,对用户的错误输出进行处理,然后会继续执行正常的业务代码;反之,如果用户输入合理,那么程序将直接执行正常的业务代码。<br>try except 是 Python 实现异常处理机制的核心结构
try:<br> a = int(input("输入被除数:"))<br> b = int(input("输入除数:"))<br> c = a / b<br> print("您输入的两个数相除的结果是:", c )<br>except (ValueError, ArithmeticError):<br> print("程序发生了数字格式异常、算术异常之一")<br>except :<br> print("未知异常")<br>print("程序继续运行")
try:<br> #...<br>except Exception:<br> #...
对于 try 块中可能出现的任何异常,Python 解释器都会交给仅有的这个 except 块处理<br>因为它的参数是 Exception,表示可以接收任何类型的异常<br>
try:<br> a = int(input("输入 a:"))<br> b = int(input("输入 b:"))<br> print( a/b )<br>except ValueError:<br> print("数值错误:程序只能接收整数参数")<br>except ArithmeticError:<br> print("算术错误")<br>except Exception:<br> print("未知异常")
根据用户输入 a 和 b 值的不同,可能会导致 ValueError、ArithmeticError 异常:<br>如果用户输入的 a 或者 b 是其他字符,而不是数字,会发生 ValueError 异常,try 块会捕获到该类型异常,同时 Python 解释器会调用第一个 except 块处理异常;<br>如果用户输入的 a 和 b 是数字,但 b 的值为 0,由于在进行除法运算时除数不能为 0,因此会发生 ArithmeticError 异常,try 块会捕获该异常,同时 Python 解释器会调用第二个 except 块处理异常;<br>当然,程序运行过程中,还可能由于其他因素出现异常,try 块都可以捕获,同时 Python 会调用最后一个 except 块来处理。
raise<br>手动引发的异常<br>
raise [exceptionName [(reason)]]<br><br>其中,用 [] 括起来的为可选参数,其作用是指定抛出的异常名称,以及异常信息的相关描述。<br>如果可选参数全部省略,则 raise 会把当前错误原样抛出;<br>如果仅省略 (reason),则在抛出异常时,将不附带任何的异常描述信息。<br>
raise 语句有如下三种常用的用法:<br>raise:单独一个 raise。该语句引发当前上下文中捕获的异常(比如在 except 块中),或默认引发 RuntimeError 异常。<br>raise 异常类名称:raise 后带一个异常类名称,表示引发执行类型的异常。<br>raise 异常类名称(描述信息):在引发指定类型的异常的同时,附带异常的描述信息。
try:<br> a = input("输入一个数:")<br> #判断用户输入的是否为数字<br> if(not a.isdigit()):<br> raise ValueError("a 必须是数字")<br>except ValueError as e:<br> print("引发异常:",repr(e))
sys.exc_info()方法<br>获取异常信息<br>
捕获异常时,有 2 种方式可获得更多的异常信息,分别是:<br>使用 sys 模块中的 exc_info 方法;<br>使用 traceback 模块中的相关函数。
exc_info() 方法会将当前的异常信息以元组的形式返回<br>该元组中包含 3 个元素,分别为 type、value 和 traceback,它们的含义分别是:<br>type:异常类型的名称,它是 BaseException 的子类<br>value:捕获到的异常实例。<br>traceback:是一个 traceback 对象。<br>
自定义异常类型
class SelfExceptionError(Exception):<br> pass<br>try:<br> raise SelfExceptionError()<br>except SelfExceptionError as err:<br> print("捕捉到自定义异常")
<span style="font-family: "Helvetica Neue", 微软雅黑, "Microsoft Yahei", Helvetica, Arial, sans-serif; font-size: 14px;"> logging</span>
直接将下面的代码复制到程序开头:<br>import logging<br>logging.basicConfig(level=logging.DEBUG, format=' %(asctime)s - %(levelname)s - %(message)s')<br>
logging日志级别
logging.disable()
在调试完程序后,可能并不希望所有这些日志消息出现在屏幕上,这时就可以使用 logging.disable() 函数禁用这些日志消息,从而不必进入到程序中,手工删除所有的日志调用
logging.disable() 函数的用法是,向其传入一个日志级别,它会禁止该级别以及更低级别的所有日志消息。因此,如果想要禁用所有日志,只要在程序中添加 logging.disable(logging.CRITICAL) 即可
>>> import logging<br>>>> logging.basicConfig(level=logging.INFO, format=' %(asctime)s - %(levelname)s - %(message)s')<br>>>> logging.critical('Critical error! Critical error!')<br>2019-09-11 14:42:14,833 - CRITICAL - Critical error! Critical error!<br>>>> logging.disable(logging.CRITICAL)<br>>>> logging.critical('Critical error! Critical error!')<br>>>> logging.error('Error! Error!')
IDLE 调试程序
<span style="font-family: "Helvetica Neue", 微软雅黑, "Microsoft Yahei", Helvetica, Arial, sans-serif; font-size: 14px;"> assert<br></span>断言
assert 可以和 try except 异常处理语句配合使用:<br>纯文本复制<br>try:<br> s_age = input("请输入您的年龄:")<br> age = int(s_age)<br> assert 20 < age < 80 , "年龄不在 20-80 之间"<br> print("您输入的年龄在20和80之间")<br>except AssertionError as e:<br> print("输入年龄不正确",e)
当在命令行模式运行 Python 程序时,传入 -O(注意是大写)参数,可以禁用程序中包含的 assert 语句。
0 条评论
下一页