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 个问题,1既然已经重写了 B 的构造函数, 为什么还要去调用 super
2 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 有两个特点:
1 Minin 里面功能比较单一, 尽量简化
2 不和我们真正的类一样, 不和基类关联, 可以和任意基类组合, 基类不和 Mixin 关联就能初始化成功, Minin 只是定义了一个方法
3 Minin 中不要使用 super 的方法, 因为 super 会根据 mro 算法去调用他的方法, 因为尽量不要和基类关联
4 命名尽量使用 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
来源: http://www.bubuko.com/infodetail-2851362.html