• Python高级编程和异步IO并发编程(笔记)


    一、魔法函数

    # 例子
    class Company(object):
        def __init__(self, employee_list):
            self.employee = employee_list
        
        def __getitem__(self, item):
            return self.employee[item]
    
        def __len__(self):
            return len(self.employee)
    company = Company(["tom", "bob", "jane"])

    1、在类中实现了__getitem__方法,就可以对类Company的实例进行切片,遍历的操作------>for循环调用__iter__方法,如果没有就调用__getitem__方法,其中的参数item是Python解释器会帮我们填进去的(从0开始),直到报错了for循环才停止。

    2、用len()来读取Python的内置类型例如list,dict,set的效率很高,因为此时Python不会去遍历,而是会直接读取list的长度

    对魔法函数的总结:Python语法会识别魔法函数,对其的调用是隐射的。可以把魔法函数看成是独立的存在,而不是对谁的调用或者从object继承。往类里面加入魔法函数后,会增强我们类的类型,例如类可以进行切片操作了,相当于把类变成了序列类型

    二、深入类和对象

    1、动态语言与鸭子类型

    动态语言中经常提到鸭子类型,所谓鸭子类型就是:如果走起路来像鸭子,叫起来也像鸭子,那么它就是鸭子(If it walks like a duck and quacks like a duck, it must be a duck)。鸭子类型是编程语言中动态类型语言中的一种设计风格,一个对象的特征不是由父类决定,而是通过对象的方法决定的。

    静态语言中对象的特性取决于其父类。而动态语言则不一样,比如迭代器,任何实现了 __iter__ 和 __next__方法的对象都可称之为迭代器,但对象本身是什么类型不受限制,可以自定义为任何类。

    # isinstance 和·type的区别
    class A(object):
        pass
    
    class B(A):
        pass
    
    b = B()
    type(b) is B  --------> True
    type(b) is A  --------> False
    type(b)是指向B这个全局唯一的类的

    2、类属性的查找顺序

    # 深度优先算法对于菱形继承的情况有问题---->例如A是B和C的父类,D同时继承B和C,若方法func在A中存在,在C中被重新定义,若采用深度优先算法,D.func调用的是A中的func,而不是C中重写的func
    # 广度优先算法对于重名问题有问题----->例如D同时继承B和C,A是B的父类,若想通过D.func调用A中的func,但因为如果C中刚好也有重名方法func的话,将导致被覆盖
    # C3算法(MRO算法)---》根据继承内容选择是深度优先还是广度优先
    
    # super不是调用父类,而是调用MRO里面顺序的类
    # 类的多继承问题的解决方法--->参考mixin的设计思路
    # mixin模式特点
    # 1. Mixin类功能单一
    # 2. 不和基类关联,可以和任意基类组合, 基类可以不和mixin关联就能初始化成功
    # 3. 在mixin中不要使用super这种用法
    
    # 要修改类方法,通过 类名.xxx 调用,不能通过实例调用赋值
    # dir() 查找对象的属性,比__dict__强大

    3、Python是基于协议进行编程的

    上下文管理协议

    (1)

    # try:
        print("...")
        raise Keyerror
    # except Keyerror:
        return 1
    # else:
        ...
    # finally:
      return 2
    # 注意返回的是2不是1,1和2都被压栈,但只弹出顶层的元素

    (2)__enter____exit__

    try...finally非常繁琐。Python的with语句允许我们非常方便地使用资源,而不必担心资源没有关闭。

    实际上,任何对象,只要正确实现了上下文管理,就可以用于with语句。

    实现上下文管理是通过__enter____exit__这两个方法实现的。

    #上下文管理器协议
    class Sample:
        def __enter__(self):
            print ("enter")
            #获取资源
            return self
        def __exit__(self, exc_type, exc_val, exc_tb):
            #释放资源
            print ("exit")
        def do_something(self):
            print ("doing something")
    
    with Sample() as sample:
        sample.do_something()

    (3)@contextlib.contextmanager

    编写__enter____exit__仍然很繁琐,因此Python的标准库contextlib提供了更简单的写法,上面的代码可以改写如下:

    import contextlib
    
    @contextlib.contextmanager
    def file_open(file_name):
        print ("file open")
        yield {}
        print ("file end")
    
    with file_open("bobby.txt") as f_opened:
        print ("file processing")

    三、自定义序列类

    # +、+=、extend的区别
    # + 的本质是重新创建一个新的列表,地址改变
    # += 的内部实现一个__iadd__的魔法函数,里面调用extend(),在内部进行for循环append进去,所以只要接受一个可迭代的类型就行,而+必须跟同类型的。在a的基础上进行修改,地址不变
    # append 直接把数组当成一个值传进去
    # += ----> extend -----> append
    # 列表推导式,如果只有一个if,就把if放在for后面,如果有if else,就放在for前面
    
    from collections.abc import MutableMapping
    a = {}
    isinstance(a, MutableMapping) # --------> True 不是a继承了MutableMapping,而是a这个字典实现了MutableMapping里面的部分魔法函数,源码里面是把{}注册到MutableMapping中

    四、深入理解dict和set

    # dict查找的性能远大于list
    #在list中随着list数据的增大 查找时间会增大
    #在dict中查找元素不会随着dict的增大而增大
    
    # dict的内部实现是通过哈希表(set也是)
    # dict为什么查找那么快?---->利用数组,通过偏移量直接找到数据,时间复杂度是O(1),而且不会随着数据量的增大而使查找速度下降
    # 所以key必须可哈希--->不可变对象都是可哈希
    # dict的内存花销大(hash的缺点,一开始会申请比较大的内存空间,降低冲突的机会),但是查询速度快, 自定义的对象 或者python内部的对象都是用dict包装的
    # dict的存储顺序和元素添加顺序有关---->因为可能会冲突,先储存,就先占据某个位置
    # 添加数据有可能改变已有数据的顺序--->因为当数据过多,重新开始申请一块更大的内存,把数据搬迁过去的时候,会改变存储顺序

    五、对象引用、可变性和垃圾回收

    #python和java(变量相当于一个盒子)中的变量本质不一样,python的变量实质上是一个指针 int str, 便利贴
    #变量大小是固定的
    a = 1
    a = "abc"
    #1. a贴在1上面
    #2. 先生成对象 然后贴便利贴
    #cpython中垃圾回收的算法是采用 引用计数

    一个经典错误

    class Company:
        def __init__(self, name, staffs=[]):
            self.name = name
            self.staffs = staffs
        def add(self, staff_name):
            self.staffs.append(staff_name)
        def remove(self, staff_name):
            self.staffs.remove(staff_name)
    
    if __name__ == "__main__":
        com1 = Company("com1", ["bobby1", "bobby2"])
        com1.add("bobby3")
        com1.remove("bobby1")
        print (com1.staffs)
    
        com2 = Company("com2")
        com2.add("bobby")
        print(com2.staffs) # [bobby]
    
        print (Company.__init__.__defaults__)
    
        com3 = Company("com3")
        com3.add("bobby5")
        print (com2.staffs) # [bobby, bobby5]
        print (com3.staffs) # [bobby, bobby5]
        print (com2.staffs is com3.staffs) # True
        # 因为com2和com3公用一个默认变量

    六、元类编程

    (1) property动态属性

    from datetime import date, datetime
    class User:
        def __init__(self, name, birthday):
            self.name = name
            self.birthday = birthday
            self._age = 0
    
        # def get_age(self):
        #     return datetime.now().year - self.birthday.year
    
        @property
        def age(self):
            return datetime.now().year - self.birthday.year
    
        @age.setter
        def age(self, value):
            self._age = value
    
    if __name__ == "__main__":
        user = User("bobby", date(year=1987, month=1, day=1))
        user.age = 30
        print (user._age)
        print(user.age)

    (2)数据描述符和非数据描述符

    class IntField:
        #数据描述符
        def __get__(self, instance, owner):
            return self.value
        def __set__(self, instance, value):
            if not isinstance(value, numbers.Integral):
                raise ValueError("int value need")
            if value < 0:
                raise ValueError("positive value need")
            self.value = value
        def __delete__(self, instance):
            pass
    
    
    class NonDataIntField:
        #非数据属性描述符
        def __get__(self, instance, owner):
            return self.value
    
    class User:
        age = IntField()
        # age = NonDataIntField()
    
    '''
    如果user是某个类的实例,那么user.age(以及等价的getattr(user,’age’))
    首先调用__getattribute__。如果类定义了__getattr__方法,
    那么在__getattribute__抛出 AttributeError 的时候就会调用到__getattr__,
    而对于描述符(__get__)的调用,则是发生在__getattribute__内部的。
    user = User(), 那么user.age 顺序如下:
    
    (1)如果“age”是出现在User或其基类的__dict__中, 且age是data descriptor(数据描述符), 那么调用其__get__方法, 否则
    
    (2)如果“age”出现在user的__dict__中, 那么直接返回 obj.__dict__[‘age’], 否则
    
    (3)如果“age”出现在User或其基类的__dict__中
    
    (3.1)如果age是non-data descriptor,那么调用其__get__方法, 否则
    
    (3.2)返回 __dict__[‘age’]
    
    (4)如果User有__getattr__方法,调用__getattr__方法,否则
    
    (5)抛出AttributeError
    
    '''

    (3)ORM的实现

    class Field:
        pass
    
    class IntField(Field):
        # 数据描述符
        def __init__(self, db_column, min_value=None, max_value=None):
            self._value = None
            self.min_value = min_value
            self.max_value = max_value
            self.db_column = db_column
            if min_value is not None:
                if not isinstance(min_value, numbers.Integral):
                    raise ValueError("min_value must be int")
                elif min_value < 0:
                    raise ValueError("min_value must be positive int")
            if max_value is not None:
                if not isinstance(max_value, numbers.Integral):
                    raise ValueError("max_value must be int")
                elif max_value < 0:
                    raise ValueError("max_value must be positive int")
            if min_value is not None and max_value is not None:
                if min_value > max_value:
                    raise ValueError("min_value must be smaller than max_value")
    
        def __get__(self, instance, owner):
            return self._value
    
        def __set__(self, instance, value):
            if not isinstance(value, numbers.Integral):
                raise ValueError("int value need")
            if value < self.min_value or value > self.max_value:
                raise ValueError("value must between min_value and max_value")
            self._value = value
    
    
    class CharField(Field):
        def __init__(self, db_column, max_length=None):
            self._value = None
            self.db_column = db_column
            if max_length is None:
                raise ValueError("you must spcify max_lenth for charfiled")
            self.max_length = max_length
    
        def __get__(self, instance, owner):
            return self._value
    
        def __set__(self, instance, value):
            if not isinstance(value, str):
                raise ValueError("string value need")
            if len(value) > self.max_length:
                raise ValueError("value len excess len of max_length")
            self._value = value
    
    
    class ModelMetaClass(type):
        def __new__(cls, name, bases, attrs, **kwargs):
            if name == "BaseModel": # 不是BaseModel才是我们定义的User,才需要进行一系列处理
                return super().__new__(cls, name, bases, attrs, **kwargs)
            fields = {}
            for key, value in attrs.items():
                if isinstance(value, Field): # 因为可能是IntField或者CharField,或者判断是否是Field
                    fields[key] = value
            attrs_meta = attrs.get("Meta", None)
            _meta = {}
            db_table = name.lower()
            if attrs_meta is not None:
                table = getattr(attrs_meta, "db_table", None)
                if table is not None:
                    db_table = table
            _meta["db_table"] = db_table
            attrs["_meta"] = _meta
            attrs["fields"] = fields
            del attrs["Meta"] # 去掉不需要的Meta,已经有_meta了
            # 上面这几步相当于对attrs进行处理,最后在一起委托给父类new方法
            return super().__new__(cls, name, bases, attrs, **kwargs)
    
    
    class BaseModel(metaclass=ModelMetaClass):
        def __init__(self, *args, **kwargs):
            for key, value in kwargs.items():
                setattr(self, key, value)
            return super().__init__()
    
        def save(self):
            fields = []
            values = []
            for key, value in self.fields.items():
                db_column = value.db_column
                if db_column is None:
                    db_column = key.lower()
                fields.append(db_column)
                value = getattr(self, key)
                values.append(str(value))
            # 需要把字符串类型的value用单引号包起来(未处理)
            sql = "insert {db_table}({fields}) value({values})".format(db_table=self._meta["db_table"],fields=",".join(fields), values=",".join(values))
            pass
    
    class User(BaseModel):
        name = CharField(db_column="name", max_length=10)
        age = IntField(db_column="age", min_value=1, max_value=100)
    
        class Meta:
            db_table = "user"
    
    
    if __name__ == "__main__":
        user = User(name="bobby", age=28)
        # user.name = "bobby"
        # user.age = 28
        user.save()
    View Code
  • 相关阅读:
    Leetcode 238. Product of Array Except Self
    Leetcode 103. Binary Tree Zigzag Level Order Traversal
    Leetcode 290. Word Pattern
    Leetcode 205. Isomorphic Strings
    Leetcode 107. Binary Tree Level Order Traversal II
    Leetcode 102. Binary Tree Level Order Traversal
    三目运算符
    简单判断案例— 分支结构的应用
    用switch判断月份的练习
    java基本打印练习《我行我素购物系统》
  • 原文地址:https://www.cnblogs.com/linyuhong/p/10428485.html
Copyright © 2020-2023  润新知