美文网首页
python 10天快速教程 Day9

python 10天快速教程 Day9

作者: XaviSong | 来源:发表于2020-07-16 19:44 被阅读0次

    本节重点

    1. IO
    2. 序列化
    3. 可迭代对象与迭代器
    4. 生成器
    5. 多线程

    一、包

    定义:

    通俗理解为带有多个模块的文件夹,只不过文件夹中有__ init __.py文件,包裹、管理模块。

    1、导入包中的模块
    # 类比导入模块时的方式
    # 方式一
    import package.first
    import package.second
    
    # 方式二
    from package import first as one
    from package import second
    
    # 方式三
    from package import * # 导入包中所有模块
    '''
    可通过__init__.py 中限定导入模块:__all__ = ["first","second"]
    '''
    
    2、直接导入包
    import package
    package.first.show()
    '''
    python2中需要在__init__.py中添加
    from package import first
    from package import second
    python3貌似不用
    '''
    
    3、使用包模块中的代码:
    package.first.show()
    package.first.show_msg()
    
    4、设置包模块的别名
    import package.first as one
    one.show()
    two.show_msg()
    

    二、IO

    目的:小批量数据先在内存中处理,再进行持久化(硬盘、数据库等)

    1、stringIO
    from io import StringIO
    str_io = io.StringIO() # 获取对象
    
    # 写入数据
    str_io.write("hello")
    str_io.write("word")
    
    # 获取内存中全部数据
    content = str_io.getvalue()
    print(content)
    
    # 设定对象指针
    str_io.seek(0)
    result = str_io.read() # 默认全部读取,接受参数表示读取字节数
    print(result)
    '''
    helloword
    helloword
    '''
    
    2、BytesIO
    from io import BytesIO
    byte_io = io.BytesIO()
    # 编码写入二进制数据
    byte_io.write("syp".encode("utf-8"))
    data = byte_io.getvalue()
    print(data)
    # 解码读取二进制数据
    result = data.decode("utf-8")
    print(result)
    '''
    b'syp'
    syp
    '''
    

    三、序列化

    定义

    把内存数据保存到本地,可以做到数据持久化

    1、pickle

    通用序列化模块,可序列化任何数据

    import pickle
    # 序列化
    mylist = [{"name":"syp","age":22},{"name":"dsy","age":22}]
    file = open("mylist.serialize","wb") # 后缀
    pickle.dump(mylist, file) # 打包序列化
    file.close()
    
    # 反序列化
    file = open("mylist.serialize","rb")
    my_list = pickle.load(file)
    print(my_list)
    file.close()
    
    # 对类对象的序列化,本质上就是序列化其属性
    class Student:
        def __init__(self,name,age):
            super().__init__()
            self.name = name
            self.age = age
    stu  = Student("syp",22)
    file = open("stu.txt","wb")
    pickle.dump(stu,file)
    file.close()
    file = open("stu.txt","rb")
    my_list = pickle.load(file)
    print(my_list.name,my_list.age)
    file.close()
    
    2、json

    json序列化:只支持部分数据类型(列表、字典、int......),不支持自定义数据类型,比如自定义类,但是可以保存类的属性 json.dump(stu.__ dict __)。

    import json
    mylist = [{"name":"syp","age":22},{"name":"dsy","age":22}]
    file = open("mylist.txt","w",encoding="utf-8")
    json.dump(mylist,file)
    file.close()
    file = open("mylist.txt","r",encoding="utf-8")
    mylist = json.load(file)
    print(mylist)
    '''
    [{'name': 'syp', 'age': 22}, {'name': 'dsy', 'age': 22}]
    '''
    

    直接json序列化一个类对象会报错

    class Student:
        def __init__(self,name,age):
            super().__init__()
            self.name = name
            self.age = age
    stu = Student("syp",22)
    file = open("mylist1.txt","w",encoding="utf-8")
    json.dump(stu,file) # 报错
    file.close()
    '''
    TypeError: Object of type Student is not JSON serializable
    '''
    

    但是可以只序列化其属性:

    json.dump(stu.__dict__,file)
    '''
    {'name': 'syp', 'age': 22}
    '''
    

    四、可迭代对象

    1、定义:

    通俗理解为,for循环遍历取值的对象就是可迭代对象(列表、元组、字符串、集合、range),统一特征是具有__ iter __方法。

    判断对象是否是可迭代对象

    from collections import Iterable
    result = isinstance([1,2,3],Iterable)
    print(result)
    
    # 判断对象是否为指定类型
    result = isinstance([1,2,3],tuple)
    print(result)
    
    # 特征:可迭代对象都有__iter__方法
    # 查看可迭代对象的所有方法
    result = dir([1,2,3])
    print(result)
    
    '''
    True
    False
    ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
    '''
    
    2、迭代器
    实现一个可迭代对象:

    自定义一个类,并在类中重写iter和next方法,创建对象。

    作用:

    可以用数据位置获取下一个位置的值。

    好处:

    节省内存,不用每次将全部数据读入内存

    class Myiterable(object):
        def __init__(self):
            super().__init__()
            self.mylist = [1,2,3,4,5]
            self.current_index = 0
        
        # 重写方法
        def __iter__(self):
            return self
    
        def __next__(self):
            if self.current_index < len(self.mylist):
                result = self.mylist[self.current_index]
                self.current_index += 1
                return result
            else:
                raise StopIteration # 抛出异常,停止迭代
    myiter = Myiterable()
    result = isinstance(myiter, Iterable)
    print(result)
    '''
    True
    '''
    
    print(next(myiter))
    print(next(myiter))
    '''
    1
    2
    '''
    
    # 可用for循环打印出全部的数据
    for value in myiter:
        print(value)
    '''
    1
    2
    3
    4
    5
    '''
    
    3、生成器
    定义:

    特殊迭代器,for循环遍历,自动停止迭代。不会一开始保存所有数据,而是实时计算出结果。而迭代器在已经存好数据的容器中不断取值。

    result = (x for x in range(4))
    print(result,type(result))
    value = next(result)
    print(value)
    value = next(result)
    print(value)
    value = next(result)
    print(value)
    '''
    <generator object <genexpr> at 0x000001EE47771138> <class 'generator'>
    0
    1
    2
    '''
    
    yield生成器:

    出现yield关键字,暂停,返回结果。下次启动生成器在暂停位置继续,可返回多次值。

    g = show_num()
    result = next(g) # 第一次返回for循环中的第一个元素0
    print(result)
    result = next(g) # 第二次生成器继续for循环,返回下一个元素1
    print(result)
    result = next(g) # 返回2
    print(result)
    '''
    0
    1
    2
    '''
    

    五、多线程

    1、定义:

    执行代码的分支,默认只有一个主线程,多个线程可同时执行。

    2、应用场景:

    百度网盘,多任务下载。

    注意:python本质上没有多线程

    3、示例:执行多线程
    # 方法A与方法B为两个线程执行
    import threading #使用threading模块
    def methodA(count):
        for i in range(count):
            print("AA\n")
    def methodB(count):
        for i in range(count):
            print("BB\n")
    if __name__ == "__main__":
        subthread1 = threading.Thread(target=methodA,args=(10,)) # 创建子线程
        subthread2 = threading.Thread(target=methodB,kwargs={"count":5})
        subthread1.start() # 执行子线程
        subthread2.start()
    '''
    AA
    AA
    AABB
    AA
    
    AABB
    
    AABB
    
    AABB
    
    AABB
    
    AA
    AA
    '''
    

    注意args接收的参数是元组形式,kwargs接收的是字典形式。

    4、示例:线程守护

    主线程结束时,子线程被直接销毁结束,运用到daemon参数。

    import threading
    import time
    def methodA():
        print("inAA",threading.current_thread())
        print("这是在子线程中执行的")
        while True:
            print("AA")
            time.sleep(0.2)
    if __name__ == '__main__':
        print("main",threading.current_thread())
        sub = threading.Thread(target=methodA)
        sub.setDaemon(True) # 设置守护线程,主线程退出会直接销毁子线程
        sub.start()
        time.sleep(1)
        print("over")
    '''
    这是在子线程中执行的
    AA
    AA
    AA
    AA
    AA
    over
    AA
    AA
    AA
    (子线程的无限循环被终止)
    '''
    
    5、公共资源的争夺

    如下两个线程都对g_num进行增加,但是不能达到预期的效果

    import threading
    g_num = 0
    def sum1():
        global g_num
        for i in range(1000000):
            g_num+=1
        print("sum1",g_num)
    
    def sum2():
        global g_num
        for i in range(1000000):
            g_num+=1
        print("sum2",g_num)
    
    if __name__ == "__main__":
        first = threading.Thread(target = sum1)
        second = threading.Thread(target = sum2)
        first.start()
        second.start()
    '''
    sum2 1047819
    sum1 1220658
    '''
    

    增加互斥锁来解决这个问题:

    要对公共资源进行操作,必须先取得该资源上的锁,没有锁就不可以访问,当其他线程占用锁的时候不能抢夺,必须等其释放锁之后来获得锁。更详细的锁概念可以参考操作系统的相关书籍。

    示例:互斥锁:
    import threading
    lock = threading.Lock() # 获得锁对象
    
    g_num = 0
    def sum1():
        lock.acquire() # 获得锁
        global g_num
        for i in range(1000000):
            g_num+=1
        lock.release() # 释放锁
        print("sum1",g_num)
    
    def sum2():
        lock.acquire() # 获得锁
        global g_num
        for i in range(1000000):
            g_num+=1
        lock.release() # 释放锁
        print("sum2",g_num)
    
    if __name__ == "__main__":
        first = threading.Thread(target = sum1)
        second = threading.Thread(target = sum2)
        first.start()
        second.start()
    '''
    sum1 1000000
    sum2 2000000
    '''
    

    上一篇:python 10天快速教程 Day8
    下一篇:python 10天快速教程 Day10

    相关文章

      网友评论

          本文标题:python 10天快速教程 Day9

          本文链接:https://www.haomeiwen.com/subject/dgumhktx.html