zoukankan      html  css  js  c++  java
  • python学习笔记

    Python学习笔记

    1.注释

    单行注释:#

    多行注释:

    注意:如果里面为三个单引号,外面需要是双引号,反之亦然。可以使用注释进行范围排错,注释逐渐缩减排查的方式。

    2.变量

    变量的定义方式:

    (1)直接赋值,a=1,b=1

    (2)多个变量对应赋值,a,b=1,2

    (3)变量对等赋值,a=b=1

    变量的命名规则:

    (1)必须是字母数字下划线的组合方式

    (2)不能以数字开始

    (3)变量名不能使用关键字定义

    (4)变量使用中文,语法上允许,但最好不用,占用空间大小。

    (5)变量名全为大写,约定俗称为常量。

    3.数值类型

    int 整形,包括正整数,负整数和零。注:type可以用来获取变量类型,id可以获取变量所指向的这个值的地址。0b表示二进制0b10,0b11等,0o表示八进制,0x表示十六进制。

    float 浮点型,表会小数。注:科学计数法用e表示,表示10的多少次方。

    bool 布尔类型,True为真1,False为假0。

    complex 复数,由实部和虚部组成,实部为0叫做纯虚数。

    4.容器类型

    4.1 str 字符串类型

    几种特殊字符:

    (1) 转义字符

    :换行

    :换行

    :缩进(水平制表符),相当于4个空格的距离

    :将后面字符串拉到当前行行首

    (2)单引号

    表示将定义的字符串当成一个整体,里面的内容不会解析

    (3)双引号

    表示将定义的字符串当成一个整体,具有特殊意义的字符会解析,如(1)中的字符

    (4)三引号

    表示可以跨行定义字符串变量。

    变量名=

    变量字符串

    (5)r

    在定义的字符串前面加上r,表示可以将具有特殊意义的字符不解析,原型化输出。

    (6)字符串格式化输出

    %d 整型占位符 %f 浮点型占位符 %s 字符串占位符 语法: 字符串 % (值1,值2,值3,.... )

     例:strvar="aaa%-5dccc%sbbbb%frrrrr" % (11,"科研",0.23)print(strvar)
     aaa11   ccc科研bbbb0.230000rrrrr

    字符串特点:可获取,不可修改,有序

    通过索引脚标获取,一个字符为一个元素,但不可以修改

    4.2 list 列表

    通过[ ]包含元素值,空列表示为listvar=[],通过索引来获取列表中的值,索引有正向索引和逆向索引,分别表示为:listvar[0],listvar[1],listvar[2]...或...listvar[-3],listvar[-2],listvar[-1]。注:可以通过len来获取容器类型数据的元素个数。

    特点:可获取,可修改,有序

    4.3 tuple 元组

    通过()包含元素,空元组表示为tuplevar=(),通过索引来获取元组中的值,有正向索引和逆向索引,分别表示为:tuplevar[0],tuplevar[1],tuplevar[2]...或...tuplevar[-2],tuplevar[-1]。区别是否为元组的标志为是否有逗号。

    特点:可获取,不可修改,有序

    4.4 set 集合

    通过{}包含元素,空集合表示为setvar=set{},集合可以自动去重。

    特点:不可获取,不可修改,无序

    4.5 dict 字典

    通过{}包含元素,空字典表示为dictvar={},元素由键和值组成。定义案例:

    dictvar = {top:孙悟空,middle:扁鹊,bottom:鲁班七号,jungle:韩信,support:蔡文姬}

    获取方式,通过键来获取对应的值,dictvar[top]...

    特点:可获取,可修改,无序

    4.6 补充

    字典的键和集合中的值 底层使用了哈希算法,所以是无序;哈希算法要求该值必须可哈希(即不可变)。所以字典的键和集合的值,要求可哈希。

    不可变类型值: Number(int,bool,float,complex),str,tuple

    可变类型值:set(集合),list(列表),dict(字典)

    注:字典的键定义,理论上可以任意使用,但推荐使用变量命名规则的字符串。

    5.自动类型转换

    转换的原则:低精度默认向高精度转换

    bool<int<float<complex

    注:用于计算中,自动转换为高精度数值,再进行计算

    6.Number强制类型转换

     var1 = 10
     var2 = 6.88
     var3 = True
     var4 = 6-2j
     var5 = "55"
     var6= "abc"

    强制转换成 int 整型

     res = int(var2)
     res = int(var3)  # 1 => True
     res = int(False) # 0 => False
     res = int(var4) error
     res = int(var5)
     res = int(var6)  error
     print(res)

    强制转换成 float 浮点型 小数

     res = float(var1) # 10.0
     res = float(var3) # 1.0
     res = float(var4) error # can't convert complex to float
     res = float(var5) # 55.0
     print(res)

    强制转换成 complex 复数

     res = complex(var1) # (10+0j)
     res = complex(var2) # (6.88+0j)
     res = complex(var3) # (1+0j)
     res = complex(var5) # (55+0j)
     res = complex(False) # 0j
     print(res)

    总结:int类型,不能强转字符串,不能强转复数。float类型,不能强转复数,不能强转字符。complex类型,不能强转字符

    bool类型强转,不为空则为真。为假的10种情况:0 0.0 False 0j ‘’ () [] {} set{} None

    7.容器类型强转

    7.1 str 强转为字符串类型

    强制转换成字符串,就是单纯的在原数据类型的两边套上引号;

    注:利用repr,可以将字符串原型化输出,不转义字符。引号可以显示出来

    7.2 list 强转为列表类型

    如果是字符串,把里面的字符,变成一个个的新元素组成新列表 如果是其他容器,就是单纯的在原数据类型的两边套上中括号 如果是字典,只获取字典的键,舍弃掉值,形成列表

    7.3 tuple 强制转换为元组类型

    如果是字符串,把里面的字符,变成一个个的新元素组成新元组 如果是其他容器,就是单纯的在原数据类型的两边套上圆括号 如果是字典,只获取字典的键,舍弃掉值,形成元组

    7.4 set 强制转换为集合类型

    如果是字符串,把里面的字符,变成一个个的新元素组成新集合 如果是其他容器,就是单纯的在原数据类型的两边套上花括号 如果是字典,只获取字典的键,舍弃掉值,形成集合

    7.5 dict 强制转换为字典类型

    多级容器:外面为容器类型数据,里面含有多层容器类型数据。两层则称为二级容器,三层则称为三层容器,......

    等长的二级容器:(1) 里面的每个元素都是容器类型数据(2) 容器类型里面的元素个数都相同

    强转成字典要求:等长的二级容器,并且里面的元素个数只有两个

    总结:其他容器强转为字典后,两个元素的前面一个用做键,后面一个用做值。集合作为里层容器的情况下,不能强转为字典,因为集合是无序的,强转后,对应的键和值会发生变化。集合可以用做外层容器。

    8.运算符

    8.1 算术运算符

     +   -   *   /   //   **   %

    // 表示地板除,用来得到一个整数

    ** 表示幂运算

    % 表示取余运算

    注:复数取余运算,若被除数为负数,除数为正数,余数=-余数+除数。若被除数为正数,除数为负数,余数=余数+(-除数)。若被除数和除数都为负数,余数=-余数。取余是依照于Python的向下取整而计算出的结果。利用计算出来的商,向下取整,在乘于除数,最后用被除数减去他们的乘积而得到python的余数。注意负数取余商都为负数。

    附:详解如下

    除法的取整分为三类:向上取整、向下取整、向零取整。

    1.向上取整:向+∞方向取最接近精确值的整数。在这种取整方式下,5 / 3 = 2, -5 / -3 = 2, -5 / 3 = -1, 5 / -3 = -1 2.向下取整:向-∞方向取最接近精确值的整数。在这种取整方式下,5 / 3 = 1, -5 / -3 = 1, -5 / 3 = -2, 5 / -3 = -2 3.向零取整:向0方向取最接近精确值的整数,换言之就是舍去小数部分,因此又称截断取整。在这种取整方式下,5 / 3 = 1, -5 / -3 = 1, -5 / 3 = -1, 5 / -3 = -1

    通过观察可以发现,无论是向上取整还是向下取整,(-a)/b-(a/b)都不一定成立。这给程序设计者带来了极大的麻烦。而对于向零取整,(-a)/b-(a/b)是成立的,以此,C/C++(包括Java)采用这种取整方式。

    而Python采用的是向下取整的方式

     C/C++PYTHON精确值
    -14/3 -4 -5 -4.67
    -14%3 -2 1 /
    14/-3 -4 -5 -4.67
    14%-3 2 -1 /
    -14/-3 4 4 4.67
    -14%-3 -2 -2 /

    总结规律如下:

    1. 两种语言中,商和余数都符合 被除数=商x除数+余数 这一数学规律。

    2. 两种语言中,整除的方法不同:C/C++ 是向零取整(负数向上、正数向下取整),Python 是下取整

    以 n/3 和 n%3 为例,看看这两种处理方法的区别。

    C 的情况,两种运算结果都关于0对称和反号

    N-5-4-3-2-10+1+2+3+4+5
    -1 -1 -1 0 0 0 0 0 1 1 1
    余数 -2 -1 0 -2 -1 0 1 2 0 1 2

    Python 的情况,运算结果是完全连续的:

    N-5-4-3-2-10+1+2+3+4+5
    -2 -2 -1 -1 -1 0 0 0 1 1 1
    余数 1 2 0 1 2 0 1 2 0 1 2

    那么,为何Python整除运算采用向下取整的规则,详细内容在Why Pythons Integer Division Floors?,简单地来讲就是:

    因为python认为余数r用到的机会会更大,采用向下取整的规则可以保证余数r与除数b的符号相同(同正或者同负)。以下为重点内容的摘抄:


    假设a和b都>=0时,

    b * q + r = a, 0 <= r < b

    如果希望将这一关系扩展到a为负(b仍为正)的情况,有两个选择:一是q向0取整,r取负值,这时约束关系变为 0 <= abs(r) < b,另一种选择是q向下(负无穷方向)取整,约束关系不变,依然是 0 <= r < b。

    在数学的数论中,数学家总是倾向于第二种选择(参见如下Wikipedia链接)。

    在Python语言中也做了同样选择,因为在某些取模操作应用中被除数a取什么符号并不重要。

    例如从POSIX时间戳(从1970年初开始的秒数)得到其对应当天的时间。因为一天有24*3600 = 86400秒,这一操作就是简单的t % 86400。但是当表达1970年之前的时间,这时是一个负数,向0取整规则得到的是一个毫无意义的结果!而向下取整规则得到的结果仍然是正确的。 另外一个我能想到的应用是计算机图形学中计算像素的位置。我相信这样的应用还有更多。

    顺便说一下,b取负值时,仅需要把符号取反,约束关系变为: 0 >= r > b 那么,现在的问题变成,C为啥不采取(Python)这样的选择呢?可能是设计C时硬件不适合这样做,所谓硬件不适合这样做是说指那些最老式的硬件把负数表示为“符号+大小”而不是像现在的硬件用二进制补码表示(至少对整数是用二进制补码)。我的第一台计算机是一台Control Data大型机,它用1的补码来表示整数和浮点数。60个1的序列表示负0! Tim Peters对Python的浮点数部分洞若观火,对于我想把这一规则推广到浮点数取模运算有些担心。可能他是对的,因为向负无穷取整的规则有可能导致当x是绝对值特别小的负数时x%1.0会丢失精度。但是这还不足以让我对整数取模,也就是//进行修改。 附言:注意我用了//而不是/,这是一个Python 3 语法,而且在Python 2 中也是有效的,它强调了使用者是要进行整除操作。Python 2 中的 / 有可能产生歧义,因为对两个操作数都是整数时或者一个整数一个浮点数或者两个都是浮点数时,返回的结果类型不同。

    8.2 比较运算符

     >    >=    <   <=   ==   !=

    比较之后只会产生两种结果:要么是True 要么是False

    8.3 赋值运算符

     +=    -=    *=    /=    //=    **=    %=
    var1 += var2 # => var1 = var1 + var2
    var1 %= var2 # => var1 = var1 % var2
    

    8.4 成员运算符

    in 表示元素是否在容器内,在为真

    not in 表示元素是否在容器内,不在为真

    注:此运算符主要针对于容器类型数据,在字典情况容器时,用键作为判断

    8.5 身份运算符

    is 表示数据地址相同为真

    is not 表示数据地址为假为真

    (1)对于整数而言,范围在-5~正无穷,如果值相同,则id值相同

    (2)对于浮点型而言,要求为非负数

    (3)布尔类型,值相同,则地址相同

    (4)complex复数 在实数+虚数这个范围内 永远不相同 (如果只有虚数,例外)

    (5)容器类新数据,除了相同的字符串和空元组, 剩下的都不相同

    8.6 逻辑运算符

    and 逻辑与,两边都为真则真,否则为假

    or 逻辑与,两边存在一方为真,则为真。两边都为假则假

    not 逻辑非,假为真,真为假

    逻辑短路:当进行and运算时,若开始为假,则一定为假,后面的则不需要判断了。当进行or运算时,若开始为真,则一定为真,后面的则不需要判断了。这样的情况假逻辑短路。

    注:逻辑运算优先级,从高到低为:() > not > and > or

    9.流程控制

    注:代码块:以冒号作为开始,用缩进来划分作用域;要用缩进就全部都是缩进 , 要么就全部都是4个空格。

    流程:代码执行的过程 流程控制: 对代码执行过程的管控

    流程控制三大结构: 顺序结构: 默认代码从上到下依次执行 分支结构: 4种 循环结构: while for .. in ..

    9.1 分支结构:

    (1)单项分支

    if 条件表达式:
    	code1
    	code2
    	code3 
    	....
    如果条件表达式成立,就执行对应的代码块里面的内容,反之不执行;
    条件表达式为True 就执行,反之为False,就不执行;
    

    (2)双项分支

    if 条件表达式:
    	code1
    	code2
    	...
    else:
    	code3
    	code4
    	...
    如果条件表达式 为真,执行if这个区间的代码块
    如果条件表达式 为假,执行else这个区间的代码块
    if这个区间的代码块也叫作真区间
    else 这个区间的代码块也叫作假区间
    

    (3)多项分支

    if 条件表达式1:
    	code1
    	code2
    elif 条件表达式2:
    	code1
    	code2
    elif 条件表达式3:
    	code1
    	code2
    else:
    	code1
    	code2
    如果 条件表达式1成立执行执行对应的代码块,后面的选项就不要了
    如果 条件表达式1不成立,看一看条件表达式2 是否成立 , 成立就执行,不成立在往下看 ,看条件表达式3
    如果 条件表达式3成立,执行对应代码块,如果不成立,直接走else分支.
    多选一,只要执行了一个分支,剩下分支通通不执行;
    elif 可以有0个,或多个
    else 可以有0个,或1个
    

    (4)巢状分支

    if 条件表达式1:
        if 条件表达式2:
            if 条件表达式3:
                ...
            else:
                代码块
        else:
            代码块
    else:
        代码块
    单项分支,双项分支,多项分支的嵌套
    数前面的缩进,如果缩进相同,代表是一对,是同一个作用域
    

    9.2 循环结构

    while 循环

    while 条件表达式:
    	code1
    	code2
    

    如果条件表达式 为真,就执行对应的代码块(循环体)否则就不循环;

    for 循环

    for 变量 in 可迭代对象:
        code1
        code2
    注:可迭代对象包括容器,rangs对象,迭代器
    

    10.字符串相关操作

    +    字符串的拼接
    *    字符串的重复
        字符串的跨行拼接
    正向索引、逆向索引
    字符串的切片:(截取)
    语法 => 字符串[::]  完整格式:[开始索引:结束索引:间隔值]
    	(1)[开始索引:]  从开始索引截取到字符串的最后
    	(2)[:结束索引]  从开头截取到结束索引之前(结束索引-1)
    	(3)[开始索引:结束索引]  从开始索引截取到结束索引之前(结束索引-1)
    	(4)[开始索引:结束索引:间隔值]  从开始索引截取到结束索引之前按照指定的间隔截取字符
    	(5)[:]或[::]  截取所有字符串
    

    11.单双循环练习

    # 1.单层循环
    #(1).打印一行十个小星星 **********
    i = 0
    while i<10:
    	# print(end="
    ") 默认print是在字符串后面加换行,如果不想换行 直接end='' 
    	print("*",end="")
    	i+=1
    
    print("<=======>")
    # (2).用变量拼接字符串的形式,打印一行十个小星星
    i = 0
    strvar = ''
    while i<10:
    	# 把代码写在如下地点:
    	# strvar = strvar + "*"
    	strvar += "*"
    	i+=1
    print(strvar)
    
    # (3)打印一行十个小星星 奇数个打印★ 偶数个打印☆
    i = 0
    while i<10:
    	if i % 2 == 0:
    		print("★",end="")
    	else:
    		print("☆",end="")
    	i+=1
    """
    任意数和n进行取余 ,余数范围是?
    0~ (n-1)
    """
    
    print("<====>")
    # (4)用 一个循环 打印十行十列小星星
    print("=========小星星=========")
    i = 0
    while i<100:
    	# 打印星星
    	print("*",end="")
    	
    	# 打印换行
    	if i % 10 == 9:
    		print()
    
    	i+=1
    
    print("=========双层循环=========")
    
    # 2.双层循环:
    # (1)打印十行十列小星星 (用两个循环)
    
    # 外层控制打印十行
    j = 0
    while j<10:
    
    	# 内层控制打印一行十个小星星
    	i = 0 	
    	while i<10:
    		# 代码写在下面:
    		print("*",end="")
    		i+=1
    		
    	# 打印换行
    	print()
    	j+=1
    
    
    
    # (2)打印十行十列隔列换色小星星
    '''外面循环控制行 , 里面循环控制列'''
    
    # 打印一行十个小星星
    j = 0
    while j<10:
    	if j %2 ==0:
    		print("★",end="")
    	else:
    		print("☆",end="")
    		
    	j+=1
    print("<====>")
    # 把一行十个星星循环10遍,就是隔列换色小星星
    i = 0 
    while i<10:
    	j = 0
    	while j<10:
    		if j % 2 ==0:
    			print("★",end="")
    		else:
    			print("☆",end="")
    			
    		j+=1
    	
    	# 打印换行
    	print()
    	i+=1
    
    
    # (3)打印十行十列隔行换色小星星
    """
    ★★★★★★★★★★
    ☆☆☆☆☆☆☆☆☆☆
    ★★★★★★★★★★
    ☆☆☆☆☆☆☆☆☆☆
    ★★★★★★★★★★
    ☆☆☆☆☆☆☆☆☆☆
    ★★★★★★★★★★
    ☆☆☆☆☆☆☆☆☆☆
    ★★★★★★★★★★
    ☆☆☆☆☆☆☆☆☆☆
    """
    i = 0 
    while i<10:
    	j = 0
    	while j<10:
    		if i % 2 ==0:
    			print("★",end="")
    		else:
    			print("☆",end="")
    			
    		j+=1
    	
    	# 打印换行
    	print()
    	i+=1
    
    # (4)99乘法表
    # 升序
    i = 1
    while i<=9:
    	j = 1
    	while j<=i:
    		print("%d*%d=%2d " % (i,j,i*j) ,end="")
    		# print(i,j)
    		j+=1
    	# 打印换行
    	print()
    	i+=1
    
    print("<=======>")
    # 降序
    i = 9
    while i>=1:
    	j = 1
    	while j<=i:
    		print("%d*%d=%2d " % (i,j,i*j) ,end="")
    		# print(i,j)
    		j+=1
    	# 打印换行
    	print()
    	i-=1
    

    12.字符串格式化

    #(1)顺序传参
    strvar="今天是一个晴朗的一天,{}和{}一块出去游玩".format("小明","小李")
    print(strvar)
    
    #(2)索引传参
    strvar="今天是一个晴朗的一天,{1}和{0}一块出去游玩".format("小明","小李")
    print(strvar
          
    #(3)关键字传参
    strvar="今天是一个晴朗的一天,{a}和{b}一块出去游玩".format(a="小明",b="小李")
    print(strvar)  #关键字不需要加双引号
          
    #(4)容器类型数据(列表或元组)传参
    strvar="今天是一个晴朗的一天,{group1[0]}和{group2[1]}一块出去游玩".format(group1=("小明","小李"),group2=("小红","小绿"))
    print(strvar)
          
    strvar="今天是一个晴朗的一天,{listvar[1]}和{listvar2[1]}一块出去游玩".format(listvar=["小明","小李"],listvar2=["小红","小兰"])
    print(strvar)
          
    #(5)字典传参
    strvar="今天是一个晴朗的一天,{group[a]}和{group[b]}一块出去游玩".format(group={"a":"小明","b":"小李"})
    print(strvar) #传参时不需要加引号,注意字典键和值之间用冒号
    

    12.1 format填充符号的使用

    ^               原字符串居中
    >     			原字符串居右
    <     			原字符串居左
    :d    			整型占位符
    :f    			浮点型占位符
    :s    			字符串占位符
    :,    			金钱占位符
    
    #填充符号使用
    strvar = "{who:*^10}在{where:_>10},{something:!<10}".format(who="小明",where="欢乐谷",something="做过山车")
    print(strvar)
    
    #占位符使用
    strvar = "小明今天去逛商城了,花了{:^3f}钱,还剩{:d}钱,剩下的钱准备去{:s}玩耍一下".format(32.5,22,"公园")
    print(strvar)
    #注:.format格式强制为相应类型,传入参数需要对应,否则会报错
    

    13.字符串函数

    语法:字符串.函数()

    capitalize 字符串首字母大写

    title 每个单词的首字母大写 (非字母隔开的单词)

    upper 将所有字母变成大写

    lower 将所有字母变成小写

    swapcase 大小写互换

    count 统计字符串中某个元素的数量

    find 查找某个字符串第一次出现的索引位置 (推荐),可以选择差找的范围 find(字符串,开始索引,结束索引) 结束索引最大值取不到

    index 与 find 功能相同 find找不到返回-1,index找不到数据直接报错

    startswith 判断是否以某个字符或字符串为开头 ,startswith(字符串,开始索引,结束索引)

    endswith 判断是否以某个字符或字符串结尾

    split 按某字符将字符串分割成列表(默认字符是空格)# 第二个参数可以选择分隔的次数lst = strvar.split(%,2)

    join 按某字符将列表拼接成字符串(容器类型都可)

    replace 替换字符串(可选择替换的次数),字符串.replace(原来的内容,将要替换的内容,替换次数)

    isdecimal 检测字符串是否以数字组成 必须是纯数字

    len 计算容器类型长度

    center 填充字符串,原字符居中 (默认填充空格)

    strip 默认去掉首尾两边的空白符 ,可以指定去掉的内容

    14.列表相关操作

    (1)列表的拼接:+ 将两个列表元素组成为一个列表

    (2)列表的重复:* 将一个列表重复n次,组成一个列表

    (3)列表的切片:

    语法 => 列表[::] 完整格式:[开始索引:结束索引:间隔值] 1) [开始索引:] 从开始索引截取到列表的最后 2) [:结束索引] 从开头截取到结束索引之前(结束索引-1) 3) [开始索引:结束索引] 从开始索引截取到结束索引之前(结束索引-1) 4) [开始索引:结束索引:间隔值] 从开始索引截取到结束索引之前按照指定的间隔截取列表元素值 5) [:]或[::] 截取所有列表

    6) 截取有正向截取和反向截取,依据于索引脚标

    (4)列表的获取:依照索引脚标获取,可以正向获取也可以反向获取。

    (5)列表的修改:可以依据于脚标进行单独修改,也可以切片修改。在切片修改时,如果没有步长限制,填入的修改元素将没有数量限制(一对一限制);如果加上步长,则需要一对一进行修改,提取了多少个,就只能填入多少个元素。

    (6)列表的删除:利用切片,切除几个,删除几个。可以加入步长

    注:元组的一级内容不能改,如果存在列表,二级的内容可以修改的

    15.列表相关函数

    append 从后面插入

    insert 从前面插入

    extend 迭代着追加,可迭代性数据iterable : 容器类型数据 ,range对象 ,迭代器

    pop 通过指定索引删除元素,若没有索引移除最后那个 (推荐)

    remove 通过给予的值来删除,如果多个相同元素,默认删除第一个

    clear 功能:清空列表

    index 获取索引 列表.index(值,start),可以指定差找的范围,如果找不到直接报错;

    count 功能:计算某个元素出现的次数

    sort 排序,加上参数,reverse=True,表示倒序排序

    reverse 列表反转操作,将列表反转排列

    16.深拷贝和浅拷贝

    通过import函数引入copy模块

    浅拷贝意味着只拷贝一级或多级容器的第一层,拷贝后两个容器之间,一层元素形成独立,而二级容器一下,则指向了一个地址,会相互影响。

    深拷贝意味着拷贝一级或多级容器的所有层,拷贝后两个容器之间,所有元素保持独立,不会相互影响。

    17.字典相关函数

    fromkeys() 使用一组键和默认值创建字典 (谨慎使用),此函数创建的字典,若往里面追加值,会导致所有键的值都被追加。不推荐使用,推荐一对一,一个键对应一个值去创建字典。

    pop() 通过键去删除键值对,如果没有键,会报错 (若没有该键可设置默认值,预防报错),返回状态为删除的那个值。

    popitem() 删除最后一个键值对

    clear() 清空字典

    update 直接在括号里面写上要更新的字典:存在的话就更新,不存在就添加

    get() 通过键获取值(若没有该键可设置默认值,预防报错)

    keys() 将字典的键组成新的可迭代对象

    values() 将字典中的值组成新的可迭代对象

    items() 将字典的键值对凑成一个个元组,组成新的可迭代对象

    18.集合相关操作

    intersection() 交集 表示两个集合的公共元素,可以用&符号代表交

    difference() 差集 表示前一个集合和后面一个集合的相差元素,可以用-符号表示

    union() 并集 表示两个集合元素的总和,去重,可以用|符号代表并

    symmetric_difference() 对称差集 (补集情况涵盖在其中) ,表示两个集合差异元素的组合。可以用^异或符号表示

    issubset() 判断是否是子集,表示前面一个集合是否是后面一个集合的子集,可以用<符号表示

    issuperset() 判断是否是父集,表示前面一个集合是否是后面一个集合的父集,可以用>符号表示

    isdisjoint() 检测两集合是否不相交 不相交 True 相交False

    add() 向集合中添加数据 (一次加一个)

    update() 迭代着增加 (一次加多个)

    clear() 清空集合

    pop() 随机删除集合中的一个数据

    remove() 删除集合中指定的值(不存在则报错)

    discard() 删除集合中指定的值(不存在的不删除 推荐使用)

    frozenset() 可强转容器类型数据变为冰冻集合,冰冻集合一旦创建,不能在进行任何修改,只能做交叉并补操作

    19.文件相关操作

    19.1 open()函数:

    格式:open(文件名,mode=采用的模式,encoding=采用的编码集)

    作用:返回一个对象,是文件的io对象(文件句柄),用于往文件中插入内容

    注:往文件中插入的内容只能是字符串或者字节流

    open()函数的编码集:一般为utf-8,默认为这个,表示万国码,通用

    open()函数模式:r w r+ w+ a a+ rb wb rb+ wb+

    r模式:表示对文件具有读取的能力,不能进行写操作,光标默认在行首
    
    r+模式:表示对文件具有读能力和写能力,光标默认在行首,进行写操作,需要将光标移到行尾
    
    w模式:表示对文件具有写能力,会自动创建文件,若果文件已经存在,并且有内容的话,会清空文件里面的内容。
    
    w+模式:表示文件具有写能力和读能力,此模式会自动创建文件,如果文件已经存在,并且有内容,则内容会被清空。读操作需要在写完之后再使用,否则没有内容显示。
    
    a模式:表示文件具有内容追加的能力,默认光标在行尾,可以直接追加内容进入。
    
    a+模式:表示只要是写入,就会强制光标在最后,读取时,可以随意移动光标;
    
    rb模式:表示字节流文件模式下,可读
    
    wb模式:表示字节流模式文件下,可以写入
    

    19.2 write()函数:

    格式:fp.write()

    作用:用于往文件中写入内容

    注:fp为open()函数返回的io对象名称,可以更改。注意光标的停留位置

    19.3 read()函数:

    格式:fp.read()

    作用:用于读取文件的内容,读取的是文件的字符个数。read()内的参数,如果不写,默认读取所有,写上数字是代表读取[字符的个数],从当前光标向后读取

    注:注意光标的停留位置。

    19.4 close()函数:

    格式:fp.close()

    作用:用来结束返回的io对象

    19.5 encode()函数:

    格式:变量或字符串.encode(utf-8)

    作用:用来将字符串改变为二进制字节流

    19.6 decode()函数:

    格式:变量或字节流.decode(“utf-8”)

    作用:用来将字节流转变为原来的数据类型,字符编码默认为utf-8

    注:在字节流模式下,不能使用字符编码,否则会报错。字节流模式,在字节流前面加上b或者字节流文件需要字节流模式。

    19.7 seek()函数:

    格式:fp.seek(移动的字节数)

    作用:调整指针的位置(里面的参数代表字节个数)

    seek(0) 把光标移动到开头 seek(0,2) 把光标移动到最后

    19.8 tell()函数:

    格式:fp.tell()

    作用:当前光标左侧所有的字节数(返回字节数)

    19.9 with语法:

    格式:with open(文件名,mode=模式,encoding=字符集) as fp:

    作用:自动完成close文件操作,由系统完成,不必再使用close()函数,可以定义多个返回io对象

    注:as的意思是起一个别名,fp为名称,同上。

    20.文件相关函数

    20.1 flush()函数:

    作用:强制刷新缓冲区,把内容写进去,用于当下面代码错误,或者进入死循环时,缓冲区内容无法写入,可以使用flush强制刷新写入。

    缓冲区刷新方式:

    # 当文件关闭的时候自动刷新缓冲区
    # 当整个程序运行结束的时候自动刷新缓冲区
    # 当缓冲区写满了  会自动刷新缓冲区
    # 手动刷新缓冲区
    

    20.2 readable()函数:

    作用: 判断文件对象是否可读

    20.3 writable()函数:

    作用: 判断文件对象是否可写

    20.4 readline()函数:

    作用: 读取一行文件内容

    读取所有内容实现方式:

    with open("test.txt",mode="r+",encoding="utf-8") as fp:
    	res = fp.readline()
    	while res:
    		# 先读取一行,如果不为空,就打印,并且在读取下一行,依次类推,如果为空,退出循环;
    		print(res)
    		res = fp.readline()
    

    20.5 readlines()函数:

    作用:将文件中的内容按照换行读取到列表当中

    读取所有内容并去掉换行符:

    with open("test.txt",mode="r+",encoding="utf-8") as fp:
    	lst = fp.readlines()
    	lst_new = []
    	for i in lst:
    		lst_new.append(i.strip())
    	print(lst_new)
    

    20.6 writelines()函数:

    作用:将内容是字符串的可迭代性数据写入文件中 参数:内容为字符串类型的可迭代数据。

    20.7 truncate()函数:

    格式:fp.truncate(字节数)

    作用: 把要截取的字符串提取出来,然后清空内容将提取的字符串重新写入文件中 (字节)

    21.循环控制

    pass:过,通过。用来占位的。当循环体中代码未知时,用于跳过这个循环体,防止报错,继续往下执行。

    break:中断,表示终止当前的循环体,与其他循环体无关。

    continue:继续,表会终止循环体内的本次循环,继续下一次循环。

    附:while循环和for循环的跳过操作

    # 打印1~10 抛去5
    i =1
    while i<=10:
    	if i == 5:
    		# 必须在跳过之前,手动加一
    		i+=1
    		continue
    	print(i)
    	i+=1
    
    print("<====>")
    # for 循环内部没执行依次都会加一,自动完成;
    for i in range(1,11):
    	if i == 5:
    		continue
    	print(i)
    

    22.函数

    22.1 函数的定义:

    包裹一部分代码 实现某一个功能 达成某一个目的

    22.2 函数的特点:

    可以反复调用,提高代码的复用性,提高开发效率,便于维护管理

    22.3 函数的基本格式:

    #函数的定义处
    def 函数名():
    	code1
    	code2
    	code3
    	...
    #函数的调用处
    函数名()
    

    22.4 函数的命名:

    与变量命名一致

    驼峰命名法: (1) 大驼峰命名法:每个单词首字母大写 mycar => MyCar socketserverhandler => SocketServerHandler (2) 小驼峰命名法:除了第一个单词,剩下单词首字符都大写 socketserverhandler => socketServerHandler 注:大驼峰命名法推荐在类名中使用,函数中一般用_来分隔不通的单词

    22.5 函数的参数:

    形参:定义在函数体中
    		普通形参:函数中定义的参数
    		默认形参:给定义的参数赋予了默认值
    		普通收集形参:*args,收集传入的多余普通实参,args为名字,可随便取
    		命名关键字形参:位于*号之后,表示之后的参数必须使用关键字来传参,位于普通收集参数和关键字收集参数之间
    		关键字收集形参:**kwargs收集传入的多余关键字实参形参字典,kwargs为名字,可随便取
    		
    实参:函数引用时,赋予的参数
    		普通实参:依据于顺序传入到函数
    		关键字实参:通过关键字对应赋值,传给对应形参,位置可以随意。在定义时,如果用的是普通形参,调用时,用的是关键字实参,那么意味着该参数后面所有参数都必须使用关键字实参
    		
    关于*的用法:
    	位于函数定义处形参:
    		*个星号代表普通收集参数
    		**个星号代表关键字收集参数
    	位于函数传入处实参:
    		*号可以跟在容器类型数据的前面,引用整个列表作为参数传入  如*list 或 *tuple (常用)
    		**号可以跟在字典类型数据的前面 如**dict表示将容器类型数据作为一个关键字与值对应传入
    		
    参数顺序:
    	普通形参 -> 默认形参 -> 普通收集形参 -> 命名关键字形参(关键字形参) -> 关键字收集形参
    注:def func(*args,**kwargs) 可以收到所有参数;普通形参 + 默认参数 : 默认形参必须放在普通形参后面;
    

    两组字典的两种调用方式的组合:

    def func(**kwargs):
    	dic = {"monitor":"花儿","classgrass":"小草"}
    	# print(kwargs) # {'monitor': '沐风', 'classgrass': '凌宇'}
    	strvar = ''
    	# 循环字典
    	for k,v in kwargs.items():
    		# 判断字典当中是否存在该键
    		# print(k,v) v => 沐风 凌宇
    		if k in dic:
    			# print(dic[k]) # 花儿 小草
    			strvar = dic[k] +  ":" + v
    			print(strvar)
    	 
    func(monitor="沐风",classgrass="凌宇")
    

    22.6 函数的return返回值:

    (1)return后面可以接Number、str、list、tuple、set、dict,除此之外还有函数和类对象。

    (2)return执行完之后,之后的代码将不再执行。

    (3)在没有定义返回值的情况,默认返回为None

    22.7 函数的使用:

    1.函数名是个特殊的变量,可以当做变量赋值

    2.函数名可以作为容器类型数据的元素

    3.函数名可以作为函数的参数

    4.函数名可作为函数的返回值

    5.doc 或者 help 查看文档

    当在函数中定义了注释函数信息时,可以通过doc或help来查看

    格式:变量=函数名. doc print(变量)

    help(函数名)

    22.8 全局变量与局部变量:

    1.局部变量:

    定义:在函数内部定义的变量

    作用域:函数内部,只能在函数内部进行获取和修改操作,若想要在全局生效则应该用global来定义。

    2.全局变量:

    定义:在函数外部,或者在函数内部,用global关键字定义的变量是全部变量。

    作用域:可以在整个文件中生效

    3.global:

    global 如果在全局空间有这个变量,那么在函数内部可以修改该变量 global 如果在全局空间没有这个变量,那么在函数内部可以定义该变量

    4.nonlocal:

    nonlocal 符合LEGB原则:

    (1) nonlocal是寻找当前作用域上一级的局部变量进行修改 (2) 如果上一级找不到,就继续向上寻找 (3) 实在没有了,直接报错

    5.LEGB原则:

    #找寻变量的调用顺序采用LEGB原则(即就近原则) B —— Builtin(Python);Python内置模块的命名空间 (内建作用域) G —— Global(module); 函数外部所在的命名空间 (全局作用域) E —— Enclosing function locals;外部嵌套函数的作用域(嵌套作用域) L —— Local(function);当前函数内的作用域 (局部作用域) 依据就近原则,从下往上 从里向外 依次寻找

    6.变量的加载顺序和生命周期:

    生命周期:

    局部变量 -> 全局变量 -> 内置变量

    加载顺序:

    内置空间的变量 -> 全局空间变量 ->局部空间变量

    22.9 函数的嵌套:

    互相嵌套的两个函数,在内层叫做内函数,在外层叫做外函数。

    内部函数仅可以在内部被调用

    函数的嵌套,变量调用遵循LEGB原则

    def outer():
    	def inner():
    		def smaller():
    			a = 5
    			print(a)
    			print("smaller")
    		smaller()
    	inner()
    outer()
    

    22.10闭包函数:

    定义:内函数使用了外函数的局部变量,外函数把内函数返回出来的过程,是闭包,这个内函数被称为闭包函数。

    特征:内函数使用了外函数的局部变量,外函数的局部变量和内函数发生绑定,延长该变量的生命周期,不释放,直到程序调用结束位置;该生命周期类似于全局变量。

    意义:用闭包对变量形成封装,起到保护变量的作用。

    #变量的封装
    def total_num():
    	count = 0
    	def inner():
    		nonlocal count
    		count += 1
    		print(count)
    	return inner
    func = total_num()
    func()
    count = 100 #此时的变量重先赋值不会影响到函数内的变量和代码运算
    func()
    
    #闭包函数进阶:
    def linruimian_family():
    	jiejie = "马蓉"
    	meimei = "马诺"
    	money = 1000
    	
    	def jiejie_hobby():
    		nonlocal money
    		money -= 700
    		print("买包包,买名表,买车,宝养小黑脸,宝强受苦了,家里钱还剩下%s" % (money))
    	
    	def meimei_hobby():
    		nonlocal money
    		money -= 200
    		print("宁愿在宝马里面哭,也不愿再自行车上撒欢.家里的钱还剩下%s" % (money))
    	
    	def big_master():
    		# 逗号才是区分是否是元组的标识,空元组()除外
    		return  (jiejie_hobby,meimei_hobby)
    	return big_master
    	
    func = linruimian_family()
    print(func)
    tup = func()
    print(tup)
    jiejie = tup[0]
    meimei = tup[1]
    # 调用妹妹
    meimei()
    # 调用姐姐
    jiejie()
    

    22.11 lambda匿名函数:

    用于将函数简单返回状态进行简写。

    (1)无参的匿名函数

    func=lambda : 返回值

    res=func()

    print(res)

    (2)有参的匿名函数

    func=lambda(参数) : 返回值

    res=func(参数)

    print(res)

    (3)带有判断条件的匿名函数

    三目运算符:res=真值 if 条件 else “假值”

    func=lambda(参数) : 返回值(res=真值 if 条件 else “假值”)

    res=func(参数)

    print(res)

    23.迭代器

    迭代器一般说明:能被next调用,并不断返回下一个值的对象。迭代器一定是一个可迭代对象,而一个可迭代对象不一定是迭代器。

    特征:迭代器会生成惰性序列,它通过计算把值依次的返回,一边循环一边计算而不是一次性得到所有数据

    优点:需要数据的时候,一次取一个,可以大大节省内存空间.而不是一次把所有数据放进内存.

    迭代对象:如果该数据结构含有iter这个方法,就是可迭代对象,一般包括,容器类型数据,range对象,迭代器,文件。可以通过dir()来查看数据结构成员。

    迭代器:

    (1)通过iter()或iter()可以将可迭代对象改变为迭代器

    (2)通过next()或next()方法可以遍历迭代器,next获取数据是单向不可逆的,所以获取完之后,想要再次获取,需要重设迭代器。

    (3)迭代器的二种判定方式:1)通过判断iternext方法是否在该数据结构类型中,print( iter in dir(it) and next in dir(it))。2)通过判断类型方法isinstance,引入迭代器数据类型(from collections import iterator,iterable)。res = isinstance(it,Iterator) ,res = isinstance(it,Iterable)

    遍历迭代器的三种方式:

    # 1.使用next多次调用
    res = next(it)
    print(res)
    res = next(it)
    print(res)
    res = next(it)
    print(res)
    res = next(it)
    print(res)
    # res = next(it)
    # print(res) # StopIteration
    
    print("<====>")
    # 重置迭代器
    it = setvar.__iter__()
    # 2.使用for
    for i in it:
    	print(i)
    	
    print("<====>")
    # 3.可以配合 next 和 for 一起使用
    # 重置迭代器
    it = setvar.__iter__()
    for i in range(2):
    	res = next(it)
    	print(res)
    

    24.高阶函数

    定义:能够把函数当成参数传递的就是高阶函数

    24.1 map函数:

    map(func,Iterable): 功能:把Iterable中的值,一个个拿出来,放到func中进行处理,把处理的结果存放在迭代器中,最终返回一个迭代器 参数: func: 自定义函数 或者 内置函数 Iterable: 可迭代对象( 容器类型数据 , range对象 , 迭代器 ) 返回值: 迭代器

    # ###综合例子 ['a','b','c'] => [97,98,99]
    """
    dic = {97:"a",98:"b",99:"c"}
    dic_new = {}
    for k,v in dic.items():
    	# print(k,v)
    	dic_new[v] = k
    print(dic_new) # {'a': 97, 'b': 98, 'c': 99}
    
    
    lst = ['a','b','c']
    lst2 = []
    for i in lst:
    	res = dic_new[i]
    	lst2.append(res)
    print(lst2)
    """
    
    # 使用map进行改造
    '''
    注意点:自定义函数一定要接受参数 1个,并且有返回值;
    '''
    def func(n):
    	dic = {97:"a",98:"b",99:"c"}
    	dic_new = {}
    	for k,v in dic.items():
    		dic_new[v] = k
    	return dic_new[n]
    
    # print(func("a"))
    # print(func("b"))
    # print(func("c"))
    lst = ['a','b','c']
    it = map(func,lst)
    print(list(it)) # [97, 98, 99]#list强转遍历所有值
    

    24.2 reduce函数:

    reduce(func,Iterable) 功能:把Iterable其中的两个值拿出来,扔到func当中做计算,得到的结果和Iterable的第三个元素,在放到func当中做计算。依次类推,直到调用结束; 参数: func : 自定义函数 或者 内置函数 Iterable : 可迭代对象( 容器类型数据 , range对象 , 迭代器 ) 返回值: 最后计算的结果

    reduce函数引入:from functools import reduce

    # "789" => 789 不能使用int强转;
    res = list("789")
    print(res)
    
    def func(x,y):
    	return x*10+y
    res = reduce(func,lst)
    print(res)
    
    def func2(n):
    	dic = {"0":0,"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9}
    	return dic[n]
    	
    it = map(func2,"789")	#将789依次取出作为迭代器
    # print(list(it))
    res = reduce(func,it)   #将迭代器数据依次迭代计算
    print(res,type(res))
    

    24.3 sorted函数:

    sorted(Iterable,reverse=False,key=函数) 功能: 排序 参数: Iterable(可迭代对象):容器类型数据,range对象,迭代器 reverse=False : 默认从小到大排序,改为True将从大到小排序 key=函数 : 自定义 或者 内置 ,按照什么方式进行排序 返回值: 排序后的结果

    #按照余数进行排序
    tup = (19,28,25,43)
    
    def func(n):
    	return n % 10
    	
    res = sorted(tup,key=func)
    print(res)
    

    注:字符类型数据按照ASCII编码排序

    sort 只能针对列表进行排序,而且是在原有列表上修改的 列表.sort() sorted 返回一个新列表,而不仅限于列表类型的数据;对原来数据没有任何变化

    24.4 filter函数:

    filter(func,Iterable) 功能: 过滤,通过指定筛选方式进行数据过滤,返回结果为True则保留,False则舍弃。 参数: func:自定义函数 return True 保留该数据 return False 舍弃该数据 Iterable:容器类型数据,range对象,迭代器 返回值: 迭代器

    lst=[1,34,345,34,654,7,567,576,867,876,9,8,879,789,789,879]
    		
    def func(n):
    	if n % 2 == 1:
    		print(n)
    		
    for i in lst:
    	func(i)
    	
    # filter写法
    def func(n):
    	if n % 2 == 1:
    		return True
    	else:
    		return False
    		
    it = filter(func,lst)
    print(list(it))
    
    # 改造成lambda匿名函数写法
    it = filter(lambda n : True if n % 2 == 1 else False ,  lst)
    print(list(it))
    

    25.推导式

    定义:通过一行循环判断,遍历出一系列数据的方式是推导式

    语法: val for val in Iterable (把想要的值写在 for的左侧)

    [val for val in Iterable]  列表推导式
    {val for val in Iterable}  集合推导式
    {a:b for a,b in iterable}  字典推导式
    

    for循环的后面只能是单项分支,其他的分支判断不可以

    25.1 列表推导式:

    #三种类型的列表推导式
    #  (1)一个循环的推导式
    lst = [i for i in range(1,101)]
    print(lst)
    
    # [1,2,3,4,5] => [2,4,5,6,10]
    lst = [i*2 for i in range(1,6)]
    print(lst)
    
    lst = ["a" for i in range(2)]
    print(lst)
    
    # (2)带有判断条件的单循环推导式
    lst = [1,2,3,4,54,65,6547,6,7]
    lst2 = []
    for i in lst:
    	if i % 2 == 0 :
    		lst2.append(i)
    print(lst2)
    
    # 推导式改写
    lst = [i for i in lst if i % 2 == 0]
    print(lst)
    
    
    # (3)二个循环的推导式 
    # # 谁❤谁
    lst1 = ["东","园","强"]
    lst2 = ["星","泽","浩"]
    
    # 普通写法
    lst = []
    for i in lst1:
    	for j in lst2:
    		res = i+"❤"+j
    		lst.append(res)
    print(lst)
    
    # 推导式改写
    lst = [i+"❤"+j for i in lst1 for j in lst2 ]
    print(lst)
    
    # (4)带有判断条件的双循环推导式
    lst1 = ["东","园","强"]
    lst2 = ["星","泽","浩"]
    lst = []
    for i in lst1:
    	for j in lst2:
    		#通过索引号,找到一对一的拼接数据
    		if lst1.index(i) ==  lst2.index(j):
    			res = i+"❤"+j 
    			lst.append(res)
    print(lst)
    
    # 推导式改写
    lst = [i+"❤"+j  for i in lst1 for j in lst2 if lst1.index(i) ==  lst2.index(j)]		
    print(lst)
    

    25.2 集合推导式:

    """
    案例:
    	满足年龄在18到21,存款大于等于5000 小于等于5500的人,
    	开卡格式为:尊贵VIP卡老x(姓氏),否则开卡格式为:抠脚大汉卡老x(姓氏)	
    	把开卡的种类统计出来
    """
    listvar = [
    	{"name":"王家辉","age":18,"money":10000},
    	{"name":"王水机","age":19,"money":5100},
    	{"name":"王鹏","age":20,"money":4800},
    	{"name":"李站","age":21,"money":2000},
    	{"name":"李小龙","age":180,"money":20}
    ]
    
    setvar = set()
    for i in listvar:
    	if 18 <= i["age"] <= 21 and 5000 <= i["money"] <= 5500:
    		res = "尊贵VIP卡老"+ i["name"][0]
    	else:
    		res = "抠脚大汉卡老" + i["name"][0]
    	# 集合可以自动去重
    	setvar.add(res)
    print(setvar)
    
    # 集合推导式 自动去重
    setvar = {"尊贵VIP卡老"+ i["name"][0]  if 18 <= i["age"] <= 21 and 5000 <= i["money"] <= 5500 else "抠脚大汉卡老" + i["name"][0] for i in listvar }
    print(setvar)
    #先进行循环遍历,在对遍历的结果通过指定条件筛选
    

    25.3 字典推导式:

    (1)enumerate

    格式:enumerate(iterable,[start=0]) 功能:枚举 ; 将索引号和iterable中的值,一个一个拿出来配对组成元组放入迭代器中 参数: iterable: 可迭代性数据 (常用:迭代器,容器类型数据,可迭代对象range) start: 可以选择开始的索引号(默认从0开始索引) 返回值:迭代器

    from collections import Iterator,Iterable
    lst = ["燕","星","建"]
    it = enumerate(lst)
    res = isinstance(it,Iterator)
    print(res)
    # print(list(it)) # [(0, '燕'), (1, '星'), (2, '建')]
    
    
    # 字典推导式
    it = enumerate(lst)
    dic = {k:v  for k,v in it}
    print(dic)
    
    # 使用dict强转成字典
    it = enumerate(lst)
    dic = dict(enumerate(lst))
    print(dic)
    
    #指定索引位置
    dic =dict(enumerate(lst,start=100))
    print(dic)
    

    (2)zip

    格式:zip(iterable, ... ...) ​ 功能: 将多个iterable中的值,一个一个拿出来配对组成元组放入迭代器中 ​ iterable: 可迭代性数据 (常用:迭代器,容器类型数据,可迭代对象range) 返回: 迭代器

    # (1) 基本语法
    lst1 = ["李","鹏","湘"]
    lst2 = ["瑞","丽","飞"]
    lst3 = ["秦","梦","倩"]
    lst4 = ["秦","梦"] # 不配对的元素 直接舍弃
    it = zip(lst1,lst2,lst4)
    print(isinstance(it,Iterator)) # True
    print(list(it))
    
    # (2) 通过字典推导式进行转化
    lst1 = ["李","鹏","湘"]
    lst2 = ["林","瑞","飞"]
    
    dic = {k:v for k,v in zip(lst1,lst2)}
    print(dic)
    
    # (3) dict 强转zip返回的迭代器变成字典 等长的二级容器
    dic = dict(zip(lst1,lst2))
    print(dic)
    

    26.生成器

    定义:元组推导式的返回值是一个生成器对象,简称生成器,生成器本质就是迭代器.

    迭代器与生成器的区别:迭代器本身是系统内置的,重写不了,而生成器是用户自定义的,可以重写迭代逻辑。

    生成器的创建:(1)生成器表达式 (里面是推导式,外面用圆括号) (2)生成器函数 (用def定义,里面含有yield)

    生成器的调用:与迭代器调用保持一致,三种方式

    生成器函数:yield

    yield 类似于 return

    共同点在于:执行到这句话都会把值返回出去 不同点在于:yield每次返回时,会记住上次离开时执行的位置 , 下次在调用生成器 , 会从上次执行的位置往下走,而return直接终止函数,每次重头调用. yield 6 和 yield(6) 2种写法都可以 yield 6 更像 return 6 的写法 推荐使用。

    生成器的调用需要初始化生成器函数。

    返回值如果超过函数可返回数量时,会报错,可以使用try:... expect: pass 将最后的返回错误忽略。

    def mygen():
    	print("start")
    	for i in range(100):
    		yield "我的球衣号码是%s" % (i)
    		
    # 初始化生成器函数 返回生成器对象 简称生成器
    gen = mygen()
    for i in range(50):
    	res = next(gen)
    	print(res)
    

    send的使用:

    作用:用来发送数据给上一个yield

    next和send区别:

    next 只能取值
    send 不但能取值,还能发送值
    

    send注意点:

    第一个 send 不能给 yield 传值 默认只能写None
    最后一个yield 接受不到send的发送值
    变量是用来接受函数的返回值
    send将内容发送给上一个yield位置
    
    def mygen():
        print("start")
        res1=yield 1
        print(res1,"limainres1")
        res2=yield 2
        print(res2,"limianres2")
        res3=yield 3
        print(res3,"limianres3")
        print("end")
    gen=mygen()
    res1=gen.send(None)
    print(res1,"waimianres1")
    
    print("diercifasong")
    res2=gen.send("aaa")
    print(res2,"waimianres2")
    
    print("disnacifasong")
    res3=gen.send("bbb")
    print(res3,"waimianres3")
    

    yield from:

    作用:将一个可迭代对象变成一个迭代器返回

    def mygen():
    	yield from [1,2,3]
    # 初始化生成器函数, 返回生成器
    gen = mygen()
    
    # 第一次调用
    res = next(gen)
    print(res)
    # 第二次调用
    res = next(gen)
    print(res)
    # 第三次调用
    res = next(gen)
    print(res)
    
    # 在调用越界报错
    

    27.内置方法

    abs 绝对值函数

    round 四舍五入(在n.5情况下则奇进偶不进)

    sum 计算一个序列的和

    max 获取一个序列里面的最大值,可以使用sorted排序获得

    min 获取一个序列里面的最小值

    pow 计算某个数值的n次方,三个参数分别为:基础值,次方值,取余值

    res = pow(2,3)
    print(res)
    # 第三个参数代表取余 2的3次幂 在和6取余 余数2
    res = pow(2,3,7)
    print(res)
    

    range 产生指定范围数据的可迭代对象

    bin 可以将10进制数据转化为2进制

    oct 可以将10进制数据转化为8进制

    hex 可以将10进制数据转化为16进制

    chr 将ASCII码转化为字符串

    ord 将字符串转化为ASCII码

    eval 将字符串当作python代码执行(慎用)

    exec 将字符串当作python代码执行(功能强大,可以针对多行字符)

    repr 不转义字符输出字符串

    input 接收输入字符串,使用input时,会等待输入内容

    hash 生成哈希值,用于比较两个文件内容是否一样,通过hash生成文件哈希值

    with open("ceshi1.txt",mode="r",encoding="utf-8") as fp:
    	res = fp.read()
    	res1 = hash(res)
    print(res1)
    
    with open("ceshi2.txt",mode="r",encoding="utf-8") as fp:
    	res = fp.read()
    	res2 = hash(res)
    print(res2)
    if res1 == res2:
    	print("两个文件内容相同")
    else:
    	print("两个日志文件不通")
    

    28.math模块

    注:模块的使用需要进行引入:import math

    ceil() 向上取整操作,(对比内置round)

    floor() 向下取整操作

    pow() 计算一个数值的n次方(结果为浮点数)(对比内置pow仅有两个参数,只做次方运算)

    sqrt() 开平方运算(结果为浮点数)

    fabs() 计算一个数值的绝对值(结果为浮点数)

    modf() 将一个数值拆分成小数和整数部分,组成元组

    copysign() 第一个数值的正负符号与第二个参数保持一致

    fsum() 将一个容器数据进行求和运算(结果为浮点数)

    pi 圆周率常数π

    29.time模块

    time() 获取本地时间戳,时间戳为从1970年1月1日0时0分0秒到目前的秒数

    mktime() 通过[时间元组]获取[时间戳] (参数是时间元组)

    localtime() 通过[时间戳]获取[时间元组] (默认当前时间)

    ctime() 通过[时间戳]获取[时间字符串] (默认当前时间)

    asctime() 通过[时间元组]获取[时间字符串]参数是时间元组。当时间元组没有指定星期的时候,返回的时间字符串星期会出错,不能自动设定。可以通过mktime和ctime一块使用来解决。

    strftime() 通过[时间元组]格式化[时间字符串] (格式化字符串,[可选时间元组参数])

    strptime() 通过[时间字符串]提取出[时间元组] (时间字符串,格式化字符串)

    sleep() 程序睡眠等待

    perf_counter() 用于计算程序运行的时间

    startime = time.perf_counter()
    for i in range(100000000):
    	pass
    endtime = time.perf_counter()
    res = endtime - startime
    print(res)
    

    30.pickle模块

    作用:将不可直接存储的数据,变得序列化为字节流可存储。可以序列化所有类型数据变成字节流。

    序列化: 把不能够直接存储在文件的数据变得可存储 反序列化: 把数据拿出来,恢复成原来的数据类型

    dumps() 把任意对象序列化成一个bytes

    loads() 把任意bytes反序列化成原来数据

    dump() 把对象序列化后写入到file-like Object(即文件对象)

    load() 把file-like Object(即文件对象)中的内容拿出来,反序列化成原来数据

    # 可以序列化函数
    def func():
    	print(12344)
    res = pickle.dumps(func)
    print(res)
    f = pickle.loads(res)
    print(f)
    f()
    
    # 可以序列化迭代器
    it = iter(range(10))
    res = pickle.dumps(it)
    print(res)
    it = pickle.loads(res)
    print(it)
    for i in it:
    	print(i)
    
    #dump  把对象序列化后写入到file-like Object(即文件对象)
    dic = {"a":1,"b":2}
    with open("ceshi111.pkl",mode="wb") as fp:
    	# dump(要序列化的数据,文件对象)
    	pickle.dump(dic,fp)
    
    #load  把file-like Object(即文件对象)中的内容拿出来,反序列化成原来数据
    with open("ceshi111.pkl",mode="rb") as fp:
    	res = pickle.load(fp)
    print(res,type(res))
    

    31.json模块

    定义:所有编程语言都能够识别的数据格式叫做json,是字符串,有数据类型的限制:int float bool str list tuple dict None

    (1) dumps 和 loads ensure_ascii=False 显示中文 sort_keys=True 按照字典的键排序

    # 序列化
    dic = {"name":"小明","age":19,"sex":"男","family":["爸爸","妈妈","姐姐","妹妹"]}
    res = json.dumps(dic,ensure_ascii=False,sort_keys=True)
    print(res,type(res))
    
    # 反序列化
    dic = json.loads(res)
    print(dic,type(dic))
    

    (2) dump 和 load 针对于文件操作

    with open("test.json",mode="w",encoding="utf-8") as fp:
    	json.dump(dic,fp,ensure_ascii=False,sort_keys=True)
    
    with open("test.json",mode="r",encoding="utf-8") as fp:
    	dic = json.load(fp)
    print(dic,type(dic))
    

    (3) json与pickle的区别

    json 可以连续进行dump , 但是不能连续load load是一次性拿取所有数据,所以不能辨别是多个字典,不能连续load

    dic1 = {"a":1,"b":2}
    dic2 = {"c":3,"d":4}
    with open("ceshi4.json",mode="w",encoding="utf-8") as fp:
    	json.dump(dic1,fp)
    	fp.write("
    ")
    	json.dump(dic2,fp)
    	fp.write("
    ")
    	
    # load 有局限性,只能一次性读取所有数据当成一个整体,不能连续load,一下load出错代码
    """
    with open("ceshi4.json",mode="r",encoding="utf-8") as fp:
    	res = json.load(fp)
    	print(res)
    """
    # 改造
    with open("ceshi4.json",mode="r",encoding="utf-8") as fp:
    	for line in fp:	
    		# 一行一行读取,通过loads进行反序列化变成字典;
    		res = json.loads(line)
    		# print(line)
    		print(res,type(res))
    #总结:通过将每次dump进入的内容进行手动添加换行,然后利用循环按行读取出来,通过loads依次反序列化。
    

    pickle可连续dump,可以连续load

    dic1 = {"a":1,"b":2}
    dic2 = {"c":3,"d":4}
    with open("test.pkl",mode="wb") as fp:
    	pickle.dump(dic1,fp)
    	pickle.dump(dic2,fp)	
    	
    # 可以连续load
    with open("test.pkl",mode="rb") as fp:
    	res = pickle.load(fp)
    	print(res,type(res))
    	res = pickle.load(fp)
    	print(res,type(res))
    
    # 优化
    print("<===>")
    with open("test.pkl",mode="rb") as fp:
    	try:
    		while True:
    			res = pickle.load(fp)
    			print(res,type(res))
    	except:
    		pass
    #总结:pickle可以连续load反序列化,可以使用循环将多个内容全部反序列化,但是,当结束时,没有内容会发生报错,此时用try: ... except: pass 可以将返回的错误排除。
    

    (4) try ... except ...用法

    try: 把有问题的代码放进来,如果出现异常错误 ,执行except代码块; except: pass

    总结: json 和 pickle 两个模块的区别: (1)json序列化之后的数据类型是str,所有编程语言都识别, 但是仅限于(int float bool)(str list tuple dict None) json不能连续load,只能一次性拿出所有数据 (2)pickle序列化之后的数据类型是bytes, 所有数据类型都可转化,但仅限于python之间的存储传输. pickle可以连续load,多套数据放到同一个文件中

    32.random模块

    random() 获取随机0-1之间的小数(左闭右开)

    randrange() 随机获取指定范围内的整数(包含开始值,不包含结束值,间隔值)

    randint() 随机产生指定范围内的整数,只有两个参数,没有间隔值

    uniform() 获取指定范围内的小数(左闭右开),语法上允许数值大小位置反排,但是不推荐。

    choice() 随机获取序列中的一个值

    #自定义获取
    lst=["a","b","c","d"]
    def mychoice(lst):
    	# 0~3
    	num = random.randrange(0,len(lst))
    	return lst[num]
    print(mychoice(lst))
    
    # 使用lambda优化
    mychoice = lambda lst : lst[ random.randrange(0,len(lst)) ]
    print(mychoice(lst))
    

    sample() 随机获取序列中的多个值,第二个参数为选择获取的值的个数

    shuffle() 随机打乱序列中的值(直接打乱原序列)

    案例:随机验证码

    def yanzhengma():
    	strvar = ''
    	# 循环4次,拼接4次
    	for i in range(4):
    		# 数字 0~9
    		num = str(random.randrange(0,10))
    		# 小写字母a~z  97 122
    		s_c = chr(   random.randrange(97,123)   )
    		# 大写字母A~Z  65 90
    		b_c = chr(   random.randrange(65,91)   )
    		# 把所有可能的字符放到列表中
    		lst = [num,s_c,b_c]
    		# 使用choice 随机抽取一个 , 拼接到当前字符串变量中
    		strvar += random.choice(lst)
    	# 返回当前字符串;
    	return strvar
    res = yanzhengma()
    print(res)
    

    33.os模块

    system() 在python中执行系统命令

    popen() 执行系统命令并返回对象,通过read()方法读出字符串

    listdir() 获取指定文件夹中所有内容的名称列表

    getcwd() 获取当前文件所在的默认路径get current working directory

    chdir() 修改当前工作的路径

    environ 获取或修改环境变量

    print(os.environ['PATH'])
    os.environ['PATH'] += ":/home/wangwen/mysoft"
    os.system("wangwen")
    

    33.1 --os模块属性

    name 获取系统标识,linux-->posix windows-->nt

    sep 获取路径分隔符,Linux-->/ windows-->

    linesep 获取系统的换行符,Linux--> windows-->

    34.os.path模块

    import os

    basename() 返回文件名

    dirname() 返回路径部分

    split() 将文件位置拆成单独的文件部分和路径部分,组合为一个元组

    join() 将多个路径和文件组成新的路径,对应不同的系统可以自动加不同的斜杆

    splitext() 将路径分割为后缀和其他部分

    isdir() 检查是否是一个文件夹

    isfile() 检查是否是一个文件

    islink() 检查路径是否是一个链接

    getctime() 获取windows文件的创建时间,Linux文件的权限最近更改时间

    getatime() 获取文件最近一次访问时间

    getmtime() 获取文件最近一次修改时间

    exists() 检查指定的路径是否存在

    getsize() 获取文件大小

    isabs() 检查一个路径是否是绝对路径

    abspath() 将相对路径转化为绝对路径

    35.zipfile模块

    # ### zipfile 压缩模块 (文件后缀zip)
    import zipfile
    
    # 1.压缩文件
    # (1) 创建一个压缩对象
    zf = zipfile.ZipFile("ceshi0919.zip","w",zipfile.ZIP_DEFLATED)
    # (2) 写入内容 write(路径,别名)
    zf.write("/bin/bash","bash")
    zf.write("/bin/bunzip2","bunzip2")
    zf.write("/bin/busybox","/tmp/busybox")
    # (3) 关闭压缩包
    zf.close()
    
    
    # 2.解压文件
    # (1) 创建一个压缩对象
    zf = zipfile.ZipFile("ceshi0919.zip","r")
    # (2) 解压内容
    # 解压单个文件 extract
    # zf.extract("bash","./ceshi0919_1")
    # 解压所有 extractall
    zf.extractall("ceshi0919")
    # (3) 关闭压缩包
    zf.close()
    
    
    # 3.追加文件
    with zipfile.ZipFile("ceshi0919.zip","a",zipfile.ZIP_DEFLATED) as zf:
    	zf.write("/bin/dd","dd")
    
    # 4.查看压缩包中的内容
    with zipfile.ZipFile("ceshi0919.zip","r") as zf:
    	lst = zf.namelist()
    print(lst)
    

    36.面向对象oop

    类:形如一个工厂,是属性和方法的集合

    对象:形如产品,是类实例化的结果

    属性:形如部件,在类中代表变量

    方法:形如制作工艺流程图,在类中代表函数

    类的定义:

    class Car:
    	pass	
    class Car(): # 推荐使用
    	pass	
    class Car(object):	
    	pass
    

    类的实例化:

    表示类中实际产出的过程,实例化结果为对象

    obj=Car()
    print(obj)
    

    类的结构:

    类为属性和方法的集合,严禁把代码直接裸露的写在类中(尽管语法上允许),需要使用一个方法包裹起来,类中的代码可以直接执行;

    类的命名:

    在类中,推荐使用大驼峰命名方法。大驼峰命名方法是将每个单词首字母大写。

    类的封装:

    对类中成员属性和方法的保护,控制外界对内部成员的访问,修改,删除等操作

    36.1 对象的相关操作:

    绑定方法:

    (1)绑定到对象:在调用方法的时候,会默认把该对象当成参数进行传递.
    (2)绑定到类  :在调用方法的时候,会默认把当前类当成参数进行传递;
    self 本对象 ,名字约定俗成
    
    class MyCar():
    	# 公有成员属性
    	logo = "特斯拉"
    	# 私有成员属性
    	__price="1000多万"
    	
    	# 公有成员方法 
    	def run(self):
    		print("小车会跑,能爬坡")
    		print(self.logo)
    		
    	# 私有成员方法
    	def __price_info(self):
    		print("我的价格信息保密")
    
    # 实例化对象
    obj = MyCar()
    
    # (1)实例化的对象访问公有成员属性和方法
    # 调用成员属性
    res = obj.logo
    print(res)
    
    # 调用成员方法
    """在obj调用run方法时,系统会默认把obj当成参数传递给run方法,self形参进行接收obj"""
    obj.run()
    print(obj.__dict__)
    # (2)实例化的对象动态添加公有成员属性和方法
    # 添加公有属性
    obj.zuodian = "布料做的"
    print(obj.zuodian)
    
    # 查看对象的成员结构 __dict__ 
    print(obj.__dict__)
    
    # 添加成员方法
    """在类外,动态为当前对象添加的方法都是静态方法,不会自动传递任何参数,形参实参一一对应"""
    # (1) 动态添加无参方法
    def fangxiangpan():
    	print("这个是造方向盘的方法")
    obj.fangxiangpan = fangxiangpan
    obj.fangxiangpan()
    print(obj.__dict__)
    
    # (2) 动态添加有参方法
    
    # 普通方法
    def luntai(something):
    	print("使用{}轮胎".format(something))
    
    obj.luntai = luntai
    obj.luntai("米其林")
    
    # 绑定方法
    def engine(self,something):
    	print("汽车的品牌是{}".format(self.logo))
    	print("我的引擎是{}".format(something))
    
    obj.engine = engine
    obj.engine(obj,"6缸发动机")	
    
    # 如何让系统把engine变成自动传对象的绑定方法呢? MethodType方法
    import types
    # MethodType(要绑定的方法,要绑定在哪个对象)  => 创建的是绑定方法;系统自动传递obj参数
    obj.engine2 = types.MethodType(engine,obj)
    obj.engine2("6缸发动机")
    
    
    # (3) 动态添加lambda表达式
    obj.chejia = lambda : print("车架是铝合金制作")
    obj.chejia()
    

    36.2 类的相关操作:

    类成员的调用:

    类中的成员:调用的方式有两种:
    	(1)对象.属性  对象.方法()
    	(2)类.属性  类.方法()
    
    class Plane():
    	# 公有成员属性
    	captain = "瑞"
    	# 私有成员属性
    	__air_sister = 88
    	
    	#公有成员方法
    	def fly():
    		print("小飞机会飞",Plane.captain,Plane.__air_sister)
    		
    	# 公有成员方法
    	def run(self):
    		print("小飞机降落的是,三角着地",self.captain)
    	
    	#私有成员方法
    	def __info():
    		print("空姐的数量保密")
    
    # (1)定义的类访问公有成员属性和方法
    # 调用属性
    res = Plane.captain
    print(res)	
    # 调用方法
    Plane.fly()
    # Plane.__info()  私有方法不可调用
    
    # (2)定义的类动态添加公有成员属性和方法 
    
    # 动态添加属性
    Plane.name = "播音787"
    print(Plane.name)
    """__dict__ 返回字典"""
    print(Plane.__dict__)
    
    # 动态添加方法
    # (1) 无参方法
    def zaike():
    	print("飞机能拉人")
    
    Plane.zaike = zaike
    Plane.zaike()
    print(Plane.__dict__)
    # (2) 有参方法
    def party(something):
    	print("在飞机上能{}".format(something))
    Plane.party = party
    Plane.party("开派对")
    
    # (3) lambda 表达式
    Plane.sheying =  lambda : print("在飞机上可以摄影")
    Plane.sheying()
    

    36.3类对象成员的删除和私有成员的调用

    (1) 实例化对象无法删除类的属性和方法

    (2) 类可以删除公有属性和方法

    (3) 直接在类外调用类中成员的两种方式

    #方式一:通过将改名策略来调用,_类__私有成员名,对象或者类点上这种形式来调用
    
    #方式二:可以在类中定义一个公有方法,公有方法中调用私有属性或者方法,然后通过外面调用这个定义的公有方法,从而实现对私有方法或者属性的间接调用。
    

    36.4 总结:

    (1)在类外,无论是对象还是类,都无法执行调用私有成员; (2)类中的成员归该类所有,对象可以使用,但是没有归属权 (3)调用的成员,如果对象中含有,使用对象自己的,如果没有,调用类成员的,如果类成员也没有,直接报错 对象可以使用类中的成员,类不能使用对象中的成员 (4)对象调用类中方法时,必须定义形参,系统会默认把对象当成参数进行调用,需要形参进行接收,保证形参实参一一对应;

    (5)在添加方法时方法后面不加括号,在引用方法时加上括号

    37.魔术方法

    37.1 init 构造方法

    触发时机:实例化对象,初始化的时候触发 功能:为对象添加成员 参数:参数不固定,至少一个self参数 返回值:无

    #(1) 基本语法:
    
    class MyClass():
    	def __init__(self):
    		self.name = “林”
    
    #实例化对象
    
    obj = MyClass()
    print(obj.name)
    
    #(2) 在init构造方法中,加入多个参数
    
    class MyClass():
    	def __init__(self,name):
    		# 左边name是成员属性  右边 name 参数传进来的值
    		self.name = name
    		
    
    #实例化对象
    
    obj = MyClass(“秦”)
    print(obj.name)
    
    #(3) 综合案例
    
    “””
    类可以是一个,对象可以是多个,1个类可以实例化出多个不同的对象
    对象可以使用类中的公有成员,对象和对象之间彼此独立;
    “””
    class Children():
    	def __init__(self,name,skin):
    		self.name = name
    		self.skin = skin
    
    def eat(self):
    	print("小孩天生喜欢吃奶奶")
    	
    def drink(self):
    	print("小孩天生喜欢喝奶奶")
    
    def play(self):
    	print("小孩天生喜欢玩玩具")
    
    def info(self):
    	print("小孩姓名:{},肤色是:{}".format(self.name,self.skin))
    
    
    #实例化第一个小孩
    
    wanggangdan = Children(“王缸蛋”,“彩色”)
    wanggangdan.eat()
    wanggangdan.info()
    	
    
    #实例化第二个小孩
    
    wangtiechu = Children(“王铁杵”,“黑色”)
    wangtiechu.drink()
    wangtiechu.info()
    
    #实例化第二个小孩
    
    wangbaoqiang = Children(“王大锤”,“绿色”)
    wangbaoqiang.play()
    wangbaoqiang.info()
    

    37.2 new 方法

    触发时机:实例化类生成对象的时候触发(触发时机在init之前) 功能:控制对象的创建过程 参数:至少一个cls接受当前的类,其他根据情况决定 返回值:通常返回对象或None

    # (1) 正常创建
    class MyClass_1():
    	a = 5
    # 实例化对象
    obj = MyClass_1()	
    print(obj.a)
    
    # (2)手动创建
    class MyClass():
    	def __new__(cls):
    		# (1)可以控制返回数据的类型
    		# return "aaa"
    		# (2)可以通过父类object帮助完成创建本类对象;
    		"""
    		print(cls)
    		obj = object.__new__(cls)
    		print(obj)
    		return obj
    		"""
    		# (3)可以返回其他类的对象 
    		return obj
    obj = MyClass()
    print(obj)
    print(obj.a)
    
    # (3) 对比 __new__ 和 __init__ 的区别
    
    """
    #__new__  用来创建对象
    #__init__ 用来初始化对象
    #先创建对象,在初始化对象;
    """
    
    class MyClass3():
    	def __new__(cls):
    		print(1)
    		return object.__new__(cls)
    	def __init__(self):
    		print(2)
    
    
    obj = MyClass3()
    
    
    # 处理有参数的情况
    """
    __new__ 和 __init__ 他们的参数要一一对应
    因为先触发__new__,在触发 __init__ 
    """
    class MyClass3():
    	def __new__(cls,name):
    		return object.__new__(cls)
    	def __init__(self,name):
    		self.name = name
    
    obj = MyClass3("林瑞面")
    print(obj.name)
    
    # 升级,处理多参数的情况
    class MyClass4():
    	# 写上*args,**kwargs ,定义一次终身受益,参数不限;
    	def __new__(cls,*args,**kwargs):
    		return object.__new__(cls)
    	def __init__(self,name,skin):
    		self.name = name
    		self.skin = skin
    
    obj = MyClass4("林","黄色")
    print(obj.name)
    print(obj.skin)
    
    
    # (4) 如果返回的不是本类对象,不会调用自己本类的构造方法;
    class MyClass_1():
    	a = 5
    # 实例化对象
    obj22 = MyClass_1()	
    
    class MyClass5():
    	def __new__(cls,*args,**kwargs):
    		print(1)
    		return obj22
    		
    	def __init__(self,name):
    		print(2)
    		self.name = name
    obj = MyClass5("何梦飞")
    # print(obj.name)
    

    37.3 del 析构方法

    触发时机:当对象被内存回收的时候自动触发[1.页面执行完毕回收所有变量 2.所有对象被del的时候] 功能:对象使用完毕后资源回收 参数:一个self接受对象 返回值:无

    class LangDog():
    	def __init__(self,name):
    		self.name = name
    	
    	def eat(self,meat):
    		print("可爱的小狼狗喜欢吃{}".format(meat))
    
    	def __del__(self):
    		print("析构方法被触发")
    		
    # (1) 页面执行完毕回收所有变量
    obj = LangDog("詹姆斯·蛋蛋")
    print("代码执行end ... ")
    
    
    
    # (2)所有对象被del的时候
    """当没有任何一个变量指向该对象,才叫做真正把这个对象给删除了"""
    obj2 = obj
    print(obj2 is obj)
    
    print("start ... ")
    del obj
    del obj2
    print("end ... ")
    
    
    # (3) 用析构方法来模拟文件读取操作;
    import os
    class ReadFile():
    	def __new__(cls,filename):
    		if os.path.exists(filename):
    			return object.__new__(cls)
    		else:
    			return print("该文件不存在")
    
    	def __init__(self,filename):
    		self.fp = open(filename,mode="r",encoding="utf-8")
    
    	# 获取文件里面的内容
    	def getcontent(self):
    		return  self.fp.read()
    		
    	def __del__(self):
    		self.fp.close()
    		
    # 文件存在
    obj = ReadFile("ceshi1.txt")
    res = obj.getcontent()
    print(res)
    
    # 文件不存在
    obj =ReadFile("ceshi2.txt")
    print(obj)
    

    37.4 str 方法

    触发时机: 使用print(对象)或者str(对象)的时候触发 功能: 查看对象 参数: 一个self接受当前对象 返回值: 必须返回字符串类型

    class Cat():
    	gift = "抓老鼠"
    	
    	def __init__(self,name):
    		self.name = name
    		
    	def cat_info(self):
    		return "小猫天生喜欢{}".format(self.gift)
    	
    	def __str__(self):
    		return self.cat_info()
    		# return 1 强制类型是字符串;
    		
    tom = Cat("汤姆")
    # 触发方式一
    print(tom)
    # 触发方式二
    res = str(tom)
    print(res)
    

    37.5 repr 方法

    触发时机: 使用repr(对象)的时候触发 功能: 查看对象,与魔术方法str相似 参数: 一个self接受当前对象 返回值: 必须返回字符串类型

    class Mouse():
    	gift = "打洞"
    	def __init__(self,name):
    		self.name = name
    		
    	def mouse_info(self):
    		return "龙生龙,凤生凤,老鼠的儿子会{}".format(self.gift)
    	
    	def __repr__(self):
    		return self.mouse_info()
    		# return 23 必须是字符串
    	"""	
    	把函数当成变量进行赋值;__str__ 和 __repr__ 都是系统内置的,
    	系统默认在repr魔术方法存在的前提下,底层默认赋值;由系统完成
    	"""
    	__str__ = __repr__
    
    jerry = Mouse("杰瑞")
    res = repr(jerry)
    print(res)
    
    print(jerry)
    res = str(jerry)
    print(res)
    

    38.继承

    继承分为单继承和多继承,一个类继承另外一个类,当前这个类叫子类(衍生类),被继承的那个类叫父类(基类,超类)。在python中,所有类都继承父类object

    38.1 单继承

    # ### 单继承
    class Father():
    	skin = "蓝色"
    	def hobby(self):
    		print("抽烟,喝酒,烫头")
    	def __secret(self):
    		print("爸爸的小秘密是每个月在床底下塞200块钱")
    		
    class Daughter(Father):
    	pass
    
    # (1) 子父继承之后,子类可以使用父类所有的公有成员
    obj = Daughter()
    print(obj.skin)
    print(Daughter.skin)
    
    # (2) 子父继承之后,子类不能使用父类的私有成员
    class Son(Father):
    	def func(self):
    		self.__secret()
    	
    obj = Son()
    # obj.__secret() error
    # obj.func() error
    
    # (3) 子父继承之后,子类可以重新定义父类同名方法
    class Son(Father):
    	
    	def hobby(self):
    		print("泡妞,上网,嗑药")
    
    obj = Son()
    obj.hobby()
    

    38.2 多继承

    # ### 多继承
    
    # (1)基本语法
    class Father():
    	f_property = "浓眉大耳,瞳孔有力,凶神恶煞,身宽体肥"
    	
    	def hobby(self):
    		print("吃喝嫖赌抽,坑蒙拐骗偷")
    		
    class Mother():
    	m_property = "沉鱼落雁,闭月羞花,一笑倾城,再笑倾城,三笑倾国"
    	
    	def hobby(self):
    		print("打麻将,拔罐,抠脚,修眉,做头发,修胡子,捋一捋护心毛")
    		
    class Daughter(Father,Mother):
    	pass
    	
    # 实例化对象
    obj = Daughter()
    print(obj.f_property)
    obj.hobby()
    
    # (2) super 调用父类的绑定方法
    
    class Father():
    	f_property = "浓眉大耳,瞳孔有力,凶神恶煞,身宽体肥"
    	
    	def hobby1():
    		print("吃喝嫖赌抽,坑蒙拐骗偷")
    		
    class Mother():
    	m_property = "沉鱼落雁,闭月羞花,一笑倾城,再笑倾城,三笑倾国"
    	
    	def hobby2(self):
    		print("打麻将,拔罐,抠脚,修眉,做头发,修胡子,捋一捋护心毛")
    
    print("<======>")
    # 利用子类调用父类相关成员
    class Son(Father,Mother):
    	f_property = "鲁班七号,智商250."
    	# 用类的方式调用父类的成员
    	def s_skill1(self):
    		Father.hobby1()
    		print(Mother.m_property)
    
    	# 用self对象的方法调用父类成员
    	def s_skill2(self):
    		self.hobby2()
    		print(self.f_property)
    
    	# 用super调用父类成员
    	def s_skill3(self):
    		super().hobby2()
    		print(super().f_property)
    obj = Son()
    # obj.s_skill1()
    # obj.s_skill2()
    obj.s_skill3()
    
    """
    # self 和 super 的区别;
    self  先优先调用自己本对象当中的成员,如果有直接调用,如果没有调用父类的成员
    super 永远只调用父类的成员,父类没有就直接报错;
    """
    

    38.3 菱形继承

    (1)super本身是一个类 super()是一个对象 用于调用父类的绑定方法 (2)super() 只应用在绑定方法中,默认自动传递self对象 (前提:super所在作用域存在self) (3)super用途: 解决复杂的多继承调用顺序

    class Human():
    	pty = 1
    	def feelT(self):
    		print("远古人类,天热了,脱树皮1")
    		print(self.pty)
    		print("远古人类,天冷了,脱兽皮2")
    
    class Man(Human):
    	pty = 2
    	def feelT(self):
    		print("现代男人,天热了,开空调3")
    		super().feelT()
    		print("现代男人,天冷了,开空调4")
    
    class Woman(Human):
    	pty = 3
    	def feelT(self):
    		print("现代女人,天热了,去游泳,穿比基尼5")
    		super().feelT()
    		print("现代女人,天冷了,裹大棉袄,穿秋裤6")
    
    class Children(Man,Woman):
    	pty = 4
    	def feelT(self):
    		print("小孩天热了,吃冰棍7")
    		super().feelT()
    		print("小孩天冷了,穿棉袄8")
    
    
    obj = Children()
    obj.feelT()
    
    """
    c3算法:可以计算出调用的顺序:
    获取类的调用顺序: 类.mro() => 列表,super就是按照这个列表的呈现顺序,依次调用;
    """
    lst = Children.mro()
    print(lst)
    """
    [
    <class '__main__.Children'>, 
    <class '__main__.Man'>, 
    <class '__main__.Woman'>, 
    <class '__main__.Human'>, 
    <class 'object'>
    ]
    """
    
    # 判断子父关系 类 和 类之间的判定
    res = issubclass(Children,Woman)
    # 在小括号中,有一个类满足,返回True
    res = issubclass(Children,(Woman,Man) )
    # 有血缘关系,在一条继承链上即可
    res = issubclass(Children,Human )
    print(res)
    
    # 判断类型 对象 和 类之间的判定
    res = isinstance(obj,Children)
    # 有血缘关系,在一条继承链上即可
    res = isinstance(obj,Man)
    res = isinstance(obj,Human)
    print(res)
    

    39.单态与多态

    39.1 多态

    多态: 不同的子类对象,调用同名方法,产生不同的执行结果

    特征: 继承,重写 针对的是对象 , 在不改变原函数名字和代码的前提下,扩展了新功能

    class Soldier():	
    	def attack(self):
    		pass
    		
    	def back(self):
    		pass
    	
    
    class Navy(Soldier):
    	def attack(self):
    		print("[海军] 扔鱼叉子,插死一个算一个")
    	def back(self):
    		print("[海军] 弃船跳海,下海喂鱼")
    
    class AirForce(Soldier):
    	def attack(self):
    		print("[空军] 把二营长的意大利给我端上来,空中射击 ")
    	def back(self):
    		print("[空军] 弃机跳伞,落地成盒")
    
    # 各就位准备
    obj_army = Army()
    obj_navy = Navy()
    obj_airforce = AirForce()
    
    lst = [obj_army , obj_navy  ,obj_airforce ]
    
    # 请将军下达命令:
    while True:
    	strvar = """
    		1.全体出击
    		2.全体撤退
    		3.空军上,其他人撤退
    	"""
    	print(strvar)
    
    	num = input("请将军下达命令:")
    	
    	for i in lst:
    		# print(i)
    		if num == '1':
    			i.attack()
    		elif num == "2":
    			i.back()
    		elif num == "3":
    			if isinstance(i,AirForce):
    				i.attack()
    			else:
    				i.back()		
    		else:
    			print("风太大,我听不到~")
    			break
    

    39.2 单态

    单态:这个类无论实例化多少次,都有且只有一个对象

    单态方法:判断对象是否存在,存在就返回,不存在就创建

    # 1.基本语法
    class Singleton():
    	__obj = None
    	def __new__(cls):
    		if cls.__obj is None:
    			# 创建一个对象,存储在cls.__obj
    			cls.__obj = object.__new__(cls)
    		return cls.__obj 
    
    obj1 = Singleton()
    obj2 = Singleton()
    obj3 = Singleton()
    print(obj1,obj2,obj3)
    
    """
    第一次实例化的时候,触发__new__方法,
    判断 cls.__obj is None 条件为真(由于第一次实例化时,类调用__obj属性,所以判断为空) 借助父类创建一个对象,赋值给cls.__obj 
    return cls.__obj 
    
    第二次实例化的时候,触发__new__方法,
    判断 cls.__obj is None 条件为假(用第一次实例化的对象和None作对比,显然不为None,所以返回上一次的对象,不执行创建对象)
    return cls.__obj
    
    第三次实例化的时候,触发__new__方法,
    判断 cls.__obj is None 条件为假(同上)
    return cls.__obj
    
    所以三个变量指向的是同一个对象;(三次返回的都是第一个对象)
    """
    
    
    # 2.加上对象初始化
    class Singleton():
    	__obj = None
    	def __new__(cls,*args,**kwargs):
    		if cls.__obj is None:
    			cls.__obj = object.__new__(cls)
    		return cls.__obj
    
    	def __init__(self,name):
    		self.name = name
    obj1 = Singleton("李四")
    obj2 = Singleton("王五")
    print(obj1.name) # 王五
    print(obj2.name) # 王五
    
    """
    obj1 = Singleton("李四") 第一次调用__init__的时候
    self.name = "李四" obj1.name => 李四
    
    obj2 = Singleton("王五") 第二次调用__init__的时候
    self.name = "王五"  obj2.name => 王五
    
    obj1 和 obj2 是不通的两个变量指向同一个对象,(后一次的实例化参数覆盖了前一次的参数,且两个变量指向了同一个对象,所以打印结果都为后者)
    对象.name 调用了两遍 ,两边都是王五;
    """
    
  • 相关阅读:
    BZOJ1036 [ZJOI2008]树的统计Count
    3224: Tyvj 1728 普通平衡树
    BZOJ 3343教主的魔法
    BZOJ 2002[Hnoi2010]Bounce 弹飞绵羊
    BZOJ1503 [NOI2004]郁闷的出纳员
    BZOJ1588 [HNOI2002]营业额统计
    带有上下界的网络流
    堆优化 dijkstra +路径输出
    luogu P3388 【模板】割点(割顶)
    Tarjan 算法求无向图的割顶和桥
  • 原文地址:https://www.cnblogs.com/hrers/p/11565265.html
Copyright © 2011-2022 走看看