• python知识点


    1. python基础

    1.1 字符串

    1.1.1格式化:

    % 用来格式化字符串,在字符串内部,

    1. %s表示用字符串替换
    2. %d表示用整数替代
    3. %f表示浮点数
    4. %06d的,表示输出的整数显示位数,不足以0补充,超出当前位数则原样输出
    5. %.2f,表示小数点后显示的小数位数

    format():它会用传入的参数依次替换字符串内的占位符{0},{1}

    注:可迭代的对象

    print ('%d %s cost me $%.2f.' %(2, 'books', 21.227))
    
    "{} {}".format("hello", "world")    # 不设置指定位置,按默认顺序
    'hello world'
     
    "{0} {1}".format("hello", "world")  # 设置指定位置
    'hello world'
     
    "{1} {0} {1}".format("hello", "world")  # 设置指定位置
    'world hello world' 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    1.1.2 常用的操作

    替换replace()、删除、截取、赋值、连接、比较、查找、分割split()等

    1. str.replace(旧子串,新子串,替换次数)
    2. capitalize():将字符串第一个字符转换为大写,其他字符全部转化为小写
    3. title():将字符串每个单词的首字母转换为大写
    4. lower():将字符串中的大写转小写
    5. upper():将字符串中小写转大写
    6. ljust(): 返回一个原字符串左对齐,并使用指定字符串(默认为空格)填充至对应长度的新字符串
    7. str.startswith(子串,开始位置下标,结束位置下标)
    8. isalpha() :如果字符串至少有一个字符并且所有字符都是字母则返回True
    9. isdigit():如果字符串只包含数字则返回True
    10. isalnum(): 如果字符串至少有一个字符并且所有字符都是字母或数字则返回True
    # 1. 去除空格
    str.strip()
    # 2. 连接字符串  +
    'love'+'lazy'
    
    ','.join(list)
    
    # 3. 查找字符串 index 和find,区别find查找时变会返回-1,不影响程序执行
    str.index('c',0,-1)
    str.find('c')
    # rfind 和find功能相同,但查找方向为右侧开始
    # 4.比较字符串
    str.cmp()
    # 5. 是否包含指定字符串 in  not in
    a='hello word'
    print('hello' in a)
    
    # 6. 字符串长度 len(str) 或 str.len
    # 7. 大小写 str.lower() str.upper()
    # 8. 将字符串放入中间位置,可指定长度以及两边的字符str.center()
    s='hello world'
    print(s.center(40,'*'))
    # 9.字符串统计 str.count()
    s='hello world'
    print(s.count('o'))
    # 10. 字符串切片
    str[::]
    # 11 分割函数,partition()分割三部分
    s='alex sb alex'
    print(s.partition('sb'))
    
    # 12. 返回指定长度的字符串,原字符串右对齐
    str.zfill(11)
    mystr="hello"
    mystr.ljust(10,'.')    # 'hello.....' 
    
    # 结束符
    print("输出的内容",end="\n") # print默认为换行符
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    1.2 list 和tuple

    1.2.1 list常用操作:

    生成、添加元素append,访问(enumerate()同时输出索引值和元素内容)、删除、排序、切片、乘等

    1. len(list),max(list)
    2. list(seq) 将元组转换为列表
    3. tuple(seq):将列表转换为元祖
    4. list.count(obj)

    元组在只包含一个元素时,tuple=(2,) 加’,'消除歧义

    #创建list
    list=[i for i in range(10)]
    
    # 列表去重
    my_list=[3,2,1,1,2,3]
    unique_list=list(set(my_list))
    
    from collections import OrderedDict
    unique_list=list(OrderedDict.fromkeys(my_list))  #去重的同是保留list中的顺序
    print(unique_list)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    1.2.2 list 当作参数时的注意点

    def f(x,li=[]):
        print(id(li))
        for i in range(x):
            li.append(i*i)
        print(li)
    # 定义函数时,会保存函数中默认参数list的值,也就是列表li=[],当两次调用时都采用默认参数时,就会在原来的基础上append追加值。
    f(4)
    f(5)
    
    # 优化
    def f(x,li=[]):
        if not li:      
            li=[]
        for i in range(x):
            li.append(x**2)
        print(li)
    
    # list 函数的copy,python变量名相当于标签名,list2=list1,直接赋值,实质上指向的是同一个内存值。任何一个变量(list1 or list2)发生改变,都会影响另外一个。
    
    list1=[1,2,3,4,5,6]
    list2=list1
    list3=list1[:]
    print(id(list1))
    print(id(list2))           # list2 是 list1的视图,指向同一个内存值
    print(id(list3))          # list切片产生新的lis
    
    """
    Python中赋值语句不复制对象,而是在目标和对象之间创建绑定关系。对于自身可变或者包含可变项的集合对象,开发者有时会需要生成其副本用于改变操作,进而避免改变原对象。copy 模块提供了通用的浅层复制 copy() 和深层复制 deepcopy() 操作。
    
    1. copy() 仅复制对象本身,而不对其中的子对象进行复制,如果对原子对象进行修改,那么浅层复制之后的对象也会随着修改。
    2. deepcopy() 是真正意义上的复制,即重新开辟一片空间,经常说的复制实际上就是 deepcopy,深层复制之后的对象不受原对象的影响,无论原对象发生什么修改,深层复制的对象都不会发生改变。
    """
    
    import copy
    list1 = [1, 2, [3, 4], 5]
    list2 = copy.copy(list1)
    list3 = copy.deepcopy(list1)
    list2 == list3
    list2 is list3
    
    # array 数组切片,赋值,实际指向同一个内存值,任意修改其中的一个变量,其他变量值都会被修改
    import numpy as np
    array1=np.array([1,2,3,4])
    array2=array1
    array3=array1[:]
    
    # 生成新的array
    array5 = array1.copy() # 对原始的array1的复制
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    1.2.3 运算符

    1. “ * ” 复制 print(‘_’*10)
    2. “+ ” 合并
    #添加元素
    list.append() # 尾部添加
    list.insert(index,object)      # 指定位置新增数据
    #两个list的合并extend 、'+' ,列表结尾追加数据,如果数据是一个序列,则将这个序列的数据逐一添加到列表
    list1.extend(list2)
    list1+list2
    
    #删除元素 remove和pop、 del
    
    
    # 重复列表 *
    l1=[1,2,3]
    print(l1*3)
    
    
    # 排序和反转
    
    list.reverse() #列表元素反转
    list.sort(cmp,key,reverse=False) #在原list上排序
    list2=sorted(list)
    
    # 元组
    #元组中的元素不能被修改,但可以对元组进行连接组合,‘+’和'*'操作
    tup1+tup2
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    1.3 dict 字典和 set集合

    1. items返回dict的(健,值)tuple的一个列表
    2. keys() 返回dict的健列表
    3. values()返回dict的值列表

    创建集合使用{}set(),但是如果要创建空集合只能使用set(),因为{}用来创建空字典

    1.3.1 常见集合操作

    1. add() 增加数据;
    2. update() 追加的数据是序列,例如,列表,集合,字符串(会依次添加每个字符)
    3. remove()删除集合中的指定数据,如果数据不存在则报错
    4. discard() 删除集合中指定数据,如果数据不存在也不会报错
    5. pop() 随机删除集合中的某个数据,并返回这个数据
    6. in/not in 查找数据
    #set 并、交、差、异或,判断子集
    a | b
    a & b
    a - b
    a ^ b
    a.issubset(b)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    1.3.2 dict相关操作

    # 1. 添加元素
    dict[key]=value
    dict.setdefault(key,value)
    
    # 2. 删除指定健值对
    dict1={'a':1,'b':2}
    del dict1['a']
    # 清空字典
    dict1.clear()
    # 删除字典对象
    del dict1
    
    # 3. 字典的方法
    #get(key,default=None)
    dict1.get('d1','no')
    
    # has_key(key) 如果key出现dict中返回True
    dict1.has_key('a')
    
    # 4. 更新字典 update()
    dict1 = {'a': 1, 2: 'b', '3': [1, 2, 3]}
    dict2 = {4: 'new1', 5: 'news'}
    dict1.update(dict2)
    print (dict1)
    
    # 5. 将两个list合并成一个字典
    dict1={list1[i]:list2[i] for i in range(len(list1))}
    
    # 6. 提取字典中的目标数据
    count1={key:value for key,value in counts.items() if value >=200}
    
    # 7. 按照value进行排序
    d = {'a':1,'b':4,'c':2}
    字典是这个,然后要对字典按照value进行排序
    方法一:
    sorted(d.items(),key = lambda x:x[1],reverse = True)
    方法二:
    import operator
    sorted(d.items(),key = operator.itemgetter(1))
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    Python遍历嵌套字典列表,取出某些字段的值

    def traverse_take_field(data, fields, currentKey=None):
        """遍历嵌套字典列表,取出某些字段的值
        :param data: 嵌套字典列表
        :param fields: 列表,某些字段
        :param values: 返回的值
        :param currentKey: 当前的键值
        :return: 列表
        """
        if isinstance(data, list):
            for i in data:
                traverse_take_field(i, fields, currentKey)
        elif isinstance(data, dict):
            for key, value in data.items():
                traverse_take_field(value, fields, key)
        else:
            values.append(data)
            # if currentKey in fields:
            #     values.append(data)
    
    data = {"info": "2班成绩单",
            "grades": {
                "小明":
                    [{"chinese": 60}, {"math": 80}, {"english": 100}],
                "小红":
                    [{"chinese": 90}, {"math": 70}, {"english": 50}],
                "小蓝":
                    [{"chinese": 80}, {"math": 80}, {"english": 80}],
            },
            "newGrades": {
                "info": "新增数据",
                "newChinese": 77
            }}
    if __name__ == '__main__':
        values = []
        fields = ["chinese", "newChinese"]
        traverse_take_field(data, fields)
        print(values)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    1.4 zip函数

    将可迭代的对象作为参数,将对象中的元素打包成一个个元组,然后返回由这些元组组成的列表,如果各个迭代器中的元素个数不一致,则返回列表长度与最短的对象相同,利用* 号操作符,可以将元祖解压为列表zip(*zipped) 可以是list数组,也可以是zip函数返回的对象

    a=[1,2,3]
    b=[4,5,6]
    c=[4,5,6,7,8]
    zipped=zip(a,b)   #zip函数返回一个list对象,需要转换为list类型
    iterator=zip(*zipped)
    print(list(iterator))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    1.5 集合的推导式

    列表推导式、使用一句表达式构造一个新列表,可包括过滤、转换等操作。

    #列表推导式方法
    result2 = [i for i in range(10000) if i%2 == 0]
    
    # 嵌套列表推导式:按照嵌套顺序理解
    lists = [range(10), range(10, 20)]
    
    evens = [item for lst in lists for item in lst if item % 2 == 0]
    print(evens)
    
    # 字典推导式
    dict1 = {key : value for key, value in enumerate(reversed(range(10)))}
    print (dict1)
    
    # 集合推导式
    set1 = {i for i in range(10)}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2. 函数

    2.1 闭包

    实现一个可变参数的求和,通常这样定义

    def calc_sum(*args):
        ax=0
        for i in args:
            ax+=i
        return ax
    
    • 1
    • 2
    • 3
    • 4
    • 5

    如果不需要立即求和,而是在后面的代码中,根据需要在计算,可以不返回求和的结果,而是返回求和的函数

    def lazy_sum(*args):
        def sum():
            ax=0
            for i in args:
                ax+=i
            return ax
        return sum
    #当我们调用lazy_sum()时,返回的不是求和结果,而是求和的函数:
    f = lazy_sum(1,2,3,5,7)
    #调用函数f()时,才真正计算求和的结果
    print(f())
    
    """
    在这个函数lazy_sum()中又定义了sum,并且内部函数sum可以引用外部函数的参数和局部变量,当lazy_sum返回函数sum时,
    相关变量和参数都保存在返回的函数中,这种称为‘闭包’closure
    
    """
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    另外需要注意的问题,返回的函数并没有立即执行,而是知道调用了f()才执行

    注意:返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量

    def count():
        fs=[]
        for i in range(1,4):
            def f():
                return i*i
            fs.append(f)
        return fs
    f1,f2,f3=count()
    
    """
    上面的例子中,每次循环,都创建了一个新的函数,然后,把创建的3个函数都返回,但是返回的函数都是9,原因在于
    返回的函数引用了变量i,但它并没有立即执行,等到3个函数都返回时,他们所引用的变量已经变成了3,因此,最终结果为9
    
    """
    f1()
    #f2()
    #f3()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    #如果要引用循环变量,需要再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已经绑定到函数参数的值不变
    def count():
        def f(j):
            def g():
                return j*j
            return g
        fs=[]
        for i in range(1,4):
            fs.append(f(i))
        return fs
        
    f1,f2,f3=count()
    f1()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2.2 匿名函数

    当我们在传入函数时,有些时候,不需要显示的定义函数,直接传入匿名函数更方便,返回值就是该函数的表达式

    函数调用传参时,如果有位置参数时,位置参数必须在关键字参数(键=值)的前面,但关键字参数之间不存在先后顺序

    # lambda 参数列表:表达式
    
    str_lst = ['Welcome', 'to', 'Python', 'Data', 'Analysis', 'Course']
    str_lst.sort(key=lambda x:len(x)) # sort by length
    print (str_lst)
    
    str_lst.sort(key=lambda x:x[-1]) # sort by the last letter
    print (str_lst)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    注意:
    1. lambda 表达式的参数可有可无,函数的参数在lambda表达式中完全适用
    2. lambda 表达式能接收任何数量的参数但只能返回一个表达式的值

    fn=lambda:100
    fn1=lambda a,b,c=100:a+b+c
    fn2=lambda *args :args
    
    def sum_num(a,b,f):
        return f(a)+f(b)
    result=sum_num(-1,2,abs)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2.3 函数参数

    # 函数返回
    def divide(a,b):
        try:
            return a*1.0/b
        except ZeroDivisionError as e:
            print(e)
            #raise e
    print(divide(0,1))
    print(divide(1,0))
    
    
    # 正常使用函数默认参数
    #不推荐使用
    def gen_list(a=[],b=None):
        a.append(b)
        return a
    print (gen_list(b=2))
    print(gen_list(b=3))
    #导致函数默认值改变,多次调用相互影响,这里只是针对传递引用类型的参数,如果是数字、字符串等类型就不存在该问题
    
    # 推荐使用
    def gen_list(a=None,b=None):
        if a is None:
            a=[]
        a.append(b)
        return a
    print(gen_list(b=2))
    print(gen_list(b=3))
    
    
    
    # 全局变量:在函数内部修改全局变量的值,需要在函数内部加一条语句: global  变量
    
    a=100
    def func():
        global a
        a=200
    func()
    print(a)
    
    # 不定长参数:不定长参数也叫可变参数,用于不确定调用的时候会传递多少个参数(不传递也可)的场景,此时,可用包裹(packing)位置参数或者包裹关键字进行参数传递
    
    # 包裹位置传递 *args
    def user_info(*args):
        print(args)
        
    user_info('TOm',18)
    
    #关键字传递 **kwargs
    
    def user_info(**kwargs):
        print(kwargs)
    
    user_info(name="TOM",age="18")
    
    
    # 引用:在python中,值是靠引用传递来的,我们可以用id()来判断两个变量是否为同一个值的引用,我们可以将id值理解为那块内存的地址标识
    # int类型为不可变类型
    a=1
    b=a
    print(id(a))
    print(id(b))
    a=2
    #print(id(b))
    # 列表是可变类型
    aa=[10,20]
    bb=aa
    print(bb)
    aa.append([30,40])
    print(bb)
    
    # 递归, 特点:函数内部自己调用自己;必须有出口
    def sum_numbers(num):
        # 1.出口
        if num ==1:
            return 1
        # 2.当前数字+当前数字-1的累加和
        return num+sum_numbers(num-1)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79

    2.4多函数模

    # 处理字符串
    str_lst = ['$1.123', ' $1123.454', '$899.12312']
    
    def remove_space(str):
        str_no_space = str.replace(' ', '')
        return str_no_space
    
    def remove_dollar(str):
        """
            remove $
        """
        if '$' in str:
            return str.replace('$', '')
        else:
            return str
    
    def clean_str_lst(str_lst, operations):
        """
            clean string list
        """
        result = []
        for item in str_lst:
            for op in operations:
                item = op(item)
            result.append(item)
        return result
    
    clean_operations = [remove_space, remove_dollar]
    result = clean_str_lst(str_lst, clean_operations)
    print (result)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    2.5 异常处理

    """
    try:
        可能发生错误的代码
    except (异常类型):
        如果出现异常执行的代码
    
    """
    try:
        print(1/0)
    except:
        print('error')
    
    # 2. 捕获异常描述信息
    try:
        print(1/0)
    except ZeroDivisionErroe as result:       # except Exception as result:
        print(result)
        
    # 3. 异常的else
    
    try:
        print(1/0)
    except Exception as result:      
        print(result)
    else:
        print('我是else,是没有异常的时候执行的代码')
    
    # 4. 异常的finally
    try:
        f=open('text.txt','r')
    except Exception as result:
        f=open('text.txt','w')
    else:
        print('没有异常,我很开心')
    finally:
        f.close()                    # 表示无论是否有异常都要执行的代码
    
    
    
    # 自定义异常,在python中,抛出自定义异常的语法为raise异常对
    
    # 自定义异常类,继承Exception
    class ShortInputError(Exception):
        def __init__(self,length,min_len):
            self.length=length
            self.min_len=min_len
        #设置抛出异常的描述性息
        def __str__(self):
            return "输入的长度是%是,不能少于%s个字符串"%(self.length,self.min_len)
        
    def main():
        try:
            con=input('请输入密码:')
            if len(con) <3:
                raise ShortInputError(len(con),3)
        except Exception as result:
            print(result)
        else:
            print("密码输入完成")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    2.6 高阶函数map、filter、reduce

    • map():将函数依次作用到序列的每一个元素,map()在python3返回的是迭代器,不是list
    • reduce():把一个函数作用在一个序列上,reduce把结果继续和序列的下一个与元素做累积计算
    • filter():也接收一个函数和一个序列,和map()不同,filter把传入的函数依次作用在每个元素元素上,然后根据返回值是True还是False决定是保留还是丢弃该元素
    # map 函数
    a = [1,2,3];b = [2,3,4]
    c = list(map(lambda x,y:x+y,a,b))
    
    # filter 函数
    l=[x for x in range(0,10)]
    l=list(filter(lambda x : x%2==0,l))
    
    # reduce函数
    from functools import reduce
    str_lst = map(str, range(5)) # ['0', '1', ...]
    
    def make_num(str1, str2):
        return int(str1) * 10 + int(str2)
    
    result = reduce(make_num, str_lst)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2.7 迭代器

    • 定义:可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
    • 可迭代对象 Iterable,以直接作用于for 循环的数据类型有一下几种:
    1. 集合数据类型:list,tuple,dict,set,str
    2. generator ,包含生成器和带yieldgenerator function

    这些可以直接用于for循环的对象统称为可迭代对象:Iterable

    2.8 生成器

    生成器与列表生成式的本质区别就是:一个已经生成数据了,使用时,如果数据过大,会产生内存溢出,而生成器是只有循环时,才会生成数据

    #1.把一个列表生成式的[]改成(),就创建了一个generator
    g = (x * x for x in range(10))
        
    # 使用了yield的函数就是生成器   
    def fib(times): #打印斐波拉契数列钱times位。
        n=0
        a,b=0,1
        while n<times:
            yield b   #功能:每次执行到有yied的时候,会返回yield后面b的值给函数并且函数会暂停,直到下次调用或迭代终止。
            a,b=b,a+b    #再一次调用next方法时,程序从停止的地方开始执行
            n+=1
        return 'done'
    for i in fib(10):
        print(i)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2.9 装饰器

    """
    这里的deco函数就是装饰器,它的参数是一个函数,然后返回值也是一个函数。其中作为参数的这个函数f()就在返回函数wrapper的内部执行。
    然后在函数f()前面加上@deco,f()函数就相当于被注入了计时功能,现在只要调用f(),它就已经变身为“新的功能更多的函数”
    
    """
    
    import time
    def deco(f):
        def wrapper(a,b):
            start_time=time.time()
            f(a,b)
            end_time=time.time()
            execution_time=(end_time-start_time)*1000
            print("time is %d ms"%execution_time)
        return wrapper
    @deco
    def f(a,b):
        print('be on')
        time.sleep(1)
        print('result is %d'%(a+b))
    if __name__=='__main__':
        f(3,4)
    
    
    # 2. 无固定参数的装饰器
    def deco(f):
        def wrapper(*args, **kwargs):      #
            start_time = time.time()
            f(*args, **kwargs)
            end_time = time.time()
            execution_time= (end_time - start_time)*1000
            print("time is %d ms" % execution_time)
        return wrapper
    @deco
    def f(a,b):
        print("be on")
        time.sleep(1)
        print("result is %d" %(a+b))
    @deco
    def f2(a,b,c):
        print("be on")
        time.sleep(1)
        print("result is %d" %(a+b+c))
    
    
    if __name__ == '__main__':
        f2(3,4,5)
        f(3,4)
    
    
    # 3. 使用多个装饰器,装饰一个函数
    
    def deco01(f):
        def wrapper(*args, **kwargs):
            print("this is deco01")
            start_time = time.time()
            f(*args, **kwargs)
            end_time = time.time()
            execution_time = (end_time - start_time)*1000
            print("time is %d ms" % execution_time)
            print("deco01 end here")
        return wrapper
    def deco02(f):
        def wrapper(*args, **kwargs):
            print("this is deco02")
            f(*args, **kwargs)
    
            print("deco02 end here")
        return wrapper
    
    @deco01
    @deco02
    def f(a,b):
        print("be on")
        time.sleep(1)
        print("result is %d" %(a+b))
    if __name__ == '__main__':
        f(3,4)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79

    3. 内建模块

    3.1 datetime|time

    日期和时间的库

    # datetime模块下的datetime类
    from datetime import datetime
    
    • 1
    • 2

    3.2 hashlib

    摘要算法又称哈希算法、散列算法,它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)

    常用在:
    任何允许用户登录的网站都会储存用户登录的用户名和口令,此时,便可以将口令用摘要算法替代

    import hashlib
    md5=hashlib.md5()
    md5.update('how to use md5 in python hashlib?'.encode('utf-8'))
    print(md5.hexdigest())
    
    • 1
    • 2
    • 3
    • 4

    3.2 collections 模块

    包含了一些特殊的容器,针对Python内置的容器,例如list、dict、set和tuple,提供了另一种选择;

    • namedtuple,可以创建包含名称的tuple

    • deque,类似于list的容器,可以快速的在队列头部和尾部添加、删除元素;

    • Counterdict的子类,计算可hash的对象;

    • OrderedDictdict的子类,可以记住元素的添加顺序;

    • defaultdictdict的子类,可以调用提供默认值的函数;

    from collections import namedtuple,deque,Counter,defaultdict
    # namedtuple是继承自tuple的子类。namedtuple创建一个和tuple类似的对象,而且对象拥有可访问的属性。
    # 1. namedtuple 用来创建一个自定义的tuple对象,并且规定了tuple元素的个数,具备tuple的不变性,并可以用属性而不是索引来引用tuple的某个元素.
    
    
    from collections import  namedtuple
    
    User = namedtuple('User', ['name', 'age', 'gender'])
    u = User('villa', 33, 'male')
    print(u.name)
    print(u.age)
    print(u.gender)
    print(u)
    
    Point =namedtuple('Point',['x','y'])   # 第一个参数tuple_name, 第二个参数filter_name   返回值是类型,需要传参数
    """
    这里其实是创建了一个类,但是class类有比较复杂,便可以通过nametuple来简化创建。第一个参数为类名,后面的list为类的属性
    
    """
    p=Point(1,2)      # 指定之后,属性值不能更改
    print(p)
    print(isinstance(p,tuple))
    print(isinstance(p,Point))
    
    # 2. deque: 解决list线性插入和删除效率低的问题,deque是为了高效的实现插入和删除操作的双向列表,适合用于队列和栈
    
    q=deque([1,2,3,4])
    q.append(5)
    q.appendleft(0)
    q.pop()
    q.popleft()
    
    
    # 3. Counter: 简单的计数器,例如统计字符的出现次数
    c=Counter
    print(c('hello'))   # 可以是字符串,list
    
    
    # 4. OrderedDict: 使用dict时,key是无序的,在对dict做迭代时,我们无法确定key的顺序,可以使用OrderdDict保持key的顺序
    d=dict([('a',1),('aa',2),('c',3)])   #python中的字典是无序的,因为它是按照hash来存储的
    d['d']=4
    d['ff']=6
    d['ef']=5
    #先后顺序不保证
    for key,value in d.items():
        print(key,value)
    
    od=OrderedDict([('a',1),('b',2),('c',3)])   #OrderedDict 的key会按照插入的顺序排序,而不是key本身排序
    print(od)
    
    # 5. defaultdict: 使用dict时,如果引用的key不存在,就会抛出keyError,如果希望key不存在时,返回一个默认值,就可以使用defaultdict
    d=defaultdict(lambda:'N/A')
    d['key1']='abc'
    print(d['key1'])
    print(d['key2'])
    
    cnt={}
    for char in ["a",'b','c','b','d','a','a']:
        if char not in cnt:
            cnt[char]=0
        cnt[char]+=1
    print(cnt)
    # 方法二
    cnt=defaultdict(int)    # 指定类型int函数,int的默认值为0
    for char in ["a",'b','c','b','d','a','a']:
        cnt[char]+=1
    print(cnt)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    3.3 itertools

    提供了非常有用的用于操作可迭代对象的函数
    迭代器的特点是:惰性求值(Lazy evaluation),即只有当迭代至某个值时,它才会被计算,这个特点使得迭代器特别适合于遍历大文件或无限集合等,因为我们不用一次性将它们存储在内存中。

    itertools 模块提供的迭代器函数有以下几种类型:

    • 无限迭代器:生成一个无限序列,比如自然数序列 1, 2, 3, 4, …;
    • 有限迭代器:接收一个或多个序列(sequence)作为参数,进行组合、分组和过滤等;
    • 组合生成器:序列的排列、组合,求序列的笛卡儿积等;
    import itertools
    # 1. itertools 模块提供了三个函数(事实上,它们是类)用于生成一个无限序列迭代器:count(firstval=0, step=1)、cycle(iterable)、repeat(object [,times]
    
    nums =itertools.count(1) #自然序列
    
    # cycle 用于对iterable中的元素反复执行循环
    
    cycle_string=itertools.cycle('ABC')
    
    # repeat 用于反复生成一个object
    for item in itertools.repeat([1,2,3,4],3):
        print(item)
    
    # 2. 合并器:chain() 与 izip(),chain()函数接收n个可迭代对象,然后返回一个他们的合集的迭代器,纵向合并;izip()函数接收n个可迭代对象,然后将其合并成tuples,横向合并,功能类似zip(),只是返回的是iterator,而不是list。
    
    for i in itertools.chain([1,2,3],['a','b','c']): #chain() 可以把一组迭代对象串联起来,形成一个更大的迭代器
        print (i)
        
    
    for i, j in itertools.izip([1,2,3],['a','b','c']):
        print (i)
    
    # 3. 切分迭代器: islice(),函数接收一个迭代器,然后返回其切片,类似于list的slice切片操作。参数有start,stop和step,其中start和step参数时可选参数。
    
    
    # 4. Map迭代器,imap()函数对迭代器进行转换,类似于python内置的map()函数。下例把range(5)乘以2。
    print ("Multiples:")
    for i in itertools.imap(lambda x,y:(x, y, x*y), range(5),range(5,10)):
        print ('%d * %d = %d' % i)
    
    # groupby() 把迭代器中的相邻重复元素挑出来放一起
    for key,group in itertools.groupby('AAAABBBCCAAA'):
        print(key,list(group))
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    3.4 OS 操作文件和目录

    1. os.mkdir 创建目录
    2. os.rmdir 删除目录
    3. os.rename 重命名
    4. os.walk 遍历目录
    5. os.path.join 连接目录和文件名
    6. os.path.split 分割文件和文件名
    7. os.path.exists() 判断路径是否存在
    8. os.getcwd() 方法用于返回当前工作目录
    9. os.path.dirname():去掉脚本的文件名,返回目录os.path.dirname(os.path.realname(__ file__)):获得所引用模块所在的绝对路径,__ file __ 为内置属性
    10. os.remove() 删除文件
    11. os.path.isdir()
    12. os.path.isfile()
    13. os.system():system函数可以将字符串转化成命令在服务器上运行
    14. os.listdir() 获取目录列表
    # 常用实例
    
    import os
    # 全局变量
    cur_dir =os.getcwd()
    new_dir=os.path.join(cur_dir,'tmp')
    #判断new_dir是否存在,如何存在删除之后再创建,不存在,直接创建
    if not os.path.exists(new_dir):
        os.mkdir(new_dir)      # 删除一个目录 os.rmdir(filepath)
    else:
        os.rmdir(new_dir)
        os.mkdir(new_dir)
    # 创建tmp.log 文件并写入内容
    
    new_file=os.path.join(new_dir,'tmp.log')
    with open(new_file,'w') as f:
        f.write('test')
      
    # 查找d:\dir_temp目录下的所有文件,以绝对路径输出文件
    search_dir = 'd:\\dir_temp'
    for root, dirs, files in os.walk(search_dir):
        for name in files:
            print (os.path.join(root, name))
    
    # 操作文件和目录一部分在os模块中,一部分在os.path中
    os.path.abspath('.') # 查看当前目录的绝对路径
    
    path=os.path.join('path','newdir') # 在一个目录下创建一个新目录,首先把新目录的完整路径表示出来
    
    os.path.split('/Users/desktop/testdir/file.txt') # 把一个路径拆分两部分,后一部分总是最后级别的目录或文件名
    # /Users/desktop/testdir   + file.txt
    
    os.path.splitext() # 可以直接得到文件的扩展名
    # /Users/desktop/testdir/file     txt     返回的list 
    
    [x for x in os.listdir('.') if os.path.isdir(x)] # 列出当前目录下的所有目录
    
    [ x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1]=='.py']  # 列出所有的.py 文件
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    3.5 re 正则表达式

    1. re.match() 方法
    2. re.search() 方法 re.search扫描整个字符串并返回第一个成功的匹
    3. re.sub() 方法 用于替换字符串中的匹配
    4. re.compile() 方法
    5. re.finditer 作为迭代器返回
    # re.match 函数 尝试从字符串的起始位置匹配一个模块,如果不是起始位置匹配成功的话,match() 就会返回None,re.match(pattern,string,flags=0),flags: 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等
    # 使用group(num)获取匹配的表达式
    
    import re
    
    line="Cats are smarter than dogs"
    
    matchObj=re.match( r'(.*) are (.*?) .*',line ,re.M|re.I)
    
    if matchObj:
    	print("matchObj.group():" ,matchObj.group())
    	print("matchObj.group(1):" ,matchObj.group(1))
    	print("matchObj.group(2):" ,matchObj.group(2))
    
    # re.sub 
    phone="2004-959-559  # 这是一个国外电话号码"
    
    #删除注释
    
    num=re.sub(r"#.*","",phone)
    print("电话号码是:",num)
    
    #删除非数字的字符串
    
    num=re.sub(r'\D',"",phone)
    
    print("电话号码是:",num)
    
    
    # compile 函数用于编译正则表达式,生成一个正则表达式pattern,供match和search这两个函数使用,re.compile(pattern,flags),pattern:一个字符串形式的正则表达式,flags : 可选,表示匹配模式,比如忽略大小写,多行模式等,具体参数为:
    """
        1. re.I 忽略大小写
        2. re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
        3. re.M 多行模式
        4. re.S 即为 . 并且包括换行符在内的任意字符(. 不包括换行符)
        5. re.S 即为 . 并且包括换行符在内的任意字符(. 不包括换行符)
    """
     
    pattern =re.compile(r'\d+')
    
    m=pattern.match('one12twothree34four',2,10) # 从'e'的位置开始匹配,没有匹配
    
    # re.finditer 作为迭代器返回,在字符串中找到正则表达是所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表
    result= pattern.findall("runoob 123 google 456",0,10)
    print(result)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    3.6 sys模块

    1. sys.argv : 用来获取当前正在执行的命令行参数列表 sys.argv[0]: 是程序名,sys.argv[1] 是第一个参数,以此类推
    2. sys.exit(n)
    3. sys.path
    4. sys.stdin\stdout\stder
    # 1. sys.argv,实现从程序外部向程序传递参数。
    import sys
    
    # 获取脚本名称
    print('the name of this program is : %s ' % sys.argv[0])
    # 获取参数列表
    print('the command line argument are:')
    for i in sys.argv:
        print(i)
    # 统计参数的个数
    print(' there are %s arguments.'%(len(sys.argv)-1))
    
    for index, arg in enumerate(sys.argv):
        print("第%d个参数是: %s" % (index, arg))
    
    # 2. sys.exit([arg]),程序中间的退出,arg=0为正常退出。
    
    # 3. sys.path: 获取指定模块搜索路径的字符串集合,可以将写好的模块放在得到的某个路径下,就可以在程序中import时正确找到,当我们导入一个模块时:import  xxx,
    # 默认情况下python解析器会搜索当前目录、已安装的内置模块和第三方模块,搜索路径存放在sys模块的path中
    #对于模块和自己写的脚本不在同一个目录下,在脚本开头加sys.path.append('xxx')
    sys.path.append('引用模块的地址')  
    #不同目录下在a.py中导入b.py
    sys.path.append('b模块的绝对路径')
    
    import b
    
    # 4. sys.stdin
    #单行输入
    line=sys.stdin.readline().strip()   #获取输入的话,不要忘了去掉末尾的换行符,可以用strip( )函数
    
    # 直接使用文件作为整体的输入
    #for line in sys.stdin.readlines(): # 等效于 for line in sys.stdin:
    
    # 使用方法,将文件重定向到输入中去就可以很方便的使      python test.py  < 123.txt
    
    # 5. sys.stdout
    sys.stderr.write() #等效于 print() sys.stdout.write()和sys.stderr.write()均是向屏幕打印的语句
    
    
    import  time 
    import sys
    
    for  i in  range(5):
        print(i)
        sys.stdout.flush()
        time.sleep(1)
    
    # 这个脚本的本意是每个一秒输出一个数字,但如果把这句话sys.stdout.flush() 去除的话。就只能等到程序执行完毕,屏幕上才会一次性输出 0,1,2,3,4,
    
    
    # 6. flush() 方法是用来刷新缓冲区的,即将缓冲区中的数据立刻写入文件,同时清空缓冲区,不需要是被动的等待输出缓冲区写入。一般情况下,文件关闭后会自动刷新缓冲区,但有时你需要在关闭前刷新它,这时就可以使用 flush() 方法。
    f.flush()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    3.7 joblib

    Joblib是一个可以将Python代码转换为并行计算模式的包,可以大大简化我们写并行计算代码的步骤。我们可以通过操作该包内的函数来实现目标代码的并行计算,从而提高代码运行效率

    # 1. 首先,定义一个简单的函
    from joblib import Parallel ,delayed
    import time
    def single(a):
        time.sleep(1)
        print(a)
        return a 
    
    # 2. 使用for 循环运行10次,并记录时
    start=time.time()
    for i in range(10):
        single(i)
    Time=time.time()-start
    print(str(Time)+'s')
    
    # 3. 使用joblib库里面的Parallel函数及delayed函数来执行10次循环函数的操作,实现并行化处理。Parallel函数会创建一个进程池,以便在多进程中执行每一列表项。
    
    start = time.time()  # 记录开始的时间
    res=Parallel(n_jobs=3,verbose=1)(delayed(single)(i) for i in range(10))   # 并行化处理,    notebook 上函数中的print不打印
    # n_jobs: int, default: None —— 设置并行执行任务的最大数量。
    print(res)
    Time = time.time() - start  # 计算执行的时间
    print(str(Time)+'s')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    3.8 堆(heap)

    是一个可以被看成近似完全二叉树的数组。树上的每一个结点对应数组的一个元素。除了最底层外,该树是完全充满的,而且是从左到右填充。又被称为优先队列(priority queue),但不是队列,在堆中,是按照元素的优先级取出元素的。

    完全二叉树(complete binary tree)树的深度是log2

    默认为顶堆,对每一个元素取负,可以构造大顶堆

    left_son_id=father_id * 2

    right_son_id=father_id * 2+1

    father_id =son_id / 2

    import heapq
    # 1.heapq.heappush(heap,item)   heap为定义堆,item 增加的元素;并且item可以为元组类型,Python按元素对元组进行排序,确保要排序元组的对象排在第一位
    heap=[]
    heapq.heappush(heap, 2)
    
    # 2.heapq.heapify(list)        将列表转换为堆
    list=[5,8,0,3,6,7,9,1,4,2]
    heapq.heapify(list) 
    heapq.heappop(list)
    list
    
    # 3.heapq.heappop(heap)        删除最小的值
    heap=[2, 4, 3, 5, 7, 8, 9, 6]   # 默认为堆
    heapq.heappop(heap) 
    
    # 4.heapq.heapreplace(heap, item)     删除最小元素值,添加新的元素值
    heap=[2, 4, 3, 5, 7, 8, 9, 6]
    heapq.heapreplace(heap, 11)
    
    # 5.heapq.heappushpop(heap, item)     首判断添加元素值与堆的第一个元素值对比,如果大于则删除最小元素,然后添加新的元素值,否则不更改堆
    heap=[2, 4, 3, 5, 7, 8, 9, 6]
    heapq.heappushpop(heap, 9)
    
    # 6.heapq.merge(...)             将多个堆合
    
    # 7.heapq.nlargest (n, heap)     查询堆中的最大元素,n表示查询元素个数
    heap=[2, 3, 5, 6, 4, 8, 7, 9]
    heapq.nlargest (1, heap)
    
    # 8.heapq.nsmallest(n, heap)     #查询堆中的最小元素,n表示查询元素个数
    heap=[2, 3, 5, 6, 4, 8, 7, 9]
    heapq.nsmallest(2, heap)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    3.9 argparse

    argparse 是python内置的一个用于命令项生成选项与参数解析的模块,通过在程序中定义我们需要的参数,argparse将会从sys.argv中解析这些参数,并自动的生成帮助和使用信息
    三个步骤:

    • 创建ArgumentParser()对象

    • 调用add_argument()方法添加参数

    • 使用parse_args()解析添加的参数

    import argparse
    parser=argparse.ArgumentParser()
    parser.add_argument("dilename",default='text.txt')
    parser.add_argument('integer',type=int,help='display an integer')
    args=parser.parse_args()
    print(args.integer)
    
    # 基本框架
    import argparse
    
    def get_parser():
        parser=argparse.ArgumentParser(description="Demo of argparse")
        parser.add_argument('--name',default="word")    #default 表示命令行没有设置该参数的时候,程序中用什么值来替代
        
        return parser
    if __name__=="__main__":
        parser=get_parser()
        args=parser.parse_args()
        name=args.name
        print("Hello {}" .format(name))
    
    # 可选参数,"-"或"--" 开头定义的命令行参数,都属于可选参数,单个字母用- ,多个字母用 --   位置参数 :必须配置的参数
    
    parser = argparse.ArgumentParser()
    
    parser.add_argument("--square", help="display a square of a given number", type=int)
    parser.add_argument("--cubic", help="display a cubic of a given number", type=int)
    parser.add_argument("--arch",required=True,choices=['alexnet','vgg'])    # required:表示这个参数是否一定需要设置
    # choices :参数值只能从集合选项里面选择
    args = parser.parse_args()
    
    if args.square:
        print(args.square**2)
    
    if args.cubic:
        print(args.cubic**3)
    
    # 混合参数, 定位参数和选项参数可以混合使用,看下面一个例子,给一个整数序列,输出它们的和或最大值(默认):
    
    parser = argparse.ArgumentParser(description='Process some integers.')
    parser.add_argument('integers', metavar='N', type=int, nargs='+',
                       help='an integer for the accumulator')     #  nargs是用来说明传入的参数个数,'+' 表示传入至少一个参数
    parser.add_argument('--sum', dest='accumulate', action='store_const',
                       const=sum, default=max,
                       help='sum the integers (default: find the max)')
    
    args = parser.parse_args()
    print(args.accumulate(args.integers))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    3.10 IO文本读写

    # 1. 读文件
    filepath='./lucy.txt'
    with open(filepath,'r') as f:      #open函数打开文件   r:读
        print(f.read())      # ready一次性读取文件内容,把内容存放到内存中
        f.readline() # 每次读取一行内容
        f.readlines()  #一次读取全部内容并按行返回list 
    # r: 表示文本文件
    # rb:读取二进制文件,比如图像、视频
    
    # 实际开发中通常使用
    with open(filepath,'r') as f:
        for line in f:
            lst=line.strip().split()
    
    # 2. seek() 作用:用来移动文件指针 , 文件对象.seek(偏移量,起始位置)
    # 3. 写文件,同读文件,w:写入文本文件,wb:写入二进制文件
    with open(filepath,'w' ) as f:
        f.write('hello python')
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    3.11 pickle & json 字符串序列化

    我们把变量从内存中变成可储存或传输的过程称为序列化

    json:是文本序列化格式

    pickle:是二进制序列化格式(特定于python)

    # 序列化 pickle 模块
    #首先,把一个对象序列化并写入文件
    import pickle,json
    d=dict(name='bob',age=20,score=90)
    pickle.dumps(d)
    
    '''
    pickle.dumps() 方法把任意对象序列化成一个bytes,然后就可以把这个btypes 写入文件,或者用另一个方法pick.dump(d,f)直接序列化并写入
    
    '''
    
    # 使用pickle.load()直接反序列化出对象,完成从磁盘到内存
    with open(filepath,'rb') as f:
        d=pickle.dump(f)
        print(d)
    
    # JSON 如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准化格式,json格式就是一个字符串,可以被所有的语言读取
    
    # 把python对象变成一个json
    d=dict(name='bob',age=20,score=90)
    json.dumps(d)  # dumps()返回一个标准的dtr,内容是标准的json,可以使用dump直接写入文件
    fw.write(json.dumps(result)+"\n")    # 将json格式的字符串写入文件
    
    json.load() # json 反序列为 python 对象
    line=json.loads(t_json)  # 将对应的json字符串load下来,转化为正常格式
    
    data={"status": "OK", "count": 2, "results": [{"age": 27, "name": "Oz", "lactose_intolerant": 'true'}, {"age": 29, "name": "Joe", "lactose_intolerant": 'false'}]}
    print(json.dumps(data,indent=2))
    
    
    # json 进阶,对python 中的类进行序列
    
    class Student():
        def __init__(self,name,age,score):
            self.name=name
            self.age=age
            self.score=score
    s=Student('Bob',20,90)
    # json 无法直接对s实例对象进行json序列化,可选参数default可以把任何一个对象序列化为json对象,
    #需要为Student专门写一个转换函数,再把函数传进去
    def student2dict(std):
        return {
            'name':std.name,
            'age':std.age,
            'score':std.score
        }
    
    print(json.dumps(s,default=student2dict))
    
    #也可以直接把任何class 的实例变为dict
    json.dumps(s,default=lambda obj: obj.__dict__)
    
    
    #同样json 先转化为dict,再到类实例
    def dict2student(d):
        return Student(d['name'],d['age'],d['score'])
    json.loads(json_str,object_hook=dict2student)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    3.12 operator

    operator 中三个类

    1. attrgetter:可以获取对象的属性,然后进行排序
    2. itemgetter
    3. methocaller
    sorted(students,key=attrgetter('age'),reverse=True) #按照年龄进行排序
    sorted(students,key=itemgetter(1),reverse=True) #按照年龄进行排序
    
    • 1
    • 2

    3.13 networkx 创建图

    3. 13.1 创建一个图

    import networkx as nx
    G=nx.Graph()
    # 添加节点
    G.add_node(1) # 一次添加一个节点
    G.add_nodes_from([2,3]) # 添加一个节点列表
    
    # 边
    G.add_edge(1,2) # 可以通过一次添加一条边来增长
    e=(2,3)
    G.add_edge(*e)    # update edge tuple*
    G.add_edges_from([(1,2),(1,3)]) #也可以通过添加边列表
    # 删除图中所有节点和边
    G.clear()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    添加新的节点和边,并且Networkx会自动的忽略任何已经存在的节点

    G.add_edges_from([(1,2),(1,3)])
    G.add_node(1)
    G.add_edge(1,2)
    print(G.number_of_nodes())
    G.add_node("spam")
    G.add_nodes_from("spam")
    G.add_edge(3,"m")
    print(G.number_of_nodes())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3.13.2 图结构的四个属性

    1. G.nodes 节点
    2. G.edges
    3. G.adj or G.neighbors() 邻接点
    4. G.degree 图中节点的成程度集
    # 查看是否有点1
    G.has_node(1)
    # 查看是否有边(1,2)
    G.has_edge(1,2)
    
    print(list(G.nodes))
    print(list(G.edges))
    print(list(G.adj[1]))
    print(G.degree[1])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    删除边和节点的函数:

    1. Graph.remove_node()
    2. Graph.remove_nodes_from()
    3. Graph.remove_edge()
    4. Graph.remove_edges_from()

    3.13.3 有向图: DiGraph()

    dg = nx.DiGraph()
    nodes1 = [
        ('Variable', {'name': 'avariable', 'table': 'tablename'}),
        ('Select', {'conditions': {'pro_code': 44}}),
        ('GroupBy', {'varname': 'gender'}),
        ('Mean', {}),
        ('Which1', {'level': 1}),
        ('Decimal1', {'place': 1})
    ]
    
    nodes2 = [
        ('Which1', {'level': 2}),
        ('Decimal2', {'place': 1})
    ]
    
    nodes3 = [
        ('Add', {})
    ]
    
    dg.add_nodes_from(nodes1)
    dg.add_nodes_from(nodes2)
    dg.add_nodes_from(nodes3)
    dg.add_edges_from([
        ('Variable', 'Select'),
        ('Select', 'GroupBy'),
        ('GroupBy', 'Mean'),
        ('Mean', 'Which1'),
        ('Mean', 'Which2'),
        ('Which1', 'Decimal1'),
        ('Which2', 'Decimal2'),
        ('Decimal1', 'Add'),
        ('Decimal2', 'Add'),
    ])
    
    nx.draw(dg, with_labels=True)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    在这里插入图片描述

    3.13.4 属性

    属性(如:权重,便签,颜色或者喜欢的python对象)可以附加到图形,节点或边上。每个图形,节点和边都可以在关联的属性字典中保存键/值属性对(键必须是可散列的)。默认情况下,这些都是空的,但是属性可以使用添加或更改add_edge,add_node或者命名的属性字典的直接操作
    图形属性

    G=nx.Graph(day="Friday")
    print(G.graph)
    # 修改属性
    G.graph['day']="MOnday"
    print(G.graph)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    节点属性

    添加节点属性使用add_node(),add_nodes_from()G.nodes

    G.add_node(1,time="5pm")
    G.add_nodes_from([3],time="2pm")
    print(G.nodes[1])
    G.nodes[1]["room"]=714
    print(G.nodes.data())
    
    • 1
    • 2
    • 3
    • 4
    • 5

    边属性
    添加/更改边属性add_edge(),add_edges_from()或标符号

    G=nx.DiGraph()
    G.add_edge(1,2,weight=4.7)
    G.add_edges_from([(3,4),(4,5)],color="red")
    G.add_edges_from([(1,2,{'color':'blue'}),(2,3,{"weight":8})])
    G.edges[3,4]["weight"]=4.2
    nx.draw(G,with_labels=True)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.13.5 从txt文件中读入有向图的函数

    nx.read_edgelist(path,comments="#",delimiter=None,create_using=None,data=True,edgetype=None,encoding='utf-8')
    # create_using为创建图的类型:有向图,无向图
    
    • 1
    • 2

    当要读取的文件中的数据并不是按节点一的名称,节点二的名称,权重这样的三列顺序排列的时候,而是中间还有一些其他的列,比如节点属性等。但只希望读入指定列的数据时,先将指定列读入为DataFrame结构的数据,再将其通过nx.from_pandas_edgelist读入为图

    df = pd.read_csv(network_path,delimiter='\t',usecols=[0,3])
    dg = nx.from_pandas_edgelist(df,'node1','node2')
    
    # 或者
    df = pd.read_csv(network_path,delimiter='\t',names=['node1','node2'])
    dg = nx.from_pandas_edgelist(df,'node1','node2')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    textline = '1 2 3'
    fh = open('test.edgelist','w')
    d = fh.write(textline)
    fh.close()
    G = nx.read_edgelist('test.edgelist', nodetype=int, data=(('weight',float),))
    G.nodes()
    #[1, 2]
    G.edges(data = True)
    # [(1, 2, {'weight': 3.0})]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3.14 Queue 队列

    python 的Queue模块中提供了FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列PriorityQueue。
    Queue 模块中的常用方法:

    • Queue.qsize () 返回队列的大小
    • Queue.empty () 如果队列为空,返回 True, 反之 False
    • Queue.full () 如果队列满了,返回 True, 反之 False
    • Queue.full 与 maxsize 大小对应
    • Queue.get () 调用队列对象的get()方法从队头删除并返回一个项目。
    • Queue.get_nowait () 相当 Queue.get (False)
    • Queue.put (item) 调用队列对象的put()方法在队尾插入一个项目
    • Queue.put_nowait (item) 相当 Queue.put (item, False)
    • Queue.task_done () 在完成一项工作之后,Queue.task_done ()
      函数向任务已经完成的队列发送一个信号
    • Queue.join () 实际上意味着等到队列为空,再执行别的操作

    4. 面向对象编程

    由于类起到模版的作用,可以在创建实例的时候,把一些我们认为必须绑定的属性写进去,通过定义一个特殊的__init__方法,在创建实例的时候,就把属性绑定上去。

    4.1 方法__new__() 和__init__()

    self:表示实例本身,因此,在__init__方法内部,就可以把各种属性绑定到self

    class Student():
        def __init__(self,name,score):
            self.name=name
            self.score=score
        def print_score(self):
            print('%S:%s'%(self.name,self.score))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    Python中存在于类中的构造方法__init__()负责将类实例化,而在__init__()执行之前,

    __new__()负责制造这样的一个实例对象,以便__init__()去让该实例对象更加的丰富(为其添加属性等)。

    4.2 方法__str__()

    #当使用print输出对象的时候,默认打印对象的内存地址。如果类定义了__str__方法,那么就会打印这个方法中return的数据
    class Wasker():
        def __init__(self,width,height):
            self.width=width
            self.height=height
        def __str__(self):
            return "这是洗衣机的说明书"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    4.3 访问权限

    __开头的实例变量,在python中变成了一个私有变量private

    self.__name=name #实例仍然需要传参数,只是只能在内部使用

    #但如果外部想要获取私有属性 ,可以给类增加get_name和get_score这样的方法
    class Student(object):
        def __init__(self,name,score):
            self.__name=name
            self.__score=score
        def get_name(self):
            return self.__name
        def get_score(self):
            return self.score
        #如果又要允许外部代码修改socre,可以通过添加set_score方法:
        def set_score(self,score):
            self.__score=score
    
    #目的:对参数做检查,防止传入无效的参数
    class Student():
        def __init__(self,name,score):
            self.__name=name
            self.__score=score
        def set_score(self,score):
            if 0<=score<=100:
                self.__score=score
            else:
                raise ValueError('bad score')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    4.4 继承和多态

    #当子类和父类具有相同的方法是,子类的方法会覆盖父类的方法,这也就是获得了继承的另一个好处:多态
    
    class People():
    
        def __init__(self,name,age,weight):
            self.name=name
            self.age=age
            self.__weight=weight
    
        def speak(self):
            print('{} 说:我今年{}岁了,体重是{:.2f}kg'.format(self.name,self.age,self.__weight))
    
    class Student(People):
        def __init__(self,name,age,weight,grade):
            People.__init__(self,name,age,weight)
            self.grade=grade
    
        #重写父类方法
    
        def speak(self):
    
            print('{}说:我今年{}岁了,我在上海读{}年级。'.format(self.name,self.age,self.grade))
    
    class Spearker():
    
        def __init__(self,name,topic):
            self.name=name
            self.topic=topic
        def speak(self):
            print("我叫 %s,我是一名演说家,我今天演讲的主题是%s" %(self.name,self.topic))
    
    
    #多重继承
    class Sample(Spearker,Student):
        def __init__(self,name,age,weight,grade,topic):
            Student.__init__(self,name,age,weight,grade)
            Spearker.__init__(self,name,topic)
    
    
    
    test=Sample('tim',10,40.123,6,'python')
    test.speak()  #方法名同,默认调用的是在括号中排前地父类的方法
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    4.5 方法重写

    class Parent:  # 定义父类
        def myMethod(self):
            print('调用父类方法')
    
    
    class Child(Parent):  # 定义子类
        def myMethod(self):
            print('调用子类方法')
    
    
    c = Child()  # 子类实例
    c.myMethod()  # 子类调用重写方法
    super(Child, c).myMethod()  # 用子类对象调用父类已被覆盖的方法
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    4.6 静态方法

    静态方法的特点,需要使用装饰器@staticmethod来进行修饰,静态方法既不需要传递类对象也不需要传递实例对象(形参没有self/cls)。

    4.7 打印类的相关信息

    class Point():
        def __init__(self,x,y):
            self.x=x
            self.y=y
        def __repr__(self):             
            return "Point({self.x},{self.y})".format(self=self)
    p=Point(3,5)
    print(p)
    # 打印类的信息,也可以不用写repr方法,直接使用p.__dict__()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    5. 多进程、多线程

    5.1 多线程

    """
    如何保持各线程之间的通信,在这里,我们使用队列Queue作为多线程之间通信的桥梁。
    使用十个线程来执行run方法消化任务队列,run方法有两个参数,一个任务队列,一个保存结果的队列。
    in_q.empty(),是对列的一个方法,它是检测队列是否为空,是一个布尔值,url = in_q.get(),这个操作是拿出队列的一个值出来,然后,把它从队列里删掉。
    
    """
    # 一个关于queue.task_done()与queue.join()的实验
    from threading import Thread
    import time
    import random
    from queue import Queue
    from collections import deque
    
    # 创建队列,设置队列最大数限制为3个
    queue = Queue(3)
    
    
    # 生产者线程
    class Pro_Thread(Thread):
        def run(self):
            # 原材料准备,等待被生产
            tasks = deque([1, 2, 3, 4, 5, 6, 7, 8])
            global queue
            while True:
                try:
                    # 从原材料左边开始生产
                    task = tasks.popleft()
                    queue.put(task)
                    print("生产", task, "现在队列数:", queue.qsize())
    
                    # 休眠随机时间
                    time.sleep(random.random())
                # 如果原材料被生产完,生产线程跳出循环
                except IndexError:
                    print("原材料已被生产完毕")
                    break
    
    
    # 消费者线程
    class Con_Thread(Thread):
        def run(self):
            global queue
            while True:
                if queue.not_empty:
                    # 通过get(),这里已经将队列减去了1
                    task = queue.get()
                    time.sleep(2)
                    # 这里可能队列数已经空了,但是消费者手里还有正在消费的队列
                    # 发出完成的信号,不发的话,join会永远阻塞,程序不会停止
                    queue.task_done()
                    print("消费", task)
                else:
                    break
    
    
    # r入口方法,主线程
    def main():
        Pro_1 = Pro_Thread()
        # 把生产线程列为守护线程,否则主线程结束之后不会销毁该线程,程序不会停止,影响实验结果
        Pro_1.setDaemon(True)
        # 启动线程
        Pro_1.start()
    
        for i in range(2):
            Con_i = Con_Thread()
            # 把两个消费者线程列为守护线程,否则主线程结束之后不会销毁该线程,程序不会停止,影响实验结果
            Con_i.setDaemon(True)
            # 启动线程
            Con_i.start()
        global queue
        # 这里休眠一秒钟,等到队列有值,否则队列创建时是空的,主线程直接就结束了,实验失败,造成误导
        time.sleep(1)
        # 接收信号,主线程在这里等待队列被处理完毕后再做下一步
        queue.join()
        # 给个标示,表示主线程已经结束
        print("主线程结束")
    
    
    if __name__ == '__main__':
        main()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

    5.2 多进程

    """
    如何保持各线程之间的通信,在这里,我们使用队列Queue作为多线程之间通信的桥梁。
    使用十个线程来执行run方法消化任务队列,run方法有两个参数,一个任务队列,一个保存结果的队列。
    in_q.empty(),是对列的一个方法,它是检测队列是否为空,是一个布尔值,url = in_q.get(),这个操作是拿出队列的一个值出来,然后,把它从队列里删掉。
    
    """
    # 一个关于queue.task_done()与queue.join()的实验
    from threading import Thread
    import time
    import random
    from queue import Queue
    from collections import deque
    
    # 创建队列,设置队列最大数限制为3个
    queue = Queue(3)
    
    
    # 生产者线程
    class Pro_Thread(Thread):
        def run(self):
            # 原材料准备,等待被生产
            tasks = deque([1, 2, 3, 4, 5, 6, 7, 8])
            global queue
            while True:
                try:
                    # 从原材料左边开始生产
                    task = tasks.popleft()
                    queue.put(task)
                    print("生产", task, "现在队列数:", queue.qsize())
    
                    # 休眠随机时间
                    time.sleep(random.random())
                # 如果原材料被生产完,生产线程跳出循环
                except IndexError:
                    print("原材料已被生产完毕")
                    break
    
    
    # 消费者线程
    class Con_Thread(Thread):
        def run(self):
            global queue
            while True:
                if queue.not_empty:
                    # 通过get(),这里已经将队列减去了1
                    task = queue.get()
                    time.sleep(2)
                    # 这里可能队列数已经空了,但是消费者手里还有正在消费的队列
                    # 发出完成的信号,不发的话,join会永远阻塞,程序不会停止
                    queue.task_done()
                    print("消费", task)
                else:
                    break
    
    
    # r入口方法,主线程
    def main():
        Pro_1 = Pro_Thread()
        # 把生产线程列为守护线程,否则主线程结束之后不会销毁该线程,程序不会停止,影响实验结果
        Pro_1.setDaemon(True)
        # 启动线程
        Pro_1.start()
    
        for i in range(2):
            Con_i = Con_Thread()
            # 把两个消费者线程列为守护线程,否则主线程结束之后不会销毁该线程,程序不会停止,影响实验结果
            Con_i.setDaemon(True)
            # 启动线程
            Con_i.start()
        global queue
        # 这里休眠一秒钟,等到队列有值,否则队列创建时是空的,主线程直接就结束了,实验失败,造成误导
        time.sleep(1)
        # 接收信号,主线程在这里等待队列被处理完毕后再做下一步
        queue.join()
        # 给个标示,表示主线程已经结束
        print("主线程结束")
    
    
    if __name__ == '__main__':
        main()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
  • 相关阅读:
    欧洲关于茶最早的记载
    原生App-云打包
    SpringBoot整合ElasticEearch【代码示例】
    SFTP(Secure File Transfer Protocol)的文件下载和上传
    HTML5期末大作业:基于HTML+CSS+JavaScript茶文化中国水墨风格绿色茶叶销售(5页) 学生网页设计作业源码
    时区的问题
    跨越单线程限制:Thread类的魅力,引领你进入Java并发编程的新纪元
    WebWall-04.CSRF(跨站请求伪造)
    Windows C++ 启动子进程并绑定子进程,主进程结束关闭后自动结束关闭子进程
    读《基于深度学习的跨视角步态识别算法研究》
  • 原文地址:https://blog.csdn.net/qq_43283527/article/details/125466521