首页 > 编程语言 > 详细

python深入理解类和对象

时间:2018-11-18 10:08:56      阅读:183      评论:0      收藏:0      [点我收藏+]

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

python深入理解类和对象

原文:https://www.cnblogs.com/zhoulixiansen/p/9961088.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!