是否有可能在Python中检测冲突的方法名称?

时间:2013-03-10 22:37:09

标签: python inheritance multiple-inheritance python-2.x

我创建了一个名为Liger的Python类,它扩展了一个名为Lion的类和一个名为Tiger的类。类Liger继承了speak()Lion中的方法Tiger,但语法仍然有效 - 不会打印错误消息,而是Tiger speak()方法的实现由Liger继承。是否有可能在Python中检测类似于此的方法名称冲突,以便在方法名称以这种方式冲突时打印错误消息?

'''
Conflicting method names in python
'''


class Tiger():
    @staticmethod
    def speak():
        print "Rawr!";

class Lion():
    @staticmethod
    def speak():
        print "Roar!";

class Liger(Tiger, Lion):
    pass
'''both superclasses define a speak() method, and I need a way to detect this type of conflict.'''    

Liger.speak(); ''' this prints "Rawr" instead of printing an error message. '''
'''Is there any way to detect method name collisions like this one?'''

可以在此处在线测试和调试代码:http://ideone.com/xXOoVq

2 个答案:

答案 0 :(得分:2)

我不确定继承是否是您用来解决问题的正确机制。通常认为继承定义了两个类之间的“IS-A”关系。也就是说,如果A继承自BB的每个实例也都是A的实例。

如果您正在使用多重继承,则该类最终会同时成为多种对象。在您的示例中,Liger实例同时是TigerLion

您可能不希望使用类继承来模拟物种继承。尽管有这个名字,但它们并不意味着同样的事情。例如,家猫可能是一种非常古怪的东西,但是说一只家猫是一只老虎是不正确的。

你在类上使用静态方法的事实让我觉得你可能根本不想使用类,而是更通用的Animal类的实例:

class Animal(object):
    def __init__(self, sound):
        self.sound = sound

    def speak(self):
        print self.sound

lion = Animal("Roar!")

那里没有继承机制,但是可以添加一种方法,以某种方式将一种Animal变异为另一种。

现在,如果您真的开始使用类和多继承,那么有两种不错的方法(使用常规实例方法,而不是静态方法):

第一个是做“协作多重继承”,并让你的每个方法在MRO的下一个类中调用相同的方法。通常,您需要从公共基类继承才能使其工作(否则对super的最后一次调用将获得object,这将不会定义方法):

class Animal(object):
    def speak(self):
        pass

class Lion(Animal):
    def speak(self):
        print("Roar!")
        super(Lion, self).speak()

class Tiger(Animal):
    def speak(self):
        print("Rawr!")
        super(Tiger, self).speak()

class Liger(Lion, Tiger):
    pass

在这种情况下,Liger实例的speak方法会打印Roar然后Rawr,这是有道理的,因为它既是狮子又是老虎。但是要注意这种编码风格,因为让协作正常工作可能很棘手。例如,您无法更改方法签名并期望它在协作多重继承情况下正常工作(除非您仅使用关键字参数,并传递**kwargs中任何未识别的方法)。

第二个解决方案是给Liger它自己的speak实现,它明确地选择要做什么(可能是调用它的一个基类)。这在某些其他语言中是必需的,例如C ++。如果您请求的继承没有按照您的意愿执行,那么它可能是最直接的解决方法:

class Liger(Lion, Tiger):
    def speak(self):
        Tiger.speak(self)

答案 1 :(得分:1)

您可以使用元类检测此类冲突:

class ConflictCheck(type):
    def __new__(meta, name, bases, dct):
        # determine attributes per base class, except for magic ones
        attrs_per_base = [set(a for a in dir(b) if not a.startswith("__"))
                          for b in bases]
        if len(set.union(*attrs_per_base)) < sum(map(len, attrs_per_base)):
            raise ValueError("attribute conflict")
        return super(ConflictCheck, meta).__new__(meta, name, bases, dct)

class Liger(Lion, Tiger):
    __metaclass__ = ConflictCheck  # will raise an error at definition time

这是一个非常粗糙的第一个版本,错误消息很差,只要在继承树中覆盖Liger以上的方法时,实际上就会引发错误,但它应该足以让你开始。