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
原文地址:https://www.cnblogs.com/zhoulixiansen/p/9961088.html