• gj4 深入类和对象


    4.1 鸭子类型和多态

    当看到一只鸟走起来像鸭子、游永起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子

    只要利用Python的魔法函数,就能实现某些Python数据类型的类似的方法。

    class Cat(object):
        def say(self):
            print("i am a cat")
    
    class Dog(object):
        def say(self):
            print("i am a fish")
    class Duck(object):
        def say(self):
            print("i am a duck")
    
    animal_list=[Cat,Dog,Duck]
    for animal in animal_list:
        animal().say()
    
    # 不同的对象实现了相同的方法,多态
    
    
    i am a cat
    i am a fish
    i am a duck
    ---
    
    a = ["lewen1", "lewen2"]
    b = ["lewen2", "lewen"]
    name_tuple = ["lewen3", "lewen4"]
    name_set = set()
    name_set.add("lewen5")
    name_set.add("lewen6")
    a.extend(name_set) # extend() 括号里面为可迭代对象
    print(a)
    
    
    ['lewen1', 'lewen2', 'lewen6', 'lewen5']
    ---
    
    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"])
    b.extend(company) # 可以接受
    print(b)
    
    ['lewen2', 'lewen', 'tom', 'bob', 'jane']
    


       4.2 抽象基类(abc模块)

    Python的变量不需指定类型,可以动态修改类型(多态)
    不同的魔法函数赋予了不同的特性
    不需要继承某个类,只需要实现相应的魔法函数就可以实现特定的方法
    抽象基类无法被实例化
    #我们去检查某个类是否有某种方法
    class Company(object):
        def __init__(self, employee_list):
            self.employee = employee_list
    ​
        def __len__(self):
            return len(self.employee)
    ​
    ​
    com = Company(["bobby1","bobby2"])
    print(hasattr(com, "__len__"))
    True
    #我们在某些情况之下希望判定某个对象是否是某个类型
    from collections.abc import Sized
    isinstance(com, Sized)
    class A:
        pass
    ​
    class B(A):
        pass
    ​
    b = B()
    print(isinstance(b, A))
    True
    #我们需要强制某个子类必须实现某些方法
    #实现了一个web框架,集成cache(redis, cache, memorychache)
    #需要设计一个抽象基类, 指定子类必须实现某些方法#如何去模拟一个抽象基类class CacheBase(object):
        def get(self, key):
            raise NotImplementedError
        def set(self, key, value):
            raise NotImplementedError
    ​
    # class RedisCache(CacheBase):
    #     pass                           #没有实现父类对应的方法,调用时会报错
    class RedisCache(CacheBase):
        def set(self, key, value):      #调用不会再报错
            pass
    ​
    redis_cache = RedisCache()
    redis_cache.set("key", "value")
    #上面更规范的写法
    import abc
    #from collections.abc import *
    ​
    ​
    class CacheBase(metaclass=abc.ABCMeta):
        @abc.abstractmethod
        def get(self, key):
            pass
    ​
        @abc.abstractmethod
        def set(self, key, value):
            pass
    class RedisCache(CacheBase):
    #     def set(self, key, value):
            pass
    redis_cache = RedisCache()    #初始化的时候就需要重载基类被装饰器修饰的方法
    # redis_cache.set("key", "value")
    ---------------------------------------------------------------------------
    ​
    TypeError                                 Traceback (most recent call last)
    ​
    <ipython-input-16-a30c00982960> in <module>
         15 #     def set(self, key, value):
         16         pass
    ---> 17 redis_cache = RedisCache()    #初始化的时候就需要重载基类方法
         18 # redis_cache.set("key", "value")
    TypeError: Can't instantiate abstract class RedisCache with abstract methods get, set
    抽象基类用的比较少
    ​
    mixin
    

    e

    4.3 使用isintance而不是type

    class A:
        pass
    ​
    class B(A):
        pass
    ​
    b = B()
    ​
    print(isinstance(b, B))
    print(isinstance(b, A))
    ​
    print(type(b))
    print(type(b) is B)  #  is 去判断两个对象是不是一个对象,
    print(type(b) == B)  # == 是对值是否相等的判断
    print(type(b) is A)
    print(isinstance(b, A))
    True
    True
    <class '__main__.B'>
    True
    True
    False
    True
    尽量使用isinstance 而不是type去判断一个类型
    
    isinstance 返回一个对象是否是类或其子类的一个实例。(Return whether an object is an instance of a class or of a subclass thereof)
    
    type 对象的类型

    4.4 类变量和对象变量

    class A:
        aa = 1 # 类变量
        def __init__(self, x, y):
            self.x = x        # 实例变量
            self.y = y
    
    a = A(2,3)
    
    A.aa = 11     # 修改类变量
    a.aa = 100    # 将值赋给实例变量
    print(a.x, a.y, a.aa)
    
    print(A.aa)
    
    b = A(3,5)
    print(b.aa)
    ---
    2 3 100
    11
    11

    4.5 类属性和实例属性以及查找顺序

    2998b113-8c23-4770-9df7-4c3bbebedf0d

    深度优先

    94a5fa91-0e72-42d1-ad44-3db75ef0b283

    这种深度优先就不再合理,如果C重载了D的方法,而找了B直接找D,C就没有用了

    再Python3以后修改了这种搜索,为广度优先

    44959078

    C和D有重名的话,理应找完B再找D,而广度优先就会使C覆盖掉D

    Python3 都是采用的深度优先

    6f73e162-6ad7-4f12-866a-c13823ca9d75

    #C3算法

    小结:py3 有共同父类(菱形)的广度优先,没有共同父类的深度优先

      

    4.6 静态方法、类方法以及对象方法

    class Date:
        #构造函数
        def __init__(self, year, month, day):
            self.year = year
            self.month = month
            self.day = day
    
        def tomorrow(self):
            self.day += 1
        #静态方法    
        @staticmethod
        def parse_from_string(date_str):
            year, month, day = tuple(date_str.split("-"))
            return Date(int(year), int(month), int(day))
            #硬编码的方式,只要类名修改,这反回的类名就得修改
    
        #类方法
        @classmethod
        def from_string(cls, date_str):
            year, month, day = tuple(date_str.split("-"))
            return cls(int(year), int(month), int(day))
    
        # 判断是否是合法的字符串,不需要反回函数
        @staticmethod
        def valid_str(date_str):
            year, month, day = tuple(date_str.split("-"))
            if int(year)>0 and (int(month) >0 and int(month)<=12) and (int(day) >0 and int(day)<=31):
                return True
            else:
                return False
    
        def __str__(self):
            return "{year}/{month}/{day}".format(year=self.year, month=self.month, day=self.day)
    ​
    if __name__ == "__main__":
        new_day = Date(2018, 12, 31)
        new_day.tomorrow()
        print(new_day)
    2018/12/32
        #2018-12-31
        date_str = "2018-12-31"
        year, month, day = tuple(date_str.split("-"))
        new_day = Date(int(year), int(month), int(day))
        print (new_day)
    
        #用staticmethod(静态方法)完成初始化
        new_day = Date.parse_from_string(date_str)
        print (new_day)
    
    
        #用classmethod完成初始化
        new_day = Date.from_string(date_str)
        print(new_day)
    ​
        print(Date.valid_str("2018-12-32"))
    2018/12/31
    2018/12/31
    2018/12/31
    False
    ​
    ​
    

    4.7 数据封装和私有属性

    class User:
        def __init__(self, birthyear):
            self.__birthyear = birthyear  # 双下划线
    
        def get_age(self):
            # 返回年龄
            return 2018 - self.__birthyear
    
    
    if __name__ == "__main__":
        user = User(1990)
        print(user.get_age())
        # print(user.__birthyear)  # 私有属性是无法通过,实例访问的
        print(user._User__birthyear)  # 双下划线并不是绝对安全的
    """
    28
    1990
    """

      

    4.8 python对象的自省机制

    #自省是通过一定的机制查询到对象的内部结构class Person:
        name = "user"
    ​
    class Student(Person):
        def __init__(self, scool_name):
            self.scool_name = scool_name
    ​
    ​
    user = Student("慕课网")
    #通过__dict__查询属性
    print(user.__dict__)
    
    #---
    {'scool_name': '慕课网'}
    #---
    user.__dict__["school_addr"] = "北京市"
    print(user.school_addr)
    #---
    北京市
    #---
    print(Person.__dict__)
    print(user.name)
    #---
    {'__module__': '__main__', 'name': 'user', '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
    user
    #---
    a = [1,2]
    print(dir(a))
    #---
    ['__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']


      

    4.9 super函数

    class A:
        def __init__(self):
            print ("A")
    ​
    class B(A):
        def __init__(self):
            print ("B")
            #super(B,self).__init__()  # py2中的写法
            super().__init__()
    ​
    b = B()
    #---
    B
    A
    既然我们重写B的构造函数, 为什么还要去调用super?
    super到底执行顺序是什么样的?
    
    from threading import Thread
    class MyThread(Thread):
        def __init__(self, name, user):
            self.user = user
            super().__init__(name=name)  # 重用父类的代码
    
    class A:
        def __init__(self):
            print ("A")
    ​
    class B(A):
        def __init__(self):
            print ("B")
            super().__init__()
    ​
    class C(A):
        def __init__(self):
            print ("C")
            super().__init__()
    
    class D(B, C):
        def __init__(self):
            print ("D")
            super(D, self).__init__()
    ​
    if __name__ == "__main__":
        print(D.__mro__)
        d = D()
    ​
    # 有共同父类,广度优先
    (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
    D
    B
    C
    A
    
    super() 调用的顺序是mro的顺序
    


      

    4.10 django rest framework中对多继承使用的经验

    mixin(混合继承)模式特点
    1. Mixin类功能单一(一个mixin实现一个功能)
    2. 不和基类关联,可以和任意基类组合。 基类可以不和mixin关联就能初始化成功
    3. 在mixin中不要使用super这种用法

    django中一个类继承多个mixin类实现多个功能

    048d2069-d527-44bd-9e94-04e9b4c051dc  

    4.11 python中的with语句

    try:
        print ("code started")
        raise KeyError
    except KeyError as e:
        print ("key error")
    else:                           #没有抛异常才会运行 else
        print ("other error")
    finally:                        # 不管有没有异常,最后会执行
        print ("finally")           # 资源的释放
    
    # ---
    code started
    key error
    finally
    # ---
    def exe_try():
        try:
            print ("code started")
            raise KeyError
            return 1
        except KeyError as e:
            print ("key error")
            return 2
        else:
            print ("other error")
            return 3
        finally:
            print ("finally")
            return 4  # 有返回值会反回,没有反回上一层的返回值
    exe_try()
    # ---
    code started
    key error
    finally
    4
    # ---
    # 上下文管理器协议, 由 __enter__,__exit__ 实现
    # with 支持上下文管理器协议
    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()
    
    # ---
    enter
    doing something
    exit

    4.12 contextlib实现上下文管理器

    import contextlib          #上下文管理器
    @contextlib.contextmanager  # 用装饰器,将一个函数变成上下文管理器
    def file_open(file_name):
        print ("file open")
        yield {}   # 必须是生成器
        print ("file end")
    
    with file_open("lewen.txt") as f_opened:
        print ("file processing")
    
    ---
    file open
    file processing
    file end
    ---

    Python 本身没有接口,利用魔法函数的组合,和协议实现某些数据类型的属性

  • 相关阅读:
    根据View找控制器
    ScrollView双击图片定点放大
    iOS消息推送原理和实现总结
    iOS完整学习路线图
    获取设备版本
    UIView与CALayer的区别,很详细
    iOS开发网络数据之AFNetworking使用
    (已实践)PLSQL本地还原Oracle数据库dmp文件
    所遇Oracle错误代码
    Dapper基本使用
  • 原文地址:https://www.cnblogs.com/wenyule/p/10361206.html
Copyright © 2020-2023  润新知