2010-02-28 28 views
2

我目前做这个,做的基于对象的类型不同的东西:按类名切换python?

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]() 
+7

请不要。这是实现多态的可怕方式。 – 2010-02-28 15:43:48

回答

0

什么

actions[obj.__class__]() 
0
actions[type(obj)]() 
1
actions[obj.__class__]() 

作品如果obj是真的的一个子类(比方说)SomeClass,而不是一个实例 - 所以如果可以的情况下,结果将与您目前的处理方式不同。另请注意,如果该类没有相应的操作,则可能会引起KeyError。为了处理这种情况下,你现在做同样的方式(即什么都不做),你可以使用

有一个默认值返回。

哦,听你的问题美国洛特的评论。在很多情况下,有更好的方法来实现这样的事情。例如,您可以让所有课程定义一个do_whatever(self),并且只需拨打obj.do_whatever()即可。

0
results = [func() for cls, func in actions.iteritems() if isinstance(obj, cls)] 

如果您的对象为isinstance为零个或多个class-keys,则会有零个或多个结果。

使用type(obj)关键,如果你的对象是一个类型的才有效。如果它继承树的下面,你会错过它。

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() 

更简单。清晰。更具可扩展性。魔术减少。没有字典。没有循环。

+0

+1。任何暗示“行动”依赖于*两个*对象('类)的情况?这是我在当前项目中遇到的一个问题,我还没有想到比'isinstance'测试更好的方法。 – balpha 2010-02-28 15:55:24

+0

@balpha:他们称之为“双派”。这是相同的基本演习,除了类层次结构A从另一个类中选择一个方法。一是研究“双派”。然后问一个单独的问题,如果你仍然有麻烦。 – 2010-02-28 16:07:20

+0

我认为真正的问题是如何组织Python代码,以便所有的“动作”方法彼此接近,而不是在每个类中植入一个。在Scala中,匹配{}构造可以让你做到这一点,如果你有一个不匹配的类型,甚至会抛出编译时类型错误,所以它似乎是一种可接受的布局多态代码的方式。 – codewarrior 2011-07-04 00:12:34

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... 
+0

用Python的鸭子打字,mixin不是必须的。只要所有类都使用正确的参数集来实现'my_return',它应该可以正常工作。然而,Tor是正确的,拥有一个共同的父类是有帮助的,因为它允许你提供一个默认行为,除非另有说明,否则你的所有类都将遵循。 – jcdyer 2010-02-28 16:32:30

+0

这是我所做的假设,特定类之间存在某种关系。 – 2010-02-28 17:16:47