8.18 利用Mixins扩展类功能 — python3-cookbook 3.0.0 文档 https://python3-cookbook.readthedocs.io/zh_CN/latest/c08/p18_extending_classes_with_mixins.html

8.18 利用Mixins扩展类功能

问题

你有很多有用的方法,想使用它们来扩展其他类的功能。但是这些类并没有任何继承的关系。 因此你不能简单的将这些方法放入一个基类,然后被其他类继承。

解决方案

通常当你想自定义类的时候会碰上这些问题。可能是某个库提供了一些基础类, 你可以利用它们来构造你自己的类。

假设你想扩展映射对象,给它们添加日志、唯一性设置、类型检查等等功能。下面是一些混入类:

class LoggedMappingMixin:
"""
Add logging to get/set/delete operations for debugging.
"""
__slots__ = () # 混入类都没有实例变量,因为直接实例化混入类没有任何意义 def __getitem__(self, key):
print('Getting ' + str(key))
return super().__getitem__(key) def __setitem__(self, key, value):
print('Setting {} = {!r}'.format(key, value))
return super().__setitem__(key, value) def __delitem__(self, key):
print('Deleting ' + str(key))
return super().__delitem__(key) class SetOnceMappingMixin:
'''
Only allow a key to be set once.
'''
__slots__ = () def __setitem__(self, key, value):
if key in self:
raise KeyError(str(key) + ' already set')
return super().__setitem__(key, value) class StringKeysMappingMixin:
'''
Restrict keys to strings only
'''
__slots__ = () def __setitem__(self, key, value):
if not isinstance(key, str):
raise TypeError('keys must be strings')
return super().__setitem__(key, value)

  

这些类单独使用起来没有任何意义,事实上如果你去实例化任何一个类,除了产生异常外没任何作用。 它们是用来通过多继承来和其他映射对象混入使用的。例如:

class LoggedDict(LoggedMappingMixin, dict):
pass d = LoggedDict()
d['x'] = 23
print(d['x'])
del d['x'] from collections import defaultdict class SetOnceDefaultDict(SetOnceMappingMixin, defaultdict):
pass d = SetOnceDefaultDict(list)
d['x'].append(2)
d['x'].append(3)
# d['x'] = 23 # KeyError: 'x already set'

  

这个例子中,可以看到混入类跟其他已存在的类(比如dict、defaultdict和OrderedDict)结合起来使用,一个接一个。 结合后就能发挥正常功效了。

讨论

混入类在标准库中很多地方都出现过,通常都是用来像上面那样扩展某些类的功能。 它们也是多继承的一个主要用途。比如,当你编写网络代码时候, 你会经常使用 socketserver 模块中的 ThreadingMixIn 来给其他网络相关类增加多线程支持。 例如,下面是一个多线程的XML-RPC服务:

from xmlrpc.server import SimpleXMLRPCServer
from socketserver import ThreadingMixIn
class ThreadedXMLRPCServer(ThreadingMixIn, SimpleXMLRPCServer):
pass

同时在一些大型库和框架中也会发现混入类的使用,用途同样是增强已存在的类的功能和一些可选特征。

对于混入类,有几点需要记住。首先是,混入类不能直接被实例化使用。 其次,混入类没有自己的状态信息,也就是说它们并没有定义 __init__() 方法,并且没有实例属性。 这也是为什么我们在上面明确定义了 __slots__ = () 。

还有一种实现混入类的方式就是使用类装饰器,如下所示:

def LoggedMapping(cls):
"""第二种方式:使用类装饰器"""
cls_getitem = cls.__getitem__
cls_setitem = cls.__setitem__
cls_delitem = cls.__delitem__ def __getitem__(self, key):
print('Getting ' + str(key))
return cls_getitem(self, key) def __setitem__(self, key, value):
print('Setting {} = {!r}'.format(key, value))
return cls_setitem(self, key, value) def __delitem__(self, key):
print('Deleting ' + str(key))
return cls_delitem(self, key) cls.__getitem__ = __getitem__
cls.__setitem__ = __setitem__
cls.__delitem__ = __delitem__
return cls @LoggedMapping
class LoggedDict(dict):
pass

  这个效果跟之前的是一样的,而且不再需要使用多继承了。参考9.12小节获取更多类装饰器的信息, 参考8.13小节查看更多混入类和类装饰器的例子。

  



利用Mixins扩展类功能的更多相关文章

  1. DRF框架(五)——context传参,二次封装Response类,两个视图基类(APIView/GenericAPIView),视图扩展类(mixins),子类视图(工具视图),视图集(viewsets),工具视图集

    复习 1.整体修改与局部修改 # 序列化get (给前端传递参数) #查询 ser_obj = ModelSerializer(model_obj) #只传递一个参数,默认是instance的参数,查 ...

  2. C++类功能扩展预留五招

    第一招虚函数 通过派生类来进行功能扩展是基本的面向对象的方式,这种方式大如下: class base { public: virtual ~base(){} virtual void fun() { ...

  3. Java:利用java Timer类实现定时执行任务的功能

    一.概述 在java中实现定时执行任务的功能,主要用到两个类,Timer和TimerTask类.其中Timer是用来在一个后台线程按指定的计划来执行指定的任务.TimerTask一个抽象类,它的子类代 ...

  4. [Swift]在Swift中实现自增(++)、自减(--)运算符:利用extension扩展Int类

    自增(++).自减(--)运算符主要用在For循环中,Swift有自己更简易的循环遍历方法,而且类似x- ++x这种代码不易维护. Swift为了营造自己的编码风格,树立自己的代码精神体系,已经不支持 ...

  5. Java定时任务:利用java Timer类实现定时执行任务的功能

    一.概述 在java中实现定时执行任务的功能,主要用到两个类,Timer和TimerTask类.其中Timer是用来在一个后台线程按指定的计划来执行指定的任务. TimerTask一个抽象类,它的子类 ...

  6. ios开发总结:Utils常用方法等收集,添加扩展类,工具类方法,拥有很多方便快捷功能(不断更新中。。。)

    BOBUtils 工具大全 本人github开源和收集功能地址:https://github.com/niexiaobo [对ios新手或者工作一年以内开发人员很有用处] 常用方法等收集.添加扩展类. ...

  7. ASP.NET MVC4 HtmlHelper扩展类,实现分页功能 @Html.ShowPageNavigate

    本文主要做了一个HtmHelper类的分页扩展函数,方便在视图中调用,有需要的朋友可以参考一下,希望对大家有所帮助. 1.扩展HtmlHelper类方法ShowPageNavigate output. ...

  8. C#中关于增强类功能的几种方式

    C#中关于增强类功能的几种方式 本文主要讲解如何利用C#语言自身的特性来对一个类的功能进行丰富与增强,便于拓展现有项目的一些功能. 拓展方法 扩展方法被定义为静态方法,通过实例方法语法进行调用.方法的 ...

  9. C# 中一些类关系的判定方法 C#中关于增强类功能的几种方式 Asp.Net Core 轻松学-多线程之取消令牌

    1.  IsAssignableFrom实例方法 判断一个类或者接口是否继承自另一个指定的类或者接口. public interface IAnimal { } public interface ID ...

随机推荐

  1. Redis基础篇(四)持久化:内存快照(RDB)

    AOF好处是每次执行只需要记录操作命令,记录量不大.但在故障恢复时,需要逐一执行AOF的操作命令,如果日志很大,恢复就很慢. 今天学习另一种持久化方式:内存快照.内存快照,是Redis某一时刻的状态, ...

  2. 阿里面试:问springBoot自动装配我这样回答的,面试官对我竖起了大拇指

    引言 最近有个读者在面试,面试中被问到了这样一个问题"看你项目中用到了springboot,你说下springboot的自动配置是怎么实现的?"这应该是一个springboot里面 ...

  3. mybatis实现MySQL数据库的增删改查之二

    这里直接附上代码: 1 package com.qijian.pojo; 2 3 import org.apache.ibatis.type.Alias; 4 5 6 public class Use ...

  4. [leetcode]House Robber1,2

    /** * 一. * You are a professional robber planning to rob houses along a street.Each house has a cert ...

  5. [Machine Learning] 逻辑回归 (Logistic Regression) -分类问题-逻辑回归-正则化

    在之前的问题讨论中,研究的都是连续值,即y的输出是一个连续的值.但是在分类问题中,要预测的值是离散的值,就是预测的结果是否属于某一个类.例如:判断一封电子邮件是否是垃圾邮件:判断一次金融交易是否是欺诈 ...

  6. Thread.yeild方法详解

    从原理上讲其实Thread.yeild方法其实只是给线程调度机制一个暗示:我的任务处理的差不多了,可以让给相同优先级的线程CPU资源了:不过确实只是一个暗示,没有任何机制保证它的建议将被采纳: 看一个 ...

  7. JAVA基础之this关键之理解

    突然觉得有几个知识点需要先复习一下 1.引用和对象并不一定要同时存在,可以只有引用,没有对象  :比如声明String  a;如果非得提供一个比喻,可以用电视遥控器和电视来做比喻,遥控器比喻引用,电视 ...

  8. 最全总结 | 聊聊 Python 办公自动化之 PPT(中)

    1. 前言 上一篇文章简单地介绍了 PPT 的文档结构,并使用 python-pptx 这个依赖库完成对 PPT 文档最基本的操作 最全总结 | 聊聊 Python 办公自动化之 PPT(上) 作为 ...

  9. Vue利用v-for渲染时表单信息出不来

    今天在写项目时,Controller的值已经传入到html,但是利用vue进行渲染的时候就是出不来, 原因如下: 注意,in 之前的空格.

  10. 园子的品牌专区上新:NoSQL 数据库佼佼者 Aerospike

    品牌专区是园子去年推出的新楼盘,为优秀的科技企业在园子里提供一个地方,展示自己的品牌,分享自己的技术内容. 最近我们和国外领先的 NoSQL 数据库厂商 Aerospike 达成了合作,入驻了园子的品 ...