我目前正在这样做,根据对象的类型做不同的事情:
actions = {
SomeClass: lambda: obj.name
AnotherClass: lambda: self.normalize(obj.identifier)
...[5 more of these]...
}
for a in actions.keys():
if isinstance(obj, a):
return actions[a]()
是否可以删除for循环,并执行类似的操作?
actions[something to do with obj]()
答案 0 :(得分:6)
class SomeClass( object ):
....
def action( self ):
return self.name
class AnotherClass( object ):
....
def action( self ):
return self.normalize( self.identifier )
[5 more classes like the above two]
a.action()
简单。清晰。更具扩展性。减少魔法。没有字典。没有循环。
答案 1 :(得分:1)
actions[obj.__class__]()
如果obj
实际上是({)SomeClass
的实例而不是子类的实例,则有效 - 所以如果可能是这种情况,结果将与您当前处理它的方式不同。另请注意,如果类没有相应的操作,则可能会引发KeyError
。要像现在一样处理这种情况(即什么也不做),你可以使用
actions.get(obj.__class__, lambda: None)
返回默认值。
哦,听听S.Lott对你问题的评论。在许多情况下,有更好的方法来实现这样的事情。例如,您可以让所有课程定义do_whatever(self)
,然后致电obj.do_whatever()
。
答案 2 :(得分:1)
我假设你有所有这些的父类,或者至少是一个mixin。在父或mixin中放置一个默认的返回函数,然后在那些不同的函数中覆盖它...这是唯一正确的方法。
当然,它会产生额外的代码,但至少它是封装的,可扩展的。假设您想为另外五个课程添加支持。不要在那里改变代码,只需将正确的代码添加到新类中。从它的外观来看,它是每个类两行(函数定义和返回行)。那不错,是吗?
如果obj
不是包含返回函数的类,则会引发异常,您可以通过干净的良心捕获并忽略该异常。
class MyMixin:
def my_return(self, *args):
return self.name
... possibly other things...
class SomeClass(MyMixin):
... no alteration to the default ...
class AnotherClass(MyParent, MyMixin):
def my_return(self, *args):
return args[0].normalize(self.identifier)
... blabla
# now, this is in the caller object...
try:
rval = obj.my_return(self) # this is the caller object 'self', not the 'self' in the 'obj'
#dosomething with rval
except Exception:
pass #no rval for this object type, skipping it...
答案 3 :(得分:0)
怎么样?
actions[obj.__class__]()
答案 4 :(得分:0)
actions[type(obj)]()
答案 5 :(得分:0)
results = [func() for cls, func in actions.iteritems() if isinstance(obj, cls)]
如果您的对象isinstance
为零或更多类密钥,则会有零个或多个结果。
使用type(obj)
作为键只有在您的对象属于该类型时才有效。如果继续在继承树下面,你会错过它。