• 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
  • 相关阅读:
    类方法代码重构寻找坏味道
    迭代二分查找二分查找
    系统牛逼[置顶] 使用RAMP理解内在动机 Understanding Intrinsic Motivation with RAMP
    对象服务器Webservices获取天气
    手机服务器Android消息推送(二)基于MQTT协议实现的推送功能
    概率小数2013年阿里巴巴暑期实习招聘笔试题目(不完整,笔试时间:2013.5.5)
    像素颜色JavaFX示例简易图片处理工具
    算法队列SPFA算法详解
    选择文件Eclipse制作jar包
    nullnull推箱子
  • 原文地址:https://www.cnblogs.com/linyuhong/p/10428485.html
Copyright © 2020-2023  润新知