混合类Mixins介绍
Posted 洗洗睡吧
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了混合类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
-------------------------------------------
个性签名:代码过万,键盘敲烂!!!
如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!
vue中mixins的理解及应用
vue中提供了一种混合机制--mixins,用来更高效的实现组件内容的复用。最开始我一度认为这个和组件好像没啥区别。。后来发现错了。下面我们来看看mixins和普通情况下引入组件有什么区别?
mixins
混合 (mixins) 是一种分发 Vue 组件中可复用功能的非常灵活的方式。
混合对象可以包含任意组件选项。
当组件使用混合对象时,所有混合对象的选项将被混入该组件本身的选项。
mixins理解
组件在引用之后相当于在父组件内开辟了一块单独的空间,来根据父组件props过来的值进行相应的操作,单本质上两者还是泾渭分明,相对独立。
而mixins则是在引入组件之后,则是将组件内部的内容如data等方法、method等属性与父组件相应内容进行合并。相当于在引入后,父组件的各种属性方法都被扩充了。
- 单纯组件引用:
父组件 + 子组件 >>> 父组件 + 子组件 - mixins:
父组件 + 子组件 >>> new父组件
有点像注册了一个vue的公共方法,可以绑定在多个组件或者多个Vue对象实例中使用。另一点,类似于在原型对象中注册方法,实例对象即组件或者Vue实例对象中,仍然可以定义相同函数名的方法进行覆盖,有点像子类和父类的感觉。
mixins的使用
方法的复用
html
<div id="app"> <child></child> <kid></kid> </div>
js
Vue.component(‘child‘,{ template:`<h1 @click="foo">child component</h1>`, methods:{ foo(){ console.log(‘Child foo()‘+this.msg++) } } }) Vue.component(‘kid‘,{ template:`<h1 @click="foo">kid component</h1>`, methods:{ foo(){ console.log(‘Kid foo()‘+this.msg++) } } })
在借助mixins之前,在两个不同的组件的组件中调用foo方法,需要重复定义,倘若方法比较复杂,代码将更加冗余。若借助mixins,则变得十分简单:
let mixin={ data(){ return{ msg:1 } }, methods:{ foo(){ console.log(‘hello from mixin!----‘+this.msg++) } } } var child=Vue.component(‘child‘,{ template:`<h1 @click="foo">child component</h1>`, mixins:[mixin] }) Vue.component(‘kid‘,{ template:`<h1 @click="foo">kid component</h1>`, mixins:[mixin] })
虽然此处,两个组件用可以通过this.msg引用mixins中定义的msg,但是,小编尝试过,两个组件引用的并不是同一个msg,而是各自创建了一个新的msg。如果在组件中定义相同的data,则此处会引用组件中的msg,而非mixins中的。
方法的覆盖
如果在引用mixins的同时,在组件中重复定义相同的方法,则mixins中的方法会被覆盖。
var child=Vue.component(‘child‘,{ template:`<h1 @click="foo">child component</h1>`, mixins:[mixin], methods:{ foo(){ console.log(‘Child foo()‘+this.msg++) } } })
此时,若单击h1标签,则在控制台中打印"Child foo() 1" 3、合并生命周期此时,若单击h1标签,则在控制台中打印"Child foo() 1"
合并生命周期
let mixin={ mounted(){ console.log(‘mixin say hi‘)//先输出 }, data(){ return{ msg:1 } }, methods:{ foo(){ console.log(‘mixin foo()‘+this.msg++) } } } let vm=new Vue({ el:"#app", data:{ msg: 2 }, mounted: function(){ console.log(‘app say hi‘)//后输出 }, methods:{ foo(){ console.log(‘Parent foo()‘+this.msg) } } })
通过上面的介绍,现在对mixins有了比较深入的了解,在设计复杂组件时是很有必要的。
实践:状态码统一过滤
一般情况下不要全局使用,因为会污染vue所有实例,这里通过一个简单的应用展示mixin的使用技巧,在所有vue实例中添加统一状态码过滤器。
因为自定义方法会在所有的实例中混入,如果按照以前的方法,难免会有覆盖原先的方法的危险,按照官方的建议,混入的自定义方法名增加前缀 $_ 用作区分。
创建一个 config.js 文件,用于保存状态码对应的含义,将其暴露出去
export const typeConfig = { 1: "type one", 2: "type two", 3: "type three" }
再创建一个 filters.js 文件,用于保存所有的自定义函数
import { typeConfig } from "./config" export default { filters: { $_filterType: (value) => { return typeConfig[value] || "type undefined" } } }
最后,在 main.js 中引入我们的 filters 方法集
import filter from "./filters"
Vue.mixin(filter)
接下来,我们就可以在 .vue 的模板文件中随意使用自定义函数了
<template> <div>{{typeStatus | $_filterType}}<div> </template>
包装插件
接下来简单应用一下 Vue
中插件的制作方法。创建插件之后,就可以 Vue.use(myPlugin)
来使用了。
首先附上插件的 官方文档[点我查看]。
一句话解释,包装的插件需要一个 install
的方法将插件装载到 Vue
上。
关于 Vue.use() 的源码
function initUse (Vue) { Vue.use = function (plugin) { var installedPlugins = (this._installedPlugins || (this._installedPlugins = [])); if (installedPlugins.indexOf(plugin) > -1) { return this } // additional parameters var args = toArray(arguments, 1); args.unshift(this); if (typeof plugin.install === ‘function‘) { plugin.install.apply(plugin, args); } else if (typeof plugin === ‘function‘) { plugin.apply(null, args); } installedPlugins.push(plugin); return this }; }
很直观的就看到他在最后调用了 plugin.install 的方法,我们要做的就是处理好这个 install 函数即可。
config.js 文件依旧需要,这里保存了所有状态码对应的转义文字
创建一个 myPlugin.js 文件,这个就是我们编写的插件
import { typeConfig } from "./config" myPlugin.install = (Vue) => { Vue.mixin({ filters: { $_filterType: (value) => { return typeConfig[value] || "type undefined" } } }) } export default myPlugin
插件的 install 函数的第一个参数为 Vue 的实例,后面还可以传入一些自定义参数。
在 main.js 文件中,我们不用 Vue.mixin() 转而使用 Vue.use() 来完成插件的装载。
import myPlugin from "./myPlugin"
Vue.use(myPlugin)
至此,我们已经完成了一个小小的插件,并将我们的状态码转义过滤器放入了所有的 Vue 实例中,在 .vue 的模板文件中,我们可以使用 {{ typeStatus | $_filterType }} 来进行状态码转义了。
Vue.mixin() 可以将自定义的方法混入所有的 Vue 实例中,谨慎使用。
转载链接:https://www.jianshu.com/p/a72bf060eeaa
以上是关于混合类Mixins介绍的主要内容,如果未能解决你的问题,请参考以下文章