您的位置:首页 > 编程语言 > Python开发

python中迷信继承

2015-12-21 15:27 746 查看

Python中的mixin混入

最近在用tornado做项目时,发现一个python老手的源码各种多重
继承,请教那位老手为什么这么做,回答说为了方便。确实使用了多重继承在一些场合确实能够很轻松的解决问题,广泛的定义这种多重继承称为mixin混入,
其实严格意义上mixin混入是动态修改类的多重继承的基类。
简单虚拟一个场景来说明多重继承和mixin的运用场景。
比如一个角色权限系统,我们设定所有管理员都具有登录权限,当然可能这个例子有更好的实现方案,姑且用这个例子说明mixin的实现:
class Admin(object):
def getName(self):
print('admin')

class LoginAuth(Admin):
def getLogin(self):
print('login auth')

admin_a = LoginAuth()
admin_a.getName()
admin_a.getLogin()

1、我们定义Admin类,表示是管理员
2、然后定义LoginAuth类,表示管理员具有登录权限
3、实例化 LoginAuth,就能获取登录的权限 getLogin

那现在如果又加入了3个权限,系统管理员,业务管理员,这时我们又需要分别建立三个不同的基类,来处理一个用户是系统管理员,或者是业务管理员,又或者既是系统管理员又是业务管理员了。
class Admin(object):
def getName(self):
print('admin')

class LoginAuth(Admin):
def getLogin(self):
print('login auth')

class SystemAuth(LoginAuth):
def getSystem(self):
print ('system auth')

class BussinessAuth(LoginAuth):
def getBussiness(self):
print ('bussiness auth')

class SystemAndBussinessAuth(SystemAuth,BussinessAuth):
pass

admin_a = SystemAndBussinessAuth()
admin_a.getName()
admin_a.getLogin()
admin_a.getSystem()
admin_a.getBussiness()
至此,增加了2种权限,我们增加了3个类,如果我们有10种权限,甚至更多那么我们是不是要把所有的排列组合的可能性都列出来,写上N多个派生类呢?
这时候动根据用户的属性,动态的修改继承的基类就会变的很便捷,还是上面的例子,一开始我们不知道访问的管理员具有什么权限。比如:用户访问进来之后,我们才得知,用户是具有 系统管理员、业务管理员权限和会员管理员的人,会员管理员将会根据会员的年龄做出不通的权限设置,代码如下:


# -*- coding: utf-8 -*-
class Admin(object):
def getName(self):
print('admin')

class LoginAuth():
age = 18
def getLogin(self):
print('login auth')

class SystemAuth():
def getSystem(self):
print ('system auth')

class BussinessAuth():
def getBussiness(self):
print ('bussiness auth')

class MemberAuth():
def getMember(self):
if self.age <18:
print ('child member auth')
else:
print ('adult member auth')

Admin.__bases__ += (LoginAuth,SystemAuth,BussinessAuth,MemberAuth,)

admin_a = Admin()
admin_a.getName()
admin_a.getLogin()
admin_a.getSystem()
admin_a.getBussiness()
admin_a.getMember()

运行上述代码之后,将会打印出如下信息:


admin
login auth
system auth
bussiness auth
adult member auth

我们关注这段代码:
class MemberAuth():    def getMember(self):        if self.age <18:            print ('child member auth')        else:            print ('adult member auth')
你会发现我们在这个MemberAuth类中根本就没有继承或者定义age属性,但是因为混入技术,可以直接拿其他基类的LoginAuth的age属性来判断,这样的代码在c++中是编译都过不了的。

python的这种灵活性给我们写项目时带来了一些便利,比如老板要对某一些情况,增加一个功能,我们甚至无须修改原有的代码,直接在运行时动态添加一个继承类到基类中,这样直接实例中就可以使用了,而且这个动态添加的继承类还能调用原有其他基类的属性和方法,而无需事先定义它。

但是mixin混入技术也有显著的不足之处:
1、编辑器无法通过联想获取实例的方法,通俗点就是,我们不能通过输入 "." 来让编辑器联想当前实例所具有的属性和方法了,因为这是运行时决定的,所以编辑器无能为力了,只能自己手动写。
2、如果几个不相干的类被mixin混入,那么其他人拿到你的代码,开始看你的混入类定义会比较迷茫,明明没有定义的属性和方法,怎么可以在类中随处调用。
3、动态混入肯定不是没有开销的,它的执行性能必然没有直接多重继承来的好,下面是测试代码:
# -*- coding: utf-8 -*-
import time

class Admin(object):
def getName(self):
print('admin')

class LoginAuth():
age = 18
def getLogin(self):
print('login auth')

class SystemAuth():
def getSystem(self):
print ('system auth')

class BussinessAuth():
def getBussiness(self):
print ('bussiness auth')

class MemberAuth():
def getMember(self):
if self.age <18:
print ('child member auth')
else:
print ('adult member auth')

class Admin1(Admin,LoginAuth,SystemAuth):
pass
class Admin2(Admin,LoginAuth,BussinessAuth):
pass
class Admin3(Admin,LoginAuth,SystemAuth,BussinessAuth):
pass
class Admin4(Admin,LoginAuth,SystemAuth,MemberAuth):
pass
class Admin5(Admin,LoginAuth,SystemAuth,MemberAuth):
pass
class Admin6(Admin,LoginAuth,SystemAuth,BussinessAuth,MemberAuth):
pass

now1 = float(time.time())
for i in range(100000):
if i % 6 ==0:
admin_a = Admin1()
elif i % 6 ==1:
admin_a = Admin2()
elif i % 6 ==2:
admin_a = Admin3()
elif i % 6 ==3:
admin_a = Admin4()
elif i % 6 ==4:
admin_a = Admin5()
elif i % 6 ==5:
admin_a = Admin6()
now2 = float(time.time())
print 'instance {0}s'.format(round(now2-now1,4))

now1 = float(time.time())
for i in range(100000):
Admin.__bases__ = (object,)
if i % 6 ==0:
Admin.__bases__ += (LoginAuth,SystemAuth,)
elif i % 6 ==1:
Admin.__bases__ += (LoginAuth,BussinessAuth,)
elif i % 6 ==2:
Admin.__bases__ += (LoginAuth,SystemAuth,BussinessAuth,)
elif i % 6 ==3:
Admin.__bases__ += (LoginAuth,SystemAuth,MemberAuth,)
elif i % 6 ==4:
Admin.__bases__ += (LoginAuth,BussinessAuth,MemberAuth,)
elif i % 6 ==5:
Admin.__bases__ += (LoginAuth,SystemAuth,BussinessAuth,MemberAuth,)
admin_a = Admin()
now2 = float(time.time())
print 'mixin {0}s'.format(round(now2-now1,4))
最后的执行结果震惊了:
instance 0.049s
mixin 43.457s
mixin混入技术还是慎用的比较好,多重继承已经够用了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: