隐藏页面特效

混合类Mixins介绍

介绍

混合类是封装了一些通用行为的基类,旨在重用代码。通常,混合类本身并没有什么用,仅扩展这种类也行不通 因为在大多数情况下,它都依赖于其它类中定义的方法和属性。通过多继承,可将混合类与其它类一起使用,从而 让混合类的方法或属性变得可用。

示例

假设有一个简单的分析器,它接收一个字符串,并迭代该字符串中由连字符(-)分隔的值: class BaseTokenizer: def __init__(self, str_token): self.str_token = str_token def __iter__(self): yield from self.str_token.split("-") >>> tk = BaseTokenizer("28a2320b-fd3f-4627-9792-a2b38e3c46b0") >>> list(tk) ['28a2320b', 'fd3f', '4627', '9792', 'a2b38e3c46b0']

拓展上述需求

现在我们要在不修改这个基类的情况下,以大写的方式发送各个值,就这个简单的示例而言, 可创建一个新类,但假设有大量的类拓展了BaseTokenizer,而我们又不想替换所有这些类。 为此,可在层次结构中混入一个处理这种变化的新类: class UpperIterableMixin: def __iter__(self): return map(str.upper, super().__iter__()) class Tokenizer(UpperIterableMixin, BaseTokenizer): pass 新的Tokenizer类非常简单,不需要有任何代码,因为它利用了混合类。这种混合类相当于一个装饰器。从前面 的介绍可知,Tokenizer从混合类那里获得方法__iter__,而这个方法通过调用supper()将职责委托给了下一个类 BaseTokenizer,同时将返回的值转换为答谢,从而实现了所需的效果。

示例

假设你想扩展映射对象,给它们添加日志,唯一性设置,类型检查等功能,下面是一些混入类 class LoggedMappingMixin: __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: __slots__ = () def __setitem__(self, key, value): if key in self: raise KeyError(str(key) + 'already set') return super().__setitem__(key, value) class StringKeysMappingMixin: __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)

讨论

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

__EOF__

本文作者404 Not Found
本文链接https://www.cnblogs.com/weiweivip666/p/17296154.html
关于博主:可能又在睡觉
版权声明:转载请注明出处
声援博主:如果看到我睡觉请喊我去学习
posted @   我在路上回头看  阅读(50)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
历史上的今天:
2021-04-07 将模型对象转换为json字典:model_to_dict
点击右上角即可分享
微信分享提示