zoukankan      html  css  js  c++  java
  • 关于 Python 基础

    Python 入门

    字面量和变量

    • 字面量就是一个一个的值,比如:1,2,3,4,5,6,‘HELLO’字面量所表示的意思就是它的字面的值,在程序中可以直接使用字面量
    • 变量(variable)变量可以用来保存字面量,并且变量中保存的字面量是不定的 变量本身没有任何意思,它会根据不同的字面量表示不同的意思

    数据类型

    数据类型指的就是变量的值得类型,也就是可以为变量赋哪些值

    • 数值
      • 整型
        • 布尔值
      • 浮点型
      • 复数
    • 字符串
    • 空值

    对象(object)

    • Python是一门面向对象的语言
    • 一切皆对象!
    • 程序运行当中,所有的数据都是存储到内存当中然后再运行的!
    • 对象就是内存中专门用来存储指定数据的一块区域
    • 对象实际上就是一个容器,专门用来存储数据

    对象的结构

    每个对象中都要保存三种数据

    • id (标识)
      • id 用来标识对象的唯一性,每一个对象都有唯一的 id
      • 对象的 id 就相当于人的身份证号一样
      • 可以通过 id() 函数来查看对象的 id
      • id 是由解析器生成的,在 CPython 中,id 就是对象的内存地址
      • 对象一旦创建,则它的 id 永远不能再改变
    • type(类型)
      • 类型用来标识当前对象所属的类型
      • 比如:intstrfloatbool ...
      • 类型决定了对象有哪些功能
      • 通过 type() 函数来查看对象的类型
      • Python 是一门强类型的语言,对象一旦创建类型便不能修改
    • value(值)
      • 值就是对象中存储的具体的数据
      • 对于有些对象值是可以改变的
      • 对象分成两大类:可变对象 不可变对象
        • 可变对象的值可以改变
        • 不可变对象的值不能改变,之前学习的对象都是不可变对象

    变量和对象

    • 对象并没有直接存储到变量中,在 Python 中变量更像是给对象起了一个别名
    • 变量中存储的不是对象的值,而是对象的 id(内存地址),当我们使用变量时,实际上就是在通过对象 id 在查找对象
    • 变量中保存的对象,只有在为变量重新赋值时才会改变
    • 变量和变量之间是相互独立的,修改一个变量不会影响另一个变量

    类型转换

    • 所谓的类型转换,将一个类型的对象转换为其他对象
    • 类型转换不是改变对象本身的类型,而是根据当前对象的值创建一个新对象

    序列

    列表(list

    • 列表是 Python 中的一个对象
    • 对象(object)就是内存中专门用来存储数据的一块区域
    • 之前我们学习的对象,像数值,它只能保存一个单一的数据
    • 列表中可以保存多个有序的数据
    • 列表是用来存储对象的对象
    • 列表的使用:
    # 创建列表,通过[]来创建列表
    my_list = [] # 创建了一个空列表
    # print(my_list , type(my_list))
    
    # 列表存储的数据,我们称为元素
    # 一个列表中可以存储多个元素,也可以在创建列表时,来指定列表中的元素
    my_list = [10] # 创建一个只包含一个元素的列表
    
    # 当向列表中添加多个元素时,多个元素之间使用,隔开
    my_list = [10,20,30,40,50] # 创建了一个保护有5个元素的列表
    
    # 列表中可以保存任意的对象
    my_list = [10,'hello',True,None,[1,2,3],print]
    
    # 列表中的对象都会按照插入的顺序存储到列表中,
    #   第一个插入的对象保存到第一个位置,第二个保存到第二个位置
    # 我们可以通过索引(index)来获取列表中的元素
    #   索引是元素在列表中的位置,列表中的每一个元素都有一个索引
    #   索引是从0开始的整数,列表第一个位置索引为0,第二个位置索引为1,第三个位置索引为2,以此类推
    my_list = [10,20,30,40,50]
    
    # 通过索引获取列表中的元素
    # 语法:my_list[索引] my_list[0]
    # print(my_list[4])
    # 如果使用的索引超过了最大的范围,会抛出异常
    # print(my_list[5]) IndexError: list index out of range
    
    # 获取列表的长度,列表中元素的个数
    # len()函数,通过该函数可以获取列表的长度
    # 获取到的长度的值,是列表的最大索引 + 1
    print(len(my_list)) # 5
    

    切片

    # 切片
    # 切片指从现有列表中,获取一个子列表
    # 创建一个列表,一般创建列表时,变量的名字会使用复数
    stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精']
    
    # 列表的索引可以是负数
    # 如果索引是负数,则从后向前获取元素,-1表示倒数第一个,-2表示倒数第二个 以此类推
    # print(stus[-2])
    
    # 通过切片来获取指定的元素
    # 语法:列表[起始:结束]
    #   通过切片获取元素时,会包括起始位置的元素,不会包括结束位置的元素
    #   做切片操作时,总会返回一个新的列表,不会影响原来的列表
    #   起始和结束位置的索引都可以省略不写
    #   如果省略结束位置,则会一直截取到最后
    #   如果省略起始位置,则会从第一个元素开始截取
    #   如果起始位置和结束位置全部省略,则相当于创建了一个列表的副本
    # print(stus[1:])
    # print(stus[:3])
    # print(stus[:])
    # print(stus)
    
    # 语法:列表[起始:结束:步长]
    # 步长表示,每次获取元素的间隔,默认值是1
    # print(stus[0:5:3])
    # 步长不能是0,但是可以是负数
    # print(stus[::0]) ValueError: slice step cannot be zero
    # 如果是负数,则会从列表的后部向前边取元素
    print(stus[::-1])
    

    通用操作

    # + 和 *
    # +可以将两个列表拼接为一个列表
    my_list = [1,2,3] + [4,5,6]
    
    # * 可以将列表重复指定的次数
    my_list = [1,2,3] * 5
    
    # print(my_list)
    
    # 创建一个列表
    stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精','沙和尚','沙和尚']
    
    # in 和 not in
    # in用来检查指定元素是否存在于列表中
    #   如果存在,返回True,否则返回False
    # not in用来检查指定元素是否不在列表中
    #   如果不在,返回True,否则返回False
    # print('牛魔王' not in stus)
    # print('牛魔王' in stus)
    
    # len()获取列表中的元素的个数
    
    # min() 获取列表中的最小值
    # max() 获取列表中的最大值
    arr = [10,1,2,5,100,77]
    # print(min(arr) , max(arr))
    
    # 两个方法(method),方法和函数基本上是一样,只不过方法必须通过 对象.方法() 的形式调用
    # xxx.print() 方法实际上就是和对象关系紧密的函数
    # s.index() 获取指定元素在列表中的第一次出现时索引
    # print(stus.index('沙和尚'))
    # index()的第二个参数,表示查找的起始位置 , 第三个参数,表示查找的结束位置
    # print(stus.index('沙和尚',3,7))
    # 如果要获取列表中没有的元素,会抛出异常
    # print(stus.index('牛魔王')) ValueError: '牛魔王' is not in list
    # s.count() 统计指定元素在列表中出现的次数
    print(stus.count('牛魔王'))
    

    修改元素

    # 创建一个列表
    stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精']
    
    # print("修改前:",stus)
    # 修改列表中的元素
    # 直接通过索引来修改元素
    stus[0] = 'sunwukong'
    stus[2] = '哈哈'
    # 通过del来删除元素
    del stus[2] # 删除索引为2的元素
    
    # print('修改后:',stus)
    
    stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精']
    
    # print("修改前:",stus)
    
    # 通过切片来修改列表
    # 在给切片进行赋值时,只能使用序列
    # stus[0:2] = ['牛魔王','红孩儿'] 使用新的元素替换旧元素
    # stus[0:2] = ['牛魔王','红孩儿','二郎神']
    # stus[0:0] = ['牛魔王'] # 向索引为0的位置插入元素
    # 当设置了步长时,序列中元素的个数必须和切片中元素的个数一致
    # stus[::2] = ['牛魔王','红孩儿','二郎神']
    
    # 通过切片来删除元素
    # del stus[0:2]
    # del stus[::2]
    # stus[1:3] = []
    
    # print('修改后:',stus)
    
    # 以上操作,只适用于可变序列
    s = 'hello'
    # s[1] = 'a' 不可变序列,无法通过索引来修改
    # 可以通过 list() 函数将其他的序列转换为list
    s = list(s)
    print(s)
    

    列表的方法

    # 列表的方法
    stus = ['孙悟空','猪八戒','沙和尚','唐僧']
    # print('原列表:',stus)
    
    # append()
    # 向列表的最后添加一个元素
    # stus.append('唐僧')
    
    # insert()
    # 向列表的指定位置插入一个元素
    # 参数:
    #   1.要插入的位置
    #   2.要插入的元素
    # stus.insert(2,'唐僧')
    
    # extend()
    # 使用新的序列来扩展当前序列
    # 需要一个序列作为参数,它会将该序列中的元素添加到当前列表中
    # stus.extend(['唐僧','白骨精'])
    # stus += ['唐僧','白骨精']
    
    # clear()
    # 清空序列
    # stus.clear()
    
    # pop()
    # 根据索引删除并返回被删除的元素
    
    # result = stus.pop(2) # 删除索引为2的元素
    # result = stus.pop() # 删除最后一个
    # print('result =',result)
    
    # remove()
    # 删除指定值得元素,如果相同值得元素有多个,只会删除第一个
    # stus.remove('猪八戒')
    
    # reverse()
    # 用来反转列表
    # stus.reverse()
    
    # sort()
    # 用来对列表中的元素进行排序,默认是升序排列
    # 如果需要降序排列,则需要传递一个reverse=True作为参数
    my_list = list('asnbdnbasdabd')
    my_list = [10,1,20,3,4,5,0,-2]
    
    print('修改前',my_list)
    
    my_list.sort(reverse=True)
    print('修改后',my_list)
    # print('修改后:',stus)
    

    遍历列表

    # 遍历列表,指的就是将列表中的所有元素取出来
    # 创建列表
    stus = ['孙悟空','猪八戒','沙和尚','唐僧','白骨精','蜘蛛精']
    
    # 遍历列表
    # print(stus[0])
    # print(stus[1])
    # print(stus[2])
    # print(stus[3])
    
    # 通过while循环来遍历列表
    # i = 0
    # while i < len(stus):
    #     print(stus[i])
    #     i += 1
    
    # 通过for循环来遍历列表
    # 语法:
    #   for 变量 in 序列 :
    #       代码块
    # for循环的代码块会执行多次,序列中有几个元素就会执行几次
    #   没执行一次就会将序列中的一个元素赋值给变量,
    #   所以我们可以通过变量,来获取列表中的元素
    
    for s in stus :
        print(s)
    

    序列(sequence

    • 序列是 Python 中最基本的一种数据结构
    • 数据结构指计算机中数据存储的方式
    • 序列用于保存一组有序的数据,所有的数据在序列当中都有一个唯一的位置(索引)并且序列中的数据会按照添加的顺序来分配索引
    • 序列的分类:
      • 可变序列(序列中的元素可以改变):
        • 列表(list
      • 不可变序列(序列中的元素不能改变):
        • 字符串(str)
        • 元组(tuple
    # range()是一个函数,可以用来生成一个自然数的序列
    r = range(5) # 生成一个这样的序列[0,1,2,3,4]
    r = range(0,10,2)
    r = range(10,0,-1)
    # 该函数需要三个参数
    #   1.起始位置(可以省略,默认是0)
    #   2.结束位置
    #   3.步长(可以省略,默认是1)
    
    # print(list(r))
    
    # 通过range()可以创建一个执行指定次数的for循环
    # for()循环除了创建方式以外,其余的都和while一样,
    #   包括else、包括break continue都可以在for循环中使用
    #   并且for循环使用也更加简单
    # 将之前使用while循环做的练习,再使用for循环完成一次!
    for i in range(30):
        print(i)
    
    # for s in 'hello':
    #     print(s)
    

    元组

    # 元组 tuple
    # 元组是一个不可变的序列
    # 它的操作的方式基本上和列表是一致的
    # 所以你在操作元组时,就把元组当成是一个不可变的列表就ok了
    # 一般当我们希望数据不改变时,就使用元组,其余情况都使用列表
    
    # 创建元组
    # 使用()来创建元组
    my_tuple = () # 创建了一个空元组
    # print(my_tuple,type(my_tuple)) # <class 'tuple'>
    
    my_tuple = (1,2,3,4,5) # 创建了一个5个元素的元组
    # 元组是不可变对象,不能尝试为元组中的元素重新赋值
    # my_tuple[3] = 10 TypeError: 'tuple' object does not support item assignment
    # print(my_tuple[3])
    
    # 当元组不是空元组时,括号可以省略
    # 如果元组不是空元组,它里边至少要有一个,
    my_tuple = 10,20,30,40
    my_tuple = 40,
    # print(my_tuple , type(my_tuple))
    
    my_tuple = 10 , 20 , 30 , 40
    
    # 元组的解包(解构)
    # 解包指就是将元组当中每一个元素都赋值给一个变量
    a,b,c,d = my_tuple
    
    # print("a =",a)
    # print("b =",b)
    # print("c =",c)
    # print("d =",d)
    
    a = 100
    b = 300
    # print(a , b)
    
    # 交互a 和 b的值,这时我们就可以利用元组的解包
    a , b = b , a
    
    # print(a , b)
    my_tuple = 10 , 20 , 30 , 40
    
    
    # 在对一个元组进行解包时,变量的数量必须和元组中的元素的数量一致
    # 也可以在变量前边添加一个*,这样变量将会获取元组中所有剩余的元素
    a , b , *c = my_tuple
    a , *b , c = my_tuple
    *a , b , c = my_tuple
    a , b , *c = [1,2,3,4,5,6,7]
    a , b , *c = 'hello world'
    # 不能同时出现两个或以上的*变量
    # *a , *b , c = my_tuple SyntaxError: two starred expressions in assignment
    print('a =',a)
    print('b =',b)
    print('c =',c)
    

    可变对象

    • 每个对象中都保存了三个数据:
      • id(标识)
      • type(类型)
      • value(值)
    • 列表就是一个可变对象
    • a[0] = 10 (改对象)
      • 这个操作是在通过变量去修改对象的值
      • 这种操作不会改变变量所指向的对象
      • 当我们去修改对象时,如果有其他变量也指向了该对象,则修改也会在其他的变量中体现
    • a = [4,5,6] (改变量)
      • 这个操作是在给变量重新赋值
      • 这种操作会改变变量所指向的对象
      • 为一个变量重新赋值时,不会影响其他的变量
    • 一般只有在为变量赋值时才是修改变量,其余的都是修改对象
    # # 可变对象
    # a = [1,2,3]
    # print('修改前:', a , id(a))
    
    # # 通过索引修改列表
    # a[0] = 10
    # print('修改后:', a , id(a))
    
    # # 为变量重新赋值
    # a = [4,5,6]
    # print('修改后:', a , id(a))
    
    
    a = [1,2,3]
    b = a
    # b[0] = 10
    b = [10,2,3]
    # print("a",a,id(a))
    # print("b",b,id(b))
    
    # == !=  is is not
    # == != 比较的是对象的值是否相等
    # is is not 比较的是对象的id是否相等(比较两个对象是否是同一个对象)
    
    a = [1,2,3]
    b = [1,2,3]
    print(a,b)
    print(id(a),id(b))
    print(a == b) # a和b的值相等,使用==会返回True
    print(a is b) # a和b不是同一个对象,内存地址不同,使用is会返回False
    

    字典(dict

    • 字典属于一种新的数据结构,称为映射mapping
    • 字典的作用和列表类似,都是用来存储对象的容器
    • 列表存储数据的性能很好,但是查询数据的性能的很差
    • 在字典中每一个元素都有一个唯一的名字,通过这个唯一的名字可以快速的查找到指定的元素
    • 在查询元素时,字典的效率是非常快的
    • 在字典中可以保存多个对象,每个对象都会有一个唯一的名字
      • 这个唯一的名字,我们称其为键(key),通过 key 可以快速的查询 value
      • 这个对象,我们称其为值(value)
      • 所以字典,我们也称为叫做键值对(key-value)结构
      • 每个字典中都可以有多个键值对,而每一个键值对我们称其为一项(item)
    # 字典
    # 使用 {} 来创建字典
    d = {} # 创建了一个空字典
    
    # 创建一个保护有数据的字典
    # 语法:
    #   {key:value,key:value,key:value}
    #   字典的值可以是任意对象
    #   字典的键可以是任意的不可变对象(int、str、bool、tuple ...),但是一般我们都会使用str
    #       字典的键是不能重复的,如果出现重复的后边的会替换到前边的
    # d = {'name':'孙悟空' , 'age':18 , 'gender':'男' , 'name':'sunwukong'}
    d = {
    'name':'孙悟空' ,
    'age':18 ,
    'gender':'男' ,
    'name':'sunwukong'
    }
    
    # print(d , type(d))
    
    # 需要根据键来获取值
    # print(d['name'],d['age'],d['gender'])
    
    # 如果使用了字典中不存在的键,会报错
    # print(d['hello']) KeyError: 'hello'
    

    字典的使用

    # 创建字典
    # 使用{}
    # 语法:{k1:v1,k2:v2,k3:v3}
    
    # 使用 dict()函数来创建字典
    # 每一个参数都是一个键值对,参数名就是键,参数名就是值(这种方式创建的字典,key都是字符串)
    d = dict(name='孙悟空',age=18,gender='男')
    
    # 也可以将一个包含有双值子序列的序列转换为字典
    # 双值序列,序列中只有两个值,[1,2] ('a',3) 'ab'
    # 子序列,如果序列中的元素也是序列,那么我们就称这个元素为子序列
    # [(1,2),(3,5)]
    d = dict([('name','孙悟饭'),('age',18)])
    # print(d , type(d))
    d = dict(name='孙悟空',age=18,gender='男')
    
    # len() 获取字典中键值对的个数
    # print(len(d))
    
    # in 检查字典中是否包含指定的键
    # not in 检查字典中是否不包含指定的键
    # print('hello' in d)
    
    # 获取字典中的值,根据键来获取值
    # 语法:d[key]
    # print(d['age'])
    
    # n = 'name'
    # print(d[n])
    
    # 通过[]来获取值时,如果键不存在,会抛出异常 KeyError
    # get(key[, default]) 该方法用来根据键来获取字典中的值
    #   如果获取的键在字典中不存在,会返回None
    #   也可以指定一个默认值,来作为第二个参数,这样获取不到值时将会返回默认值
    # print(d.get('name'))
    # print(d.get('hello','默认值'))
    
    # 修改字典
    # d[key] = value 如果key存在则覆盖,不存在则添加
    d['name'] = 'sunwukong' # 修改字典的key-value
    d['address'] = '花果山' # 向字典中添加key-value
    
    # print(d)
    # setdefault(key[, default]) 可以用来向字典中添加key-value
    #   如果key已经存在于字典中,则返回key的值,不会对字典做任何操作
    #   如果key不存在,则向字典中添加这个key,并设置value
    result = d.setdefault('name','猪八戒')
    result = d.setdefault('hello','猪八戒')
    
    # print('result =',result)
    # print(d)
    
    # update([other])
    # 将其他的字典中的key-value添加到当前字典中
    # 如果有重复的key,则后边的会替换到当前的
    d = {'a':1,'b':2,'c':3}
    d2 = {'d':4,'e':5,'f':6, 'a':7}
    d.update(d2)
    
    # print(d)
    # 删除,可以使用 del 来删除字典中的 key-value
    del d['a']
    del d['b']
    
    # popitem()
    # 随机删除字典中的一个键值对,一般都会删除最后一个键值对
    #   删除之后,它会将删除的key-value作为返回值返回
    #   返回的是一个元组,元组中有两个元素,第一个元素是删除的key,第二个是删除的value
    # 当使用popitem()删除一个空字典时,会抛出异常 KeyError: 'popitem(): dictionary is empty'
    # d.popitem()
    # result = d.popitem()
    
    # pop(key[, default])
    # 根据key删除字典中的key-value
    # 会将被删除的value返回!
    # 如果删除不存在的key,会抛出异常
    #   如果指定了默认值,再删除不存在的key时,不会报错,而是直接返回默认值
    result = d.pop('d')
    result = d.pop('z','这是默认值')
    
    # del d['z'] z不存在,报错
    # result = d.popitem()
    # result = d.popitem()
    # result = d.popitem()
    # result = d.popitem()
    
    # clear()用来清空字典
    d.clear()
    
    # print('result =',result)
    # print(d)
    
    # copy()
    # 该方法用于对字典进行浅复制
    # 复制以后的对象,和原对象是独立,修改一个不会影响另一个
    # 注意,浅复制会简单复制对象内部的值,如果值也是一个可变对象,这个可变对象不会被复制
    d = {'a':1,'b':2,'c':3}
    d2 = d.copy()
    # d['a'] = 100
    
    d = {'a':{'name':'孙悟空','age':18},'b':2,'c':3}
    d2 = d.copy()
    d2['a']['name'] = '猪八戒'
    
    
    print('d = ',d , id(d))
    print('d2 = ',d2 , id(d2))
    

    字典的遍历

    # 遍历字典
    # keys() 该方法会返回字典的所有的key
    #   该方法会返回一个序列,序列中保存有字典的所有的键
    d = {'name':'孙悟空','age':18,'gender':'男'}
    
    # 通过遍历keys()来获取所有的键
    # for k in d.keys() :
    #     print(k , d[k])
    
    # values()
    # 该方法会返回一个序列,序列中保存有字典的左右的值
    # for v in d.values():
    #     print(v)
    
    # items()
    # 该方法会返回字典中所有的项
    # 它会返回一个序列,序列中包含有双值子序列
    # 双值分别是,字典中的key和value
    # print(d.items())
    for k,v in d.items() :
        print(k , '=' , v)
    

    集合(set

    • 集合和列表非常相似
    • 不同点:
      • 集合中只能存储不可变对象
      • 集合中存储的对象是无序(不是按照元素的插入顺序保存)
      • 集合中不能出现重复的元素
    # 集合
    # 使用 {} 来创建集合
    s = {10,3,5,1,2,1,2,3,1,1,1,1} # <class 'set'>
    # s = {[1,2,3],[4,6,7]} TypeError: unhashable type: 'list'
    # 使用 set() 函数来创建集合
    s = set() # 空集合
    # 可以通过set()来将序列和字典转换为集合
    s = set([1,2,3,4,5,1,1,2,3,4,5])
    s = set('hello')
    s = set({'a':1,'b':2,'c':3}) # 使用set()将字典转换为集合时,只会包含字典中的键
    
    # 创建集合
    s = {'a' , 'b' , 1 , 2 , 3 , 1}
    
    # 使用in和not in来检查集合中的元素
    # print('c' in s)
    
    # 使用len()来获取集合中元素的数量
    # print(len(s))
    
    # add() 向集合中添加元素
    s.add(10)
    s.add(30)
    
    # update() 将一个集合中的元素添加到当前集合中
    #   update()可以传递序列或字典作为参数,字典只会使用键
    s2 = set('hello')
    s.update(s2)
    s.update((10,20,30,40,50))
    s.update({10:'ab',20:'bc',100:'cd',1000:'ef'})
    
    # {1, 2, 3, 100, 40, 'o', 10, 1000, 'a', 'h', 'b', 'l', 20, 50, 'e', 30}
    # pop()随机删除并返回一个集合中的元素
    # result = s.pop()
    
    # remove()删除集合中的指定元素
    s.remove(100)
    s.remove(1000)
    
    # clear()清空集合
    s.clear()
    
    # copy()对集合进行浅复制
    
    # print(result)
    print(s , type(s))
    

    集合的运算

    # 在对集合做运算时,不会影响原来的集合,而是返回一个运算结果
    # 创建两个集合
    s = {1,2,3,4,5}
    s2 = {3,4,5,6,7}
    
    # & 交集运算
    result = s & s2 # {3, 4, 5}
    
    # | 并集运算
    result = s | s2 # {1,2,3,4,5,6,7}
    
    # - 差集
    result = s - s2 # {1, 2}
    
    # ^ 异或集 获取只在一个集合中出现的元素
    result = s ^ s2 # {1, 2, 6, 7}
    
    # <= 检查一个集合是否是另一个集合的子集
    # 如果a集合中的元素全部都在b集合中出现,那么a集合就是b集合的子集,b集合是a集合超集
    a = {1,2,3}
    b = {1,2,3,4,5}
    
    result = a <= b # True
    result = {1,2,3} <= {1,2,3} # True
    result = {1,2,3,4,5} <= {1,2,3} # False
    
    # < 检查一个集合是否是另一个集合的真子集
    # 如果超集b中含有子集a中所有元素,并且b中还有a中没有的元素,则b就是a的真超集,a是b的真子集
    result = {1,2,3} < {1,2,3} # False
    result = {1,2,3} < {1,2,3,4,5} # True
    
    # >= 检查一个集合是否是另一个的超集
    # > 检查一个集合是否是另一个的真超集
    print('result =',result)
    

    函数

    函数简介(function

    • 函数也是一个对象
    • 对象是内存中专门用来存储数据的一块区域
    • 函数可以用来保存一些可执行的代码,并且可以在需要时,对这些语句进行多次的调用
    • 创建函数
    def 函数名([形参1,形参2,...形参n]) :
        代码块
    
    • 函数名必须要符号标识符的规范(可以包含字母、数字、下划线、但是不能以数字开头)
    • 函数中保存的代码不会立即执行,需要调用函数代码才会执行
    • 调用函数:函数对象()
    • 定义函数一般都是要实现某种功能的

    函数的参数

    • 在定义函数时,可以在函数名后的 () 中定义数量不等的形参,多个形参之间使用 , 隔开
    • 形参(形式参数),定义形参就相当于在函数内部声明了变量,但是并不赋值
    • 实参(实际参数)
      • 如果函数定义时,指定了形参,那么在调用函数时也必须传递实参,实参将会赋值给对应的形参,简单来说,有几个形参就得传几个实参
    # 求任意三个数的乘积
    def mul(a,b,c):
        print(a*b*c)
    
    # 根据不同的用户名显示不同的欢迎信息
    def welcome(username):
        print('欢迎',username,'光临')
    
    # mul(1,2,3)
    # welcome('孙悟空')
    
    # 定义一个函数
    # 定义形参时,可以为形参指定默认值
    # 指定了默认值以后,如果用户传递了参数则默认值没有任何作用
    #   如果用户没有传递,则默认值就会生效
    def fn(a = 5 , b = 10 , c = 20):
        print('a =',a)
        print('b =',b)
        print('c =',c)
    
    # fn(1 , 2 , 3)
    # fn(1 , 2)
    # fn()
    
    # 实参的传递方式
    # 位置参数
    # 位置参数就是将对应位置的实参复制给对应位置的形参
    # 第一个实参赋值给第一个形参,第二个实参赋值给第二个形参 。。。
    # fn(1 , 2 , 3)
    
    # 关键字参数
    # 关键字参数,可以不按照形参定义的顺序去传递,而直接根据参数名去传递参数
    # fn(b=1 , c=2 , a=3)
    # print('hello' , end='')
    # 位置参数和关键字参数可以混合使用
    # 混合使用关键字和位置参数时,必须将位置参数写到前面
    # fn(1,c=30)
    
    def fn2(a):
        print('a =',a)
    
    # 函数在调用时,解析器不会检查实参的类型
    # 实参可以传递任意类型的对象
    b = 123
    b = True
    b = 'hello'
    b = None
    b = [1,2,3]
    
    # fn2(b)
    fn2(fn)
    
    def fn3(a , b):
        print(a+b)
    
    # fn3(123,"456")
    
    def fn4(a):
        # 在函数中对形参进行重新赋值,不会影响其他的变量
        # a = 20
        # a是一个列表,尝试修改列表中的元素
        # 如果形参执行的是一个对象,当我们通过形参去修改对象时
        #   会影响到所有指向该对象的变量
        a[0] = 30
        print('a =',a,id(a))
    
    c = 10
    c = [1,2,3]
    
    # fn4(c)
    # fn4(c.copy())
    # fn4(c[:])
    
    # print('c =',c,id(c))
    

    不定长参数

    # 不定长的参数
    # 定义一个函数,可以求任意个数字的和
    def sum(*nums):
        # 定义一个变量,来保存结果
        result = 0
        # 遍历元组,并将元组中的数进行累加
        for n in nums :
            result += n
        print(result)
    
    
    # sum(123,456,789,10,20,30,40)
    
    # 在定义函数时,可以在形参前边加上一个*,这样这个形参将会获取到所有的实参
    # 它将会将所有的实参保存到一个元组中
    # a,b,*c = (1,2,3,4,5,6)
    
    # *a会接受所有的位置实参,并且会将这些实参统一保存到一个元组中(装包)
    def fn(*a):
        print("a =",a,type(a))
    
    # fn(1,2,3,4,5)
    # 带星号的形参只能有一个
    # 带星号的参数,可以和其他参数配合使用
    # 第一个参数给a,第二个参数给b,剩下的都保存到c的元组中
    # def fn2(a,b,*c):
    #     print('a =',a)
    #     print('b =',b)
    #     print('c =',c)
    
    # 可变参数不是必须写在最后,但是注意,带*的参数后的所有参数,必须以关键字参数的形式传递
    # 第一个参数给a,剩下的位置参数给b的元组,c必须使用关键字参数
    # def fn2(a,*b,c):
    #     print('a =',a)
    #     print('b =',b)
    #     print('c =',c)
    
    # 所有的位置参数都给a,b和c必须使用关键字参数
    # def fn2(*a,b,c):
    #     print('a =',a)
    #     print('b =',b)
    #     print('c =',c)
    
    # 如果在形参的开头直接写一个*,则要求我们的所有的参数必须以关键字参数的形式传递
    def fn2(*,a,b,c):
        print('a =',a)
        print('b =',b)
        print('c =',c)
    # fn2(a=3,b=4,c=5)
    
    # *形参只能接收位置参数,而不能接收关键字参数
    # def fn3(*a) :
    #     print('a =',a)
    
    # **形参可以接收其他的关键字参数,它会将这些参数统一保存到一个字典中
    #   字典的key就是参数的名字,字典的value就是参数的值
    # **形参只能有一个,并且必须写在所有参数的最后
    def fn3(b,c,**a) :
        print('a =',a,type(a))
        print('b =',b)
        print('c =',c)
    
    # fn3(b=1,d=2,c=3,e=10,f=20)
    
    # 参数的解包(拆包)
    def fn4(a,b,c):
        print('a =',a)
        print('b =',b)
        print('c =',c)
    
    # 创建一个元组
    t = (10,20,30)
    
    # 传递实参时,也可以在序列类型的参数前添加星号,这样他会自动将序列中的元素依次作为参数传递
    # 这里要求序列中元素的个数必须和形参的个数的一致
    # fn4(*t)
    
    # 创建一个字典
    d = {'a':100,'b':200,'c':300}
    # 通过 **来对一个字典进行解包操作
    fn4(**d)
    

    返回值

    # 返回值,返回值就是函数执行以后返回的结果
    # 可以通过 return 来指定函数的返回值
    # 可以之间使用函数的返回值,也可以通过一个变量来接收函数的返回值
    
    def sum(*nums):
        # 定义一个变量,来保存结果
        result = 0
        # 遍历元组,并将元组中的数进行累加
        for n in nums :
            result += n
        print(result)
    
    # sum(123,456,789)
    
    
    # return 后边跟什么值,函数就会返回什么值
    # return 后边可以跟任意的对象,返回值甚至可以是一个函数
    def fn():
        # return 'Hello'
        # return [1,2,3]
        # return {'k':'v'}
        def fn2() :
            print('hello')
        return fn2 # 返回值也可以是一个函数
    
    r = fn() # 这个函数的执行结果就是它的返回值
    # r()
    # print(fn())
    # print(r)
    
    # 如果仅仅写一个return 或者 不写return,则相当于return None
    def fn2() :
        a = 10
        return
    
    # 在函数中,return后的代码都不会执行,return 一旦执行函数自动结束
    def fn3():
        print('hello')
        return
        print('abc')
    
    # r = fn3()
    # print(r)
    
    def fn4() :
        for i in range(5):
            if i == 3 :
                # break 用来退出当前循环
                # continue 用来跳过当次循环
                return # return 用来结束函数
            print(i)
        print('循环执行完毕!')
    
    # fn4()
    
    def sum(*nums):
        # 定义一个变量,来保存结果
        result = 0
        # 遍历元组,并将元组中的数进行累加
        for n in nums :
            result += n
        return result
    
    r = sum(123,456,789)
    
    # print(r + 778)
    
    def fn5():
        return 10
    
    # fn5 和 fn5()的区别
    print(fn5) # fn5是函数对象,打印fn5实际是在打印函数对象 <function fn5 at 0x05771BB8>
    print(fn5()) # fn5()是在调用函数,打印fn5()实际上是在打印fn5()函数的返回值 10
    

    文档字符串

    # help()是Python中的内置函数
    # 通过help()函数可以查询python中的函数的用法
    # 语法:help(函数对象)
    # help(print) # 获取print()函数的使用说明
    
    # 文档字符串(doc str)
    # 在定义函数时,可以在函数内部编写文档字符串,文档字符串就是函数的说明
    #   当我们编写了文档字符串时,就可以通过help()函数来查看函数的说明
    #   文档字符串非常简单,其实直接在函数的第一行写一个字符串就是文档字符串
    def fn(a:int,b:bool,c:str='hello') -> int:
        '''
        这是一个文档字符串的示例
    
        函数的作用:。。。。。
        函数的参数:
            a,作用,类型,默认值。。。。
            b,作用,类型,默认值。。。。
            c,作用,类型,默认值。。。。
        '''
        return 10
    
    help(fn)
    

    作用域与命名空间

    # 作用域(scope)
    # 作用域指的是变量生效的区域
    b = 20 # 全局变量
    
    def fn():
        a = 10 # a定义在了函数内部,所以他的作用域就是函数内部,函数外部无法访问
        print('函数内部:','a =',a)
        print('函数内部:','b =',b)
    
    # fn()
      
    
    # print('函数外部:','a =',a)
    # print('函数外部:','b =',b)
    
    # 在Python中一共有两种作用域
    #  全局作用域
    #   - 全局作用域在程序执行时创建,在程序执行结束时销毁
    #   - 所有函数以外的区域都是全局作用域
    #   - 在全局作用域中定义的变量,都属于全局变量,全局变量可以在程序的任意位置被访问
    #
    #  函数作用域
    #   - 函数作用域在函数调用时创建,在调用结束时销毁
    #   - 函数每调用一次就会产生一个新的函数作用域
    #   - 在函数作用域中定义的变量,都是局部变量,它只能在函数内部被访问
    #
    #  变量的查找
    #   - 当我们使用变量时,会优先在当前作用域中寻找该变量,如果有则使用,
    #       如果没有则继续去上一级作用域中寻找,如果有则使用,
    #       如果依然没有则继续去上一级作用域中寻找,以此类推
    #       直到找到全局作用域,依然没有找到,则会抛出异常
    #           NameError: name 'a' is not defined
    
    def fn2():
        def fn3():
            print('fn3中:','a =',a)
        fn3()
    
    # fn2()
    
    a = 20
    
    def fn3():
        # a = 10 # 在函数中为变量赋值时,默认都是为局部变量赋值
        # 如果希望在函数内部修改全局变量,则需要使用global关键字,来声明变量
        global a # 声明在函数内部的使用a是全局变量,此时再去修改a时,就是在修改全局的a
        a = 10 # 修改全局变量
        print('函数内部:','a =',a)
    
    # fn3()
    # print('函数外部:','a =',a)
    
    
    # 命名空间(namespace)
    # 命名空间指的是变量存储的位置,每一个变量都需要存储到指定的命名空间当中
    # 每一个作用域都会有一个它对应的命名空间
    # 全局命名空间,用来保存全局变量。函数命名空间用来保存函数中的变量
    # 命名空间实际上就是一个字典,是一个专门用来存储变量的字典
    
    # locals()用来获取当前作用域的命名空间
    # 如果在全局作用域中调用locals()则获取全局命名空间,如果在函数作用域中调用locals()则获取函数命名空间
    # 返回的是一个字典
    scope = locals() # 当前命名空间
    print(type(scope))
    # print(a)
    # print(scope['a'])
    # 向scope中添加一个key-value
    scope['c'] = 1000 # 向字典中添加key-value就相当于在全局中创建了一个变量(一般不建议这么做)
    # print(c)
    
    def fn4():
        a = 10
        # scope = locals() # 在函数内部调用locals()会获取到函数的命名空间
        # scope['b'] = 20 # 可以通过scope来操作函数的命名空间,但是也是不建议这么做
    
        # globals() 函数可以用来在任意位置获取全局命名空间
        global_scope = globals()
        # print(global_scope['a'])
        global_scope['a'] = 30
        # print(scope)
    
    fn4()
    

    函数式编程

    • 在 Python 中,函数是一等对象
    • 一等对象一般都会具有如下特点:
      • 对象是在运行时创建的
      • 能赋值给变量或作为数据结构中的元素
      • 能作为参数传递
      • 能作为返回值返回
    • 高阶函数
      • 高阶函数至少要符合以下两个特点中的一个
        • 接收一个或多个函数作为参数
        • 将函数作为返回值返回
    • 装饰器

    高阶函数

    # 高阶函数
    # 接收函数作为参数,或者将函数作为返回值的函数是高阶函数
    # 当我们使用一个函数作为参数时,实际上是将指定的代码传递进了目标函数
    
    # 创建一个列表
    l = [1,2,3,4,5,6,7,8,9,10]
    
    # 定义一个函数
    #   可以将指定列表中的所有的偶数,保存到一个新的列表中返回
    
    # 定义一个函数,用来检查一个任意的数字是否是偶数
    def fn2(i) :
        if i % 2 == 0 :
            return True
    
        return False
    
    # 这个函数用来检查指定的数字是否大于5
    def fn3(i):
        if i > 5 :
            return True
        return False
    
    def fn(func , lst) :
    
        '''
            fn()函数可以将指定列表中的所有偶数获取出来,并保存到一个新列表中返回
    
            参数:
                lst:要进行筛选的列表
        '''
        # 创建一个新列表
        new_list = []
    
        # 对列表进行筛选
        for n in lst :
            # 判断n的奇偶
            if func(n) :
                new_list.append(n)
            # if n > 5 :
            #     new_list.append(n)
    
    
    
    
        # 返回新列表
        return new_list
    
    # def fn4(i):
    #     if i % 3 == 0:
    #         return True
    #     return False
    
    def fn4(i):
        return i % 3 == 0
    
    # print(fn(fn4 , l))
    
    # filter()
    # filter()可以从序列中过滤出符合条件的元素,保存到一个新的序列中
    # 参数:
    #  1.函数,根据该函数来过滤序列(可迭代的结构)
    #  2.需要过滤的序列(可迭代的结构)
    # 返回值:
    #   过滤后的新序列(可迭代的结构)
    
    # fn4是作为参数传递进filter()函数中
    #   而fn4实际上只有一个作用,就是作为filter()的参数
    #   filter()调用完毕以后,fn4就已经没用
    # 匿名函数 lambda 函数表达式 (语法糖)
    #   lambda函数表达式专门用来创建一些简单的函数,他是函数创建的又一种方式
    #   语法:lambda 参数列表 : 返回值
    #   匿名函数一般都是作为参数使用,其他地方一般不会使用
    
    def fn5(a , b):
        return a + b
    
    # (lambda a,b : a + b)(10,20)
    # 也可以将匿名函数赋值给一个变量,一般不会这么做
    fn6 = lambda a,b : a + b
    # print(fn6(10,30))
    
    
    r = filter(lambda i : i > 5 , l)
    # print(list(r))
    
    # map()
    # map()函数可以对可迭代对象中的所有元素做指定的操作,然后将其添加到一个新的对象中返回
    l = [1,2,3,4,5,6,7,8,9,10]
    
    r = map(lambda i : i ** 2 , l)
    
    # print(list(r))
    
    # sort()
    # 该方法用来对列表中的元素进行排序
    # sort()方法默认是直接比较列表中的元素的大小
    # 在sort()可以接收一个关键字参数 , key
    #   key需要一个函数作为参数,当设置了函数作为参数
    #   每次都会以列表中的一个元素作为参数来调用函数,并且使用函数的返回值来比较元素的大小
    l = ['bb','aaaa','c','ddddddddd','fff']
    # l.sort(key=len)
    
    l = [2,5,'1',3,'6','4']
    l.sort(key=int)
    # print(l)
    
    # sorted()
    # 这个函数和sort()的用法基本一致,但是sorted()可以对任意的序列进行排序
    #   并且使用sorted()排序不会影响原来的对象,而是返回一个新对象
    
    l = [2,5,'1',3,'6','4']
    # l = "123765816742634781"
    
    print('排序前:',l)
    print(sorted(l,key=int))
    print('排序后:',l)
    

    闭包

    # 将函数作为返回值返回,也是一种高阶函数
    # 这种高阶函数我们也称为叫做闭包,通过闭包可以创建一些只有当前函数能访问的变量
    #   可以将一些私有的数据藏到的闭包中
    
    def fn():
    
        a = 10
    
        # 函数内部再定义一个函数
        def inner():
            print('我是fn2' , a)
    
        # 将内部函数 inner作为返回值返回
        return inner
    
    # r是一个函数,是调用fn()后返回的函数
    # 这个函数实在fn()内部定义,并不是全局函数
    # 所以这个函数总是能访问到fn()函数内的变量
    r = fn()
    
    # r()
    
    # 求多个数的平均值
    # nums = [50,30,20,10,77]
    
    # sum()用来求一个列表中所有元素的和
    # print(sum(nums)/len(nums))
    
    # 形成闭包的要件
    #   ① 函数嵌套
    #   ② 将内部函数作为返回值返回
    #   ③ 内部函数必须要使用到外部函数的变量
    def make_averager():
        # 创建一个列表,用来保存数值
        nums = []
    
        # 创建一个函数,用来计算平均值
        def averager(n) :
            # 将n添加到列表中
            nums.append(n)
            # 求平均值
            return sum(nums)/len(nums)
    
        return averager
    
    averager = make_averager()
    
    print(averager(10))
    print(averager(20))
    print(averager(30))
    print(averager(40))
    

    装饰器

    # 创建几个函数
    
    def add(a , b):
        '''
            求任意两个数的和
        '''
        r = a + b
        return r
    
    
    def mul(a , b):
        '''
            求任意两个数的积
        '''
        r = a * b
        return r
    
    # 希望函数可以在计算前,打印开始计算,计算结束后打印计算完毕
    #  我们可以直接通过修改函数中的代码来完成这个需求,但是会产生以下一些问题
    #   ① 如果要修改的函数过多,修改起来会比较麻烦
    #   ② 并且不方便后期的维护
    #   ③ 并且这样做会违反开闭原则(OCP)
    #           程序的设计,要求开发对程序的扩展,要关闭对程序的修改
    
    
    # r = add(123,456)
    # print(r)
    
    # 我们希望在不修改原函数的情况下,来对函数进行扩展
    def fn():
        print('我是fn函数....')
    
    # 只需要根据现有的函数,来创建一个新的函数
    def fn2():
        print('函数开始执行~~~')
        fn()
        print('函数执行结束~~~')
    
    # fn2()
    
    def new_add(a,b):
        print('计算开始~~~')
        r = add(a,b)
        print('计算结束~~~')
        return r
    
    # r = new_add(111,222)
    # print(r)
    
    # 上边的方式,已经可以在不修改源代码的情况下对函数进行扩展了
    #   但是,这种方式要求我们每扩展一个函数就要手动创建一个新的函数,实在是太麻烦了
    #   为了解决这个问题,我们创建一个函数,让这个函数可以自动的帮助我们生产函数
    
    def begin_end(old):
        '''
            用来对其他函数进行扩展,使其他函数可以在执行前打印开始执行,执行后打印执行结束
    
            参数:
                old 要扩展的函数对象
        '''
        # 创建一个新函数
        def new_function(*args , **kwargs):
            print('开始执行~~~~')
            # 调用被扩展的函数
            result = old(*args , **kwargs)
            print('执行结束~~~~')
            # 返回函数的执行结果
            return result
        # 返回新函数
        return new_function
    
    f = begin_end(fn)
    f2 = begin_end(add)
    f3 = begin_end(mul)
    
    # r = f()
    # r = f2(123,456)
    # r = f3(123,456)
    # print(r)
    # 向begin_end()这种函数我们就称它为装饰器
    #   通过装饰器,可以在不修改原来函数的情况下来对函数进行扩展
    #   在开发中,我们都是通过装饰器来扩展函数的功能的
    # 在定义函数时,可以通过@装饰器,来使用指定的装饰器,来装饰当前的函数
    #   可以同时为一个函数指定多个装饰器,这样函数将会安装从内向外的顺序被装饰
    
    def fn3(old):
        '''
            用来对其他函数进行扩展,使其他函数可以在执行前打印开始执行,执行后打印执行结束
    
            参数:
                old 要扩展的函数对象
        '''
        # 创建一个新函数
        def new_function(*args , **kwargs):
            print('fn3装饰~开始执行~~~~')
            # 调用被扩展的函数
            result = old(*args , **kwargs)
            print('fn3装饰~执行结束~~~~')
            # 返回函数的执行结果
            return result
        # 返回新函数
        return new_function
    
    @fn3
    @begin_end
    def say_hello():
        print('大家好~~~')
    
    say_hello()
    

    对象(object)

    • 对象是内存中专门用来存储数据的一块区域。
    • 对象中可以存放各种数据(比如:数字、布尔值、代码)
    • 对象由三部分组成:
      • 对象的标识(id)
      • 对象的类型(type)
      • 对象的值(value)

    类(class)

    • 我们目前所学习的对象都是 Python 内置的对象
    • 但是内置对象并不能满足所有的需求,所以我们在开发中经常需要自定义一些对象
    • 类,简单理解它就相当于一个图纸。在程序中我们需要根据类来创建对象
    • 类就是对象的图纸!
    • 我们也称对象是类的实例(instance)
    • 如果多个对象是通过一个类创建的,我们称这些对象是一类对象
    • int()float()bool()str()list()dict() .... 这些都是类
    • a = int(10) 创建一个 int 类的实例 等价于 a = 10
    • 我们自定义的类都需要使用大写字母开头,使用大驼峰命名法(帕斯卡命名法)来对类命名
    • 类也是一个对象!
    • 类就是一个用来创建对象的对象!
    • 类是 type 类型的对象,定义类实际上就是定义了一个 type 类型的对象
    a = int(10) # 创建一个int类的实例
    b = str('hello') # 创建一个str类的实例
    
    # print(a , type(a))
    # print(b , type(b))
    
    # 定义一个简单的类
    # 使用class关键字来定义类,语法和函数很像!
    # class 类名([父类]):
    #   代码块
    # <class '__main__.MyClass'>
    class MyClass():
        pass
    
    # print(MyClass)
    # 使用MyClass创建一个对象
    # 使用类来创建对象,就像调用一个函数一样
    mc = MyClass() # mc就是通过MyClass创建的对象,mc是MyClass的实例
    mc_2 = MyClass()
    mc_3 = MyClass()
    mc_4 = MyClass()
    # mc mc_2 mc_3 mc_4 都是MyClass的实例,他们都是一类对象
    # isinstance()用来检查一个对象是否是一个类的实例
    result = isinstance(mc_2,MyClass)
    result = isinstance(mc_2,str)
    
    # print(mc , type(mc))
    # print('result =',result)
    
    # print(id(MyClass) , type(MyClass))
    
    # 现在我们通过MyClass这个类创建的对象都是一个空对象
    # 也就是对象中实际上什么都没有,就相当于是一个空的盒子
    # 可以向对象中添加变量,对象中的变量称为属性
    # 语法:对象.属性名 = 属性值
    mc.name = '孙悟空'
    mc_2.name = '猪八戒'
    
    print(mc_2.name)
    

    类的定义

    • 类和对象都是对现实生活中的事物或程序中的内容的抽象
    • 实际上所有的事物都由两部分构成:
      • 数据(属性)
      • 行为(方法)
    • 在类的代码块中,我们可以定义变量函数,变量会成为该类实例的公共属性,所有的该类实例都可以通过 对象.属性名 的形式访问;函数会成为该类实例的公共方法,所有该类实例都可以通过 对象.方法名() 的形式调用方法
      • 注意:方法调用时,第一个参数由解析器自动传递,所以定义方法时,至少要定义一个形参!
    • 实例为什么能访问到类中的属性和方法:类中定义的属性和方法都是公共的,任何该类实例都可以访问
      • 属性和方法查找的流程
        • 当我们调用一个对象的属性时,解析器会先在当前对象中寻找是否含有该属性,
          • 如果有,则直接返回当前的对象的属性值,
          • 如果没有,则去当前对象的类对象中去寻找,如果有则返回类对象的属性值,
          • 如果类对象中依然没有,则报错!
      • 类对象和实例对象中都可以保存属性(方法)
        • 如果这个属性(方法)是所有的实例共享的,则应该将其保存到类对象中
        • 如果这个属性(方法)是某个实例独有,则应该保存到实例对象中
          • 一般情况下,属性保存到实例对象中,而方法需要保存到类对象中
    # 尝试定义一个表示人的类
    class Person :
        # 在类的代码块中,我们可以定义变量和函数
        # 在类中我们所定义的变量,将会成为所有的实例的公共属性
        # 所有实例都可以访问这些变量
        name = 'swk' # 公共属性,所有实例都可以访问
        # 在类中也可以定义函数,类中的定义的函数,我们称为方法
        # 这些方法可以通过该类的所有实例来访问
        def say_hello(self) :
            # 方法每次被调用时,解析器都会自动传递第一个实参
            # 第一个参数,就是调用方法的对象本身,
            #   如果是p1调的,则第一个参数就是p1对象
            #   如果是p2调的,则第一个参数就是p2对象
            # 一般我们都会将这个参数命名为self
    
            # say_hello()这个方法,可以显示如下格式的数据:
            #   你好!我是 xxx
            #   在方法中不能直接访问类中的属性
            print('你好!我是 %s' %self.name)
    
    # 创建Person的实例
    p1 = Person()
    p2 = Person()
    
    # print(p2.name)
    
    # 调用方法,对象.方法名()
    # 方法调用和函数调用的区别
    # 如果是函数调用,则调用时传几个参数,就会有几个实参
    # 但是如果是方法调用,默认传递一个参数,所以方法中至少要定义一个形参
    
    
    # 修改p1的name属性
    p1.name = '猪八戒'
    p2.name = '沙和尚'
    
    p1.say_hello() # '你好!我是 猪八戒'
    p2.say_hello() # '你好!我是 沙和尚'
    
    # del p2.name # 删除p2的name属性
    
    # print(p1.name)
    # print(p2.name)
    

    创建对象的流程

    p1 = Person() 的运行流程

    • 创建一个变量
    • 在内存中创建一个新对象
    • __init__(self) 方法执行
    • 将对象的 id 赋值给变量
    class Person :
        # 在类中可以定义一些特殊方法(魔术方法)
        # 特殊方法都是以__开头,__结尾的方法
        # 特殊方法不需要我们自己调用,不要尝试去调用特殊方法
        # 特殊方法将会在特殊的时刻自动调用
        # 学习特殊方法:
        #   1.特殊方法什么时候调用
        #   2.特殊方法有什么作用
        # 创建对象的流程
        # p1 = Person()的运行流程
        #   1.创建一个变量
        #   2.在内存中创建一个新对象
        #   3.__init__(self)方法执行
        #   4.将对象的id赋值给变量
    
        # init会在对象创建以后离开执行
        # init可以用来向新创建的对象中初始化属性
        # 调用类创建对象时,类后边的所有参数都会依次传递到init()中
        def __init__(self,name):
            # print(self)
            # 通过self向新建的对象中初始化属性
            self.name = name
    
        def say_hello(self):
            print('大家好,我是%s'%self.name)
    
    
    # 目前来讲,对于Person类来说name是必须的,并且每一个对象中的name属性基本上都是不同
    # 而我们现在是将name属性在定义为对象以后,手动添加到对象中,这种方式很容易出现错误
    # 我们希望,在创建对象时,必须设置name属性,如果不设置对象将无法创建
    #   并且属性的创建应该是自动完成的,而不是在创建对象以后手动完成
    # p1 = Person()
    # # 手动向对象添加name属性
    # p1.name = '孙悟空'
    
    # p2 = Person()
    # p2.name = '猪八戒'
    
    # p3 = Person()
    # p3.name = '沙和尚'
    
    # p3.say_hello()
    
    p1 = Person('孙悟空')
    p2 = Person('猪八戒')
    p3 = Person('沙和尚')
    p4 = Person('唐僧')
    # p1.__init__() 不要这么做
    
    # print(p1.name)
    # print(p2.name)
    # print(p3.name)
    # print(p4.name)
    
    p4.say_hello()
    

    类的基本结构

    class 类名([父类]) :
        公共的属性...
    
        # 对象的初始化方法
        def __init__(self,...):
            ...
    
        # 其他的方法
        def method_1(self,...):
            ...
        def method_2(self,...):
            ...
        ...
    

    封装

    class Rectangle:
        '''
            表示矩形的类
        '''
        def __init__(self,width,height):
            self.hidden_width = width
            self.hidden_height = height
    
        def get_width(self):
            return self.hidden_width
    
        def get_height(self):
            return self.hidden_height
    
        def set_width(self , width):
            self.hidden_width = width
    
        def set_height(self , height):
            self.hidden_height = height
    
        def get_area(self):
            return self.hidden_width * self.hidden_height
    
    # r = Rectangle(5,2)  
    # r.set_width(10)
    # r.set_height(20)
    
    # print(r.get_area())
    
    
    # 可以为对象的属性使用双下划线开头,__xxx
    # 双下划线开头的属性,是对象的隐藏属性,隐藏属性只能在类的内部访问,无法通过对象访问
    # 其实隐藏属性只不过是Python自动为属性改了一个名字
    #   实际上是将名字修改为了,_类名__属性名 比如 __name -> _Person__name
    # class Person:
    #     def __init__(self,name):
    #         self.__name = name
    
    #     def get_name(self):
    #         return self.__name
    
    #     def set_name(self , name):
    #         self.__name = name
    
    # p = Person('孙悟空')
    
    # print(p.__name) __开头的属性是隐藏属性,无法通过对象访问
    # p.__name = '猪八戒'
    # print(p._Person__name)
    # p._Person__name = '猪八戒'
    
    # print(p.get_name())
    
    # 使用__开头的属性,实际上依然可以在外部访问,所以这种方式我们一般不用
    #   一般我们会将一些私有属性(不希望被外部访问的属性)以_开头
    #   一般情况下,使用_开头的属性都是私有属性,没有特殊需要不要修改私有属性
    class Person:
        def __init__(self,name):
            self._name = name
    
        def get_name(self):
            return self._name
    
        def set_name(self , name):
            self._name = name
    
    p = Person('孙悟空')
    
    print(p._name)
    
    class Person:
        def __init__(self,name,age):
            self._name = name
            self._age = age
    
        # property装饰器,用来将一个get方法,转换为对象的属性
        # 添加为property装饰器以后,我们就可以像调用属性一样使用get方法
        # 使用property装饰的方法,必须和属性名是一样的
        @property
        def name(self):
            print('get方法执行了~~~')
            return self._name
    
        # setter方法的装饰器:@属性名.setter
        @name.setter
        def name(self , name):
            print('setter方法调用了')
            self._name = name
    
        @property
        def age(self):
            return self._age
    
        @age.setter
        def age(self , age):
            self._age = age
    
    
    
    p = Person('猪八戒',18)
    
    p.name = '孙悟空'
    p.age = 28
    
    print(p.name,p.age)
    

    继承

    # 继承
    
    # 定义一个类 Animal(动物)
    #   这个类中需要两个方法:run() sleep()
    class Animal:
        def run(self):
            print('动物会跑~~~')
    
        def sleep(self):
            print('动物睡觉~~~')
    
        # def bark(self):
        #     print('动物嚎叫~~~')
    
    # 定义一个类 Dog(狗)
    #   这个类中需要三个方法:run() sleep() bark()
    # class Dog:
    #     def run(self):
    #         print('狗会跑~~~')
    
    #     def sleep(self):
    #         print('狗睡觉~~~')
    
    #     def bark(self):
    #         print('汪汪汪~~~')
    
    # 有一个类,能够实现我们需要的大部分功能,但是不能实现全部功能
    # 如何能让这个类来实现全部的功能呢?
    #   ① 直接修改这个类,在这个类中添加我们需要的功能
    #       - 修改起来会比较麻烦,并且会违反OCP原则
    #   ② 直接创建一个新的类
    #       - 创建一个新的类比较麻烦,并且需要大量的进行复制粘贴,会出现大量的重复性代码
    #   ③ 直接从Animal类中来继承它的属性和方法
    #       - 继承是面向对象三大特性之一
    #       - 通过继承我们可以使一个类获取到其他类中的属性和方法
    #       - 在定义类时,可以在类名后的括号中指定当前类的父类(超类、基类、super)
    #           子类(衍生类)可以直接继承父类中的所有的属性和方法
    #
    #  通过继承可以直接让子类获取到父类的方法或属性,避免编写重复性的代码,并且也符合OCP原则
    #   所以我们经常需要通过继承来对一个类进行扩展
    
    class Dog(Animal):
        def bark(self):
            print('汪汪汪~~~')
    
        def run(self):
            print('狗跑~~~~')
    
    class Hashiqi(Dog):
        def fan_sha(self):
            print('我是一只傻傻的哈士奇')
    
    d = Dog()
    h = Hashiqi()
    
    # d.run()
    # d.sleep()
    # d.bark()
    
    # r = isinstance(d , Dog)
    # r = isinstance(d , Animal)
    # print(r)
    
    # 在创建类时,如果省略了父类,则默认父类为object
    #   object是所有类的父类,所有类都继承自object
    class Person(object):
        pass
    
    # issubclass() 检查一个类是否是另一个类的子类
    # print(issubclass(Animal , Dog))
    # print(issubclass(Animal , object))
    # print(issubclass(Person , object))
    
    # isinstance()用来检查一个对象是否是一个类的实例
    #   如果这个类是这个对象的父类,也会返回True
    #   所有的对象都是object的实例
    print(isinstance(print , object))
    
    class A(object):
        def test(self):
            print('AAA')
    
    class B(object):
        def test(self):
            print('B中的test()方法~~')
    
        def test2(self):
            print('BBB')
    
    # 在Python中是支持多重继承的,也就是我们可以为一个类同时指定多个父类
    #   可以在类名的()后边添加多个类,来实现多重继承
    #   多重继承,会使子类同时拥有多个父类,并且会获取到所有父类中的方法
    # 在开发中没有特殊的情况,应该尽量避免使用多重继承,因为多重继承会让我们的代码过于复杂
    # 如果多个父类中有同名的方法,则会现在第一个父类中寻找,然后找第二个,然后找第三个。。。
    #   前边父类的方法会覆盖后边父类的方法
    class C(A,B):
        pass
    
    # 类名.__bases__ 这个属性可以用来获取当前类的所有父类
    # print(C.__bases__) (<class '__main__.B'>,)
    # print(B.__bases__) (<class 'object'>,)
    
    # print(C.__bases__) # (<class '__main__.A'>, <class '__main__.B'>)
    
    c = C()
    
    c.test()
    

    多态

    # 多态是面向对象的三大特征之一
    # 多态从字面上理解是多种形态
    # 狗(狼狗、藏獒、哈士奇、古牧 。。。)
    # 一个对象可以以不同的形态去呈现
    
    # 定义两个类
    class A:
        def __init__(self,name):
            self._name = name
    
        @property
        def name(self):
            return self._name
    
        @name.setter
        def name(self,name):
            self._name = name
    
    class B:
        def __init__(self,name):
            self._name = name
    
        def __len__(self):
            return 10
    
        @property
        def name(self):
            return self._name
    
        @name.setter
        def name(self,name):
            self._name = name
    
    class C:
        pass
    
    
    a = A('孙悟空')
    b = B('猪八戒')
    c = C()
    
    # 定义一个函数
    # 对于say_hello()这个函数来说,只要对象中含有name属性,它就可以作为参数传递
    #   这个函数并不会考虑对象的类型,只要有name属性即可
    def say_hello(obj):
        print('你好 %s'%obj.name)
    
    # 在say_hello_2中我们做了一个类型检查,也就是只有obj是A类型的对象时,才可以正常使用,
    #   其他类型的对象都无法使用该函数,这个函数就违反了多态
    # 违反了多态的函数,只适用于一种类型的对象,无法处理其他类型对象,这样导致函数的适应性非常的差
    # 注意,向isinstance()这种函数,在开发中一般是不会使用的!
    def say_hello_2(obj):
        # 做类型检查
        if isinstance(obj , A):
            print('你好 %s'%obj.name)
    # say_hello(b)
    # say_hello_2(b)
    
    # 鸭子类型
    # 如果一个东西,走路像鸭子,叫声像鸭子,那么它就是鸭子
    
    # len()
    # 之所以一个对象能通过len()来获取长度,是因为对象中具有一个特殊方法__len__
    # 换句话说,只要对象中具有__len__特殊方法,就可以通过len()来获取它的长度
    l = [1,2,3]
    s = 'hello'
    
    # print(len(l))
    # print(len(s))
    print(len(b))
    print(len(c))
    
    # 面向对象的三大特征:
    #   封装
    #       - 确保对象中的数据安全
    #   继承
    #       - 保证了对象的可扩展性
    #   多态
    #       - 保证了程序的灵活性
    

    类中的属性和方法

    # 定义一个类
    class A(object):
    
        # 类属性
        # 实例属性
        # 类方法
        # 实例方法
        # 静态方法
    
        # 类属性,直接在类中定义的属性是类属性
        #   类属性可以通过类或类的实例访问到
        #   但是类属性只能通过类对象来修改,无法通过实例对象修改
        count = 0
    
        def __init__(self):
            # 实例属性,通过实例对象添加的属性属于实例属性
            #   实例属性只能通过实例对象来访问和修改,类对象无法访问修改
            self.name = '孙悟空'
    
        # 实例方法
        #   在类中定义,以self为第一个参数的方法都是实例方法
        #   实例方法在调用时,Python会将调用对象作为self传入  
        #   实例方法可以通过实例和类去调用
        #       当通过实例调用时,会自动将当前调用对象作为self传入
        #       当通过类调用时,不会自动传递self,此时我们必须手动传递self
        def test(self):
            print('这是test方法~~~ ' , self)
    
        # 类方法
        # 在类内部使用 @classmethod 来修饰的方法属于类方法
        # 类方法的第一个参数是cls,也会被自动传递,cls就是当前的类对象
        #   类方法和实例方法的区别,实例方法的第一个参数是self,而类方法的第一个参数是cls
        #   类方法可以通过类去调用,也可以通过实例调用,没有区别
        @classmethod
        def test_2(cls):
            print('这是test_2方法,他是一个类方法~~~ ',cls)
            print(cls.count)
    
        # 静态方法
        # 在类中使用 @staticmethod 来修饰的方法属于静态方法  
        # 静态方法不需要指定任何的默认参数,静态方法可以通过类和实例去调用  
        # 静态方法,基本上是一个和当前类无关的方法,它只是一个保存到当前类中的函数
        # 静态方法一般都是一些工具方法,和当前类无关
        @staticmethod
        def test_3():
            print('test_3执行了~~~')
    
    
    a = A()
    # 实例属性,通过实例对象添加的属性属于实例属性
    # a.count = 10
    # A.count = 100
    # print('A ,',A.count)
    # print('a ,',a.count)
    # print('A ,',A.name)
    # print('a ,',a.name)
    
    # a.test() 等价于 A.test(a)
    
    # A.test_2() 等价于 a.test_2()
    
    A.test_3()
    a.test_3()
    

    垃圾回收

    # 就像我们生活中会产生垃圾一样,程序在运行过程当中也会产生垃圾
    # 程序运行过程中产生的垃圾会影响到程序的运行的运行性能,所以这些垃圾必须被及时清理
    # 没用的东西就是垃圾
    # 在程序中没有被引用的对象就是垃圾,这种垃圾对象过多以后会影响到程序的运行的性能
    #   所以我们必须进行及时的垃圾回收,所谓的垃圾回收就是讲垃圾对象从内存中删除
    # 在Python中有自动的垃圾回收机制,它会自动将这些没有被引用的对象删除,
    #   所以我们不用手动处理垃圾回收
    
    class A:
        def __init__(self):
            self.name = 'A类'
    
        # del是一个特殊方法,它会在对象被垃圾回收前调用
        def __del__(self):
            print('A()对象被删除了~~~',self)
    
    a = A()
    b = a # 又使用一个变量b,来引用a对应的对象
    
    print(a.name)
    
    # a = None # 将a设置为了None,此时没有任何的变量对A()对象进行引用,它就是变成了垃圾
    # b = None
    # del a
    # del b
    

    特殊方法

    # 特殊方法,也称为魔术方法
    # 特殊方法都是使用__开头和结尾的
    # 特殊方法一般不需要我们手动调用,需要在一些特殊情况下自动执行
    
    # 定义一个Person类
    class Person(object):
        """人类"""
        def __init__(self, name , age):
            self.name = name
            self.age = age
    
        # __str__()这个特殊方法会在尝试将对象转换为字符串的时候调用
        # 它的作用可以用来指定对象转换为字符串的结果  (print函数)  
        def __str__(self):
            return 'Person [name=%s , age=%d]'%(self.name,self.age)
    
        # __repr__()这个特殊方法会在对当前对象使用repr()函数时调用
        # 它的作用是指定对象在 ‘交互模式’中直接输出的效果
        def __repr__(self):
            return 'Hello'
    
        # object.__add__(self, other)
        # object.__sub__(self, other)
        # object.__mul__(self, other)
        # object.__matmul__(self, other)
        # object.__truediv__(self, other)
        # object.__floordiv__(self, other)
        # object.__mod__(self, other)
        # object.__divmod__(self, other)
        # object.__pow__(self, other[, modulo])
        # object.__lshift__(self, other)
        # object.__rshift__(self, other)
        # object.__and__(self, other)
        # object.__xor__(self, other)
        # object.__or__(self, other)
    
        # object.__lt__(self, other) 小于 <
        # object.__le__(self, other) 小于等于 <=
        # object.__eq__(self, other) 等于 ==
        # object.__ne__(self, other) 不等于 !=
        # object.__gt__(self, other) 大于 >
        # object.__ge__(self, other) 大于等于 >=
    
        # __len__()获取对象的长度
    
        # object.__bool__(self)
        # 可以通过bool来指定对象转换为布尔值的情况
        def __bool__(self):
            return self.age > 17
    
        # __gt__会在对象做大于比较的时候调用,该方法的返回值将会作为比较的结果
        # 他需要两个参数,一个self表示当前对象,other表示和当前对象比较的对象
        # self > other
        def __gt__(self , other):
            return self.age > other.age
    
    
    # 创建两个Person类的实例
    p1 = Person('孙悟空',18)
    p2 = Person('猪八戒',28)
    
    # 打印p1
    # 当我们打印一个对象时,实际上打印的是对象的中特殊方法 __str__()的返回值
    # print(p1) # <__main__.Person object at 0x04E95090>
    # print(p1)
    # print(p2)
    
    # print(repr(p1))
    
    # t = 1,2,3
    # print(t) # (1, 2, 3)
    
    # print(p1 > p2)
    # print(p2 > p1)
    
    # print(bool(p1))
    
    # if p1 :
    #     print(p1.name,'已经成年了')
    # else :
    #     print(p1.name,'还未成年了')
    

    模块

    # 模块(module)
    # 模块化,模块化指将一个完整的程序分解为一个一个小的模块
    #   通过将模块组合,来搭建出一个完整的程序
    # 不采用模块化,统一将所有的代码编写到一个文件中
    # 采用模块化,将程序分别编写到多个文件中
    #   模块化的有点:
    #       ① 方便开发
    #       ② 方便维护
    #       ③ 模块可以复用!
    
    # 在Python中一个py文件就是一个模块,要想创建模块,实际上就是创建一个python文件
    # 注意:模块名要符号标识符的规范
    
    # 在一个模块中引入外部模块
    # ① import 模块名 (模块名,就是python文件的名字,注意不要py)
    # ② import 模块名 as 模块别名
    #   - 可以引入同一个模块多次,但是模块的实例只会创建一个
    #   - import可以在程序的任意位置调用,但是一般情况下,import语句都会统一写在程序的开头
    #   - 在每一个模块内部都有一个__name__属性,通过这个属性可以获取到模块的名字
    #   - __name__属性值为 __main__的模块是主模块,一个程序中只会有一个主模块
    #       主模块就是我们直接通过 python 执行的模块
    import test_module as test
    
    # print(test.__name__)
    print(__name__)
    

    m.py

    # 可以在模块中定义变量,在模块中定义的变量,在引入模块后,就可以直接使用了
    a = 10
    b = 20
    
    # 添加了_的变量,只能在模块内部访问,在通过import * 引入时,不会引入_开头的变量
    _c = 30
    
    # 可以在模块中定义函数,同样可以通过模块访问到
    def test():
        print('test')
    
    def test2():
        print('test2')
    
    # 也可以定义类
    class Person:
        def __init__(self):
            self.name = '孙悟空'
    
    # 编写测试代码,这部分代码,只要当当前文件作为主模块的时候才需要执行
    #   而当模块被其他模块引入时,不需要执行的,此时我们就必须要检查当前模块是否是主模块  
    if __name__ == '__main__':
        test()
        test2()
        p = Person()
        print(p.name)
    
    # import m
    
    # # 访问模块中的变量:模块名.变量名
    # # print(m.a , m.b)
    
    # # m.test2()
    
    # p = m.Person()
    
    # print(p.name)
    
    def test2():
        print('这是主模块中的test2')
    
    
    # 也可以只引入模块中的部分内容
    # 语法 from 模块名 import 变量,变量....
    # from m import Person
    # from m import test
    # from m import Person,test
    # from m import * # 引入到模块中所有内容,一般不会使用
    # p1 = Person()
    # print(p1)
    # test()
    # test2()
    
    # 也可以为引入的变量使用别名
    # 语法:from 模块名 import 变量 as 别名
    # from m import test2 as new_test2
    
    # test2()
    # new_test2()
    
    from m import *
    # print(_c)
    
    # import xxx
    # import xxx as yyy
    # from xxx import yyy , zzz , fff
    # from xxx import *
    # from xxx import yyy as zz
    

    图片

    # 包 Package
    # 包也是一个模块
    # 当我们模块中代码过多时,或者一个模块需要被分解为多个模块时,这时就需要使用到包
    # 普通的模块就是一个py文件,而包是一个文件夹
    #   包中必须要一个一个 __init__.py 这个文件,这个文件中可以包含有包中的主要内容
    from hello import a , b
    
    print(a.c)
    print(b.d)
    
    # __pycache__ 是模块的缓存文件
    # py代码在执行前,需要被解析器先转换为机器码,然后再执行
    #   所以我们在使用模块(包)时,也需要将模块的代码先转换为机器码然后再交由计算机执行
    #   而为了提高程序运行的性能,python会在编译过一次以后,将代码保存到一个缓存文件中
    #   这样在下次加载这个模块(包)时,就可以不再重新编译而是直接加载缓存中编译好的代码即可
    

    python 标准库

    # 开箱即用
    # 为了实现开箱即用的思想,Python中为我们提供了一个模块的标准库
    # 在这个标准库中,有很多很强大的模块我们可以直接使用,
    #   并且标准库会随Python的安装一同安装
    # sys模块,它里面提供了一些变量和函数,使我们可以获取到Python解析器的信息
    #   或者通过函数来操作Python解析器
    # 引入sys模块
    import sys
    
    # pprint 模块它给我们提供了一个方法 pprint() 该方法可以用来对打印的数据做简单的格式化
    import pprint
    
    # sys.argv
    # 获取执行代码时,命令行中所包含的参数
    # 该属性是一个列表,列表中保存了当前命令的所有参数
    # print(sys.argv)
    
    # sys.modules
    # 获取当前程序中引入的所有模块
    # modules是一个字典,字典的key是模块的名字,字典的value是模块对象
    # pprint.pprint(sys.modules)
    
    # sys.path
    # 他是一个列表,列表中保存的是模块的搜索路径
    # ['C:\Users\lilichao\Desktop\resource\course\lesson_06\code',
    # 'C:\dev\python\python36\python36.zip',
    # 'C:\dev\python\python36\DLLs',
    # 'C:\dev\python\python36\lib',
    # 'C:\dev\python\python36',
    # 'C:\dev\python\python36\lib\site-packages']
    # pprint.pprint(sys.path)
    
    # sys.platform
    # 表示当前Python运行的平台
    # print(sys.platform)
    
    # sys.exit()
    # 函数用来退出程序
    # sys.exit('程序出现异常,结束!')
    # print('hello')
    
    # os 模块让我们可以对操作系统进行访问
    import os
    
    # os.environ
    # 通过这个属性可以获取到系统的环境变量
    # pprint.pprint(os.environ['path'])
    
    # os.system()
    # 可以用来执行操作系统的名字
    # os.system('dir')
    os.system('notepad')
    

    异常和文件

    异常

    • 程序在运行过程当中,不可避免的会出现一些错误,比如:
      • 使用了没有赋值过的变量
      • 使用了不存在的索引
      • 除0
      • ...
    • 这些错误在程序中,我们称其为异常。
    • 程序运行过程中,一旦出现异常将会导致程序立即终止,异常以后的代码全部都不会执行!

    处理异常

    程序运行时出现异常,目的并不是让我们的程序直接终止!

    Python是希望在出现异常时,我们可以编写代码来对异常进行处理!

    try:
        代码块(可能出现错误的语句)
    except 异常类型 as 异常名:
        代码块(出现错误以后的处理方式)
    else:
        代码块(没出错时要执行的语句)
    finally:
        代码块(该代码块总会执行)
    
    • try 是必须的 else 语句有没有都行
    • except 和 finally 至少有一个
    • 可以将可能出错的代码放入到 try 语句,这样如果代码没有错误,则会正常执行,如果出现错误,则会执行 expect 子句中的代码,这样我们就可以通过代码来处理异常,避免因为一个异常导致整个程序的终止

    异常的传播(抛出异常)

    • 当在函数中出现异常时,如果在函数中对异常进行了处理,则异常不会再继续传播,
      • 如果函数中没有对异常进行处理,则异常会继续向函数调用处传播,
      • 如果函数调用处处理了异常,则不再传播,如果没有处理则继续向调用处传播
      • 直到传递到全局作用域(主模块)如果依然没有处理,则程序终止,并且显示异常信息
    • 当程序运行过程中出现异常以后,所有的异常信息会被保存一个专门的异常对象中
      • 而异常传播时,实际上就是异常对象抛给了调用处
      • 比如:ZeroDivisionError 类的对象专门用来表示除 0 的异常
        • NameError 类的对象专门用来处理变量错误的异常
        • ....
    • 在Python为我们提供了多个异常对象
    print('异常出现前')
    l = []
    try:
        # print(c)
        # l[10]
        # 1 + 'hello'
        print(10/0)
    except NameError:
        # 如果except后不跟任何的内容,则此时它会捕获到所有的异常
        # 如果在except后跟着一个异常的类型,那么此时它只会捕获该类型的异常
        print('出现 NameError 异常')
    except ZeroDivisionError:
        print('出现 ZeroDivisionError 异常')
    except IndexError:
        print('出现 IndexError 异常')
    # Exception 是所有异常类的父类,所以如果except后跟的是Exception,他也会捕获到所有的异常
    # 可以在异常类后边跟着一个 as xx 此时xx就是异常对象
    except Exception as e :
        print('未知异常',e,type(e))
    finally :
        print('无论是否出现异常,该子句都会执行')
    
    print('异常出现后')
    

    抛出异常

    可以使用 raise 语句来抛出异常,raise 语句后需要跟一个 异常类异常的实例

    # 也可以自定义异常类,只需要创建一个类继承Exception即可
    class MyError(Exception):
        pass
    
    def add(a,b):
        # 如果a和b中有负数,就向调用处抛出异常
        if a < 0 or b < 0:
            # raise用于向外部抛出异常,后边可以跟一个异常类,或异常类的实例
            # raise Exception
            # 抛出异常的目的,告诉调用者这里调用时出现问题,希望你自己处理一下
            # raise Exception('两个参数中不能有负数!')  
            raise MyError('自定义的异常')
    
            # 也可以通过if else来代替异常的处理
            # return None
        r = a + b
        return r
    
    print(add(-123,456))
    

    文件(File)

    • 通过 Python 程序来对计算机中的各种文件进行增删改查的操作
    • I/O(Input / Output)
    • 操作文件的步骤:
      • 打开文件
      • 对文件进行各种操作(读、写),然后保存
      • 关闭文件

    打开文件

    # open(file, mode='r', buffering=-1, encoding_=None, errors=None, newline=None, closefd=True, opener=None)
    # 使用open函数来打开一个文件
    # 参数:
    #   file 要打开的文件的名字(路径)
    # 返回值:
    #   返回一个对象,这个对象就代表了当前打开的文件
    
    # 创建一个变量,来保存文件的名字
    # 如果目标文件和当前文件在同一级目录下,则直接使用文件名即可
    file_name = 'demo.txt'
    
    # 在windows系统使用路径时,可以使用/来代替 
    # 或者可以使用 \ 来代替 
    # 或者也可以使用原始字符串
    file_name = 'hello\demo.txt'
    file_name = r'hellodemo.txt'
    
    # 表示路径,可以使用..来返回一级目录
    file_name = '../hello/demo.txt'
    
    # 如果目标文件距离当前文件比较远,此时可以使用绝对路径
    # 绝对路径应该从磁盘的根目录开始书写
    file_name = r'C:UserslilichaoDesktophello.txt'
    
    # file_obj = open(file_name) # 打开 file_name 对应的文件
    
    # print(file_obj)
    

    关闭文件

    # 打开文件
    file_name = 'demo.txt'
    
    # 调用open()来打开文件
    # file_obj = open(file_name)
    
    # # 当我们获取了文件对象以后,所有的对文件的操作都应该通过对象来进行
    # # 读取文件中的内容
    # # read()方法,用来读取文件中的内容,它会将内容全部保存为一个字符串返回
    # content = file_obj.read()
    
    # print(content)
    
    # # 关闭文件
    # # 调用close()方法来关闭文件
    # file_obj.close()
    
    # with ... as 语句
    # with open(file_name) as file_obj :
    #     # 在with语句中可以直接使用file_obj来做文件操作
    #     # 此时这个文件只能在with中使用,一旦with结束则文件会自动close()
    #     print(file_obj.read())
    
    
    file_name = 'hello'
    
    try:
        with open(file_name) as file_obj :
            print(file_obj.read())
    except FileNotFoundError:
        print(f'{file_name} 文件不存在~~')
    

    文件的读取

    file_name = 'demo2.txt'
    
    try:
        # 调用open()来打开一个文件,可以将文件分成两种类型
        # 一种,是纯文本文件(使用utf-8等编码编写的文本文件)
        # 一种,是二进制文件(图片、mp3、ppt等这些文件)
        # open()打开文件时,默认是以文本文件的形式打开的,但是open()默认的编码为None
        #   所以处理文本文件时,必须要指定文件的编码
        with open(file_name,encoding='utf-8') as file_obj:
            # 通过 read() 来读取文件中的内容
            # 如果直接调用read()它会将文本文件的所有内容全部都读取出来
            #   如果要读取的文件较大的话,会一次性将文件的内容加载到内存中,容易导致内存泄漏
            #   所以对于较大的文件,不要直接调用read()
            # help(file_obj.read)
            # read()可以接收一个size作为参数,该参数用来指定要读取的字符的数量
            #   默认值为-1,它会读取文件中的所有字符
            #   可以为size指定一个值,这样read()会读取指定数量的字符,
            #       每一次读取都是从上次读取到位置开始读取的
            #       如果字符的数量小于size,则会读取剩余所有的
            #       如果已经读取到了文件的最后了,则会返回''空串
            # content = file_obj.read(-1)
            content = file_obj.read(6)
            content = file_obj.read(6)
            content = file_obj.read(6)
            content = file_obj.read(6)
            # print(content)
            # print(len(content))
    except FileNotFoundError :
        print(f'{file_name} 这个文件不存在!')
    
    # 读取大文件的方式
    file_name = 'demo.txt'
    
    try:
        with open(file_name,encoding='utf-8') as file_obj:
            # 定义一个变量,来保存文件的内容
            file_content = ''
            # 定义一个变量,来指定每次读取的大小
            chunk = 100
            # 创建一个循环来读取文件内容
            while True:
                # 读取chunk大小的内容
                content = file_obj.read(chunk)
    
                # 检查是否读取到了内容
                if not content:
                    # 内容读取完毕,退出循环
                    break
    
                # 输出内容
                # print(content,end='')
                file_content += content
    
    except FileNotFoundError :
        print(f'{file_name} 这个文件不存在!')
    
    print(file_content)
    
    import pprint
    import os
    file_name = 'demo.txt'
    
    with open(file_name , encoding='utf-8') as file_obj:
        # readline()
        # 该方法可以用来读取一行内容
        # print(file_obj.readline(),end='')
        # print(file_obj.readline())
        # print(file_obj.readline())
    
        # readlines()
        # 该方法用于一行一行的读取内容,它会一次性将读取到的内容封装到一个列表中返回
        # r = file_obj.readlines()
        # pprint.pprint(r[0])
        # pprint.pprint(r[1])
        # pprint.pprint(r[2])
    
        for t in file_obj:
            print(t)
    

    文件的写入

    file_name = 'demo5.txt'
    
    # 使用open()打开文件时必须要指定打开文件所要做的操作(读、写、追加)
    # 如果不指定操作类型,则默认是 读取文件 , 而读取文件时是不能向文件中写入的
    # r 表示只读的
    # w 表示是可写的,使用w来写入文件时,如果文件不存在会创建文件,如果文件存在则会截断文件
    #   截断文件指删除原来文件中的所有内容
    # a 表示追加内容,如果文件不存在会创建文件,如果文件存在则会向文件中追加内容
    # x 用来新建文件,如果文件不存在则创建,存在则报错
    # + 为操作符增加功能
    #   r+ 即可读又可写,文件不存在会报错
    #   w+
    #   a+
    # with open(file_name , 'w' , encoding='utf-8') as file_obj:
    # with open(file_name , 'r+' , encoding='utf-8') as file_obj:
    with open(file_name , 'x' , encoding='utf-8') as file_obj:
        # write()来向文件中写入内容,
        # 如果操作的是一个文本文件的话,则write()需要传递一个字符串作为参数
        # 该方法会可以分多次向文件中写入内容
        # 写入完成以后,该方法会返回写入的字符的个数
        file_obj.write('aaa
    ')
        file_obj.write('bbb
    ')
        file_obj.write('ccc
    ')
        r = file_obj.write(str(123)+'123123
    ')
        r = file_obj.write('今天天气真不错')
        print(r)
    
    file_name = 'c:/Users/lilichao/Desktop/告白气球.flac'
    
    # 读取模式
    # t 读取文本文件(默认值)
    # b 读取二进制文件
    
    with open(file_name , 'rb') as file_obj:
        # 读取文本文件时,size是以字符为单位的
        # 读取二进制文件时,size是以字节为单位
        # print(file_obj.read(100))
    
        # 将读取到的内容写出来
        # 定义一个新的文件
        new_name = 'aa.flac'
    
        with open(new_name , 'wb') as new_obj:
    
            # 定义每次读取的大小
            chunk = 1024 * 100
    
            while True :
                # 从已有的对象中读取数据
                content = file_obj.read(chunk)
    
                # 内容读取完毕,终止循环
                if not content :
                    break
    
                # 将读取到的数据写入到新对象中
                new_obj.write(content)
    

    读取文件的位置

    # with open('demo.txt','rb') as file_obj:
    #     # print(file_obj.read(100))
    #     # print(file_obj.read(30))
    
    #     # seek() 可以修改当前读取的位置
    #     file_obj.seek(55)
    #     file_obj.seek(80,0)
    #     file_obj.seek(70,1)
    #     file_obj.seek(-10,2)
    #     # seek()需要两个参数
    #     #   第一个 是要切换到的位置
    #     #   第二个 计算位置方式
    #     #       可选值:
    #     #           0 从头计算,默认值
    #     #           1 从当前位置计算
    #     #           2 从最后位置开始计算
    
    #     print(file_obj.read())
    
    #     # tell() 方法用来查看当前读取的位置
    #     print('当前读取到了 -->',file_obj.tell())
    
    with open('demo2.txt','rt' , encoding='utf-8') as file_obj:
        # print(file_obj.read(100))
        # print(file_obj.read(30))
    
        # seek() 可以修改当前读取的位置
        file_obj.seek(9)
        # seek()需要两个参数
        #   第一个 是要切换到的位置
        #   第二个 计算位置方式
        #       可选值:
        #           0 从头计算,默认值
        #           1 从当前位置计算
        #           2 从最后位置开始计算
    
        print(file_obj.read())
    
        # tell() 方法用来查看当前读取的位置
        print('当前读取到了 -->',file_obj.tell())
    

    文件的其他操作

    import os
    from pprint import pprint
    
    # os.listdir() 获取指定目录的目录结构
    # 需要一个路径作为参数,会获取到该路径下的目录结构,默认路径为 . 当前目录
    # 该方法会返回一个列表,目录中的每一个文件(夹)的名字都是列表中的一个元素
    r = os.listdir()
    
    # os.getcwd() 获取当前所在的目录
    r = os.getcwd()
    
    # os.chdir() 切换当前所在的目录 作用相当于 cd
    # os.chdir('c:/')
    
    # r = os.getcwd()
    
    # 创建目录
    # os.mkdir("aaa") # 在当前目录下创建一个名字为 aaa 的目录
    
    # 删除目录
    # os.rmdir('abc')
    
    # open('aa.txt','w')
    # 删除文件
    # os.remove('aa.txt')
    
    # os.rename('旧名字','新名字') 可以对一个文件进行重命名,也可以用来移动一个文件
    # os.rename('aa.txt','bb.txt')
    os.rename('bb.txt','c:/users/lilichao/desktop/bb.txt')
    
    pprint(r)
    
    不一定每天 code well 但要每天 live well
  • 相关阅读:
    Proj THUDBFuzz Paper Reading: The Art, Science, and Engineering of Fuzzing: A Survey
    Proj THUDBFuzz Paper Reading: A systematic review of fuzzing based on machine learning techniques
    9.3 付费代理的使用
    11.1 Charles 的使用
    第十一章 APP 的爬取
    10.2 Cookies 池的搭建
    10.1 模拟登录并爬取 GitHub
    11.5 Appium 爬取微信朋友圈
    11.4 Appium 的基本使用
    11.3 mitmdump 爬取 “得到” App 电子书信息
  • 原文地址:https://www.cnblogs.com/geekfx/p/13733158.html
Copyright © 2011-2022 走看看