• python深入理解类和对象


    1,鸭子类型和多态

    当看到一只鸟走起来像鸭子,游泳起来像鸭子,叫起来也像鸭子,那这只鸟就是鸭子

    是不是比较混乱,看个例子:

    # -*- coding:UTF-8 -*-
    __autor__ = 'zhouli'
    __date__ = '2018/11/14 20:46'
    
    
    class Cat:
        def say(self):
            print('iam a cat')
    
    
    class Dog:
        def say(self):
            print('iam a dog')
    
    
    class Duck:
        def say(self):
            print('iam a duck')
    
    
    animal_list = [Cat, Dog, Duck]
    for animal in animal_list:
        animal().say()

    结果如下:

    iam a cat
    iam a dog
    iam a duck

    在这个地方三个类实现了同一个方法,这样就是一种多态,什么叫鸭子类型呢,就是所有类都实现共同的方法,所有的方法名称都一样,这样就是鸭子类型

    2,类的三个方法:

    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))
    
        @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
    
        @classmethod
        def from_string(cls, date_str):
            year, month, day = tuple(date_str.split("-"))
            return cls(int(year), int(month), int(day))
    
        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-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"))

    所谓静态方法就相当于将需要外部调用的方法集成到类的内部,将命名空间并入到类中

     类方法相比静态方法,不在需要硬编码了

    实例方法就很简单了,使用实例+方法+()即可

    3,super函数:

    先看一个简单的例子:

    # -*- coding:UTF-8 -*-
    __autor__ = 'zhouli'
    __date__ = '2018/11/17 21:18'
    
    
    class A:
        def __init__(self):
            print('A')
    
    
    class B(A):
        def __init__(self):
            print('B')
            # super(B, self).__init__()  # python2的用法
            super().__init__()
    
    
    # 既然已经重写了B的构造函数,为什么还要去调用super
    # super到底执行顺序是什么
    if __name__ == '__main__':
        b = B()

    打印结果如下:但是我们得思考2个问题,①既然已经重写了B的构造函数,为什么还要去调用super

    ② super到底执行顺序是什么

    # -*- coding:UTF-8 -*-
    __autor__ = 'zhouli'
    __date__ = '2018/11/17 21:18'
    
    
    class A:
        def __init__(self,user,name):
            print('A')
            self.user = user
            self.name = name
    
    
    class B(A):
        def __init__(self,user,name):
            self.user = user
            print('B')
            super().__init__(name=name)
    
    
    if __name__ == '__main__':
        b = B()

    可以看到B类中继承A类中,如果定义父类中的部分方法,所以为了节省代码,因此采用super

    super函数并不是简单的调用父类的方法,先看代码

    # -*- coding:UTF-8 -*-
    __autor__ = 'zhouli'
    __date__ = '2018/11/17 21:18'
    
    
    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().__init__()
    
    
    if __name__ == '__main__':
        D = D()

    D回去调用父类的函数,因为B在C之前,所以会有限调用

     结果如下:但是注意到B在调用super之后打印的是C,而不是A

    如果super是简单调用父类的构造函数的话,那么久不成立了

    为什么会打印出这样的结果呢?

    因为super是执行D的__mro__

    print(D.__mro__)
    (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

    这两个数据顺序是保持一致的!

    4,Mixin继承混合模式(除非万不得已,不要使用多继承)

    Mixin其实和普通的多继承是本质一样的,但是Mixin有两个特点:

    ①  Minin里面功能比较单一,尽量简化

    ②  不和我们真正的类一样,不和基类关联,可以和任意基类组合,基类不和Mixin关联就能初始化成功,Minin只是定义了一个方法

    ③  Minin中不要使用super的方法,因为super会根据mro算法去调用他的方法,因为尽量不要和基类关联

    ④  命名尽量使用Mixin结尾(约定俗成)

    class GoodsListViewSet(CacheResponseMixin, mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
        """
        商品列表页, 分页, 搜索, 过滤, 排序
        """
        # throttle_classes = (UserRateThrottle, )
        queryset = Goods.objects.all()
        serializer_class = GoodsSerializer
        pagination_class = GoodsPagination
        # authentication_classes = (TokenAuthentication, )
        filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter)
        filter_class = GoodsFilter
        search_fields = ('name', 'goods_brief', 'goods_desc')
        ordering_fields = ('sold_num', 'shop_price')
    
        def retrieve(self, request, *args, **kwargs):
            instance = self.get_object()
            instance.click_num += 1
            instance.save()
            serializer = self.get_serializer(instance)
            return Response(serializer.data)

    在这个类中,一个类可以完成商品列表页, 分页, 搜索, 过滤, 排序,

    class ListModelMixin(object):
        """
        List a queryset.
        """
        def list(self, request, *args, **kwargs):
            queryset = self.filter_queryset(self.get_queryset())
    
            page = self.paginate_queryset(queryset)
            if page is not None:
                serializer = self.get_serializer(page, many=True)
                return self.get_paginated_response(serializer.data)
    
            serializer = self.get_serializer(queryset, many=True)
            return Response(serializer.data)

    5,上下文管理器:

    #上下文管理器协议
    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()

    上下文如果使用with语句就必须在类中定义这个两个方法

    那如何简化这个上下文管理器呢?

    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")

    在python中提供了一个contextlib模块

    在上面的__enter__中的所有代码全部在yield之前操作

    在yield之后是原来的__exit__方法全部放在里面

    当然函数的上方必须要加上装饰器@contextlib.contextmanager

    6,使用bisect

    import bisect
    from collections import deque
    
    #用来处理已排序的序列,用来维持已排序的序列, 升序
    #二分查找
    inter_list = deque()
    bisect.insort(inter_list, 3)
    bisect.insort(inter_list, 2)
    bisect.insort(inter_list, 5)
    bisect.insort(inter_list, 1)
    bisect.insort(inter_list, 6)
    
    print(bisect.bisect_left(inter_list, 3))
    #学习成绩
    print(inter_list)

    结果如下:

    2
    deque([1, 2, 3, 5, 6])

    但是如果一旦插入一个相同的数字,左插入和右插入又有何分别呢?

    其实在一定的时候,比方说3和3.0相比或者是对成绩的排序时候有讲究

  • 相关阅读:
    查看行业数据的站点
    OKR:团队提升的目标你真的达成了吗?
    好的OKR应该有这6个特点
    Windows批量执行Sql文件
    FISCO-BCOS-Python-SDK 在window系统的安装
    docker打开2375监听端口
    fabric-sdk-java 简单示例
    fabric智能合约
    性能测试工具(BenchmarkDotnet)
    Docker安装Jenkins教程
  • 原文地址:https://www.cnblogs.com/zhoulixiansen/p/9961088.html
Copyright © 2020-2023  润新知