在Python中可以检测到冲突的方法名吗?

2024-06-02 08:30:28 发布

您现在位置:Python中文网/ 问答频道 /正文

我创建了一个名为Liger的Python类,它扩展了一个名为Lion的类和一个名为Tiger的类。类LigerLion和{}继承了方法speak(),但是语法仍然有效-不会打印错误消息,而是,Tiger方法的实现由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


Tags: 方法消息def错误thismethodwayclass
2条回答

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

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上重写一个方法时,它实际上会引发一个错误,但它应该足以让您开始。在

我不确定继承是否是解决问题的正确机制。继承通常被称为定义两个类之间的“is-A”关系。也就是说,如果AB继承,B的每个实例也是{}的实例。在

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

您可能不想使用类继承来建模物种继承。尽管有名字,但它们的意思并不完全相同。例如,家猫可能是虎类动物的后代,但是说家猫是老虎是不对的。在

您在类上使用静态方法的事实使我认为您可能根本不想使用类,而是使用更通用的Animal类的实例:

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

    def speak(self):
        print self.sound

lion = Animal("Roar!")

那里没有遗传机制,但是可以增加一种方法,以某种方式使一种动物变异成另一种动物。在

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

第一种方法是执行“协作多重继承”,并让每个方法在MRO的下一个类上调用相同的方法。通常,您需要从公共基类继承来实现这一点(否则,对super的最后一次调用将得到object,它没有定义方法):

^{pr2}$

在这种情况下,Liger实例的speak方法将同时打印Roar,然后Rawr,这是有意义的,因为它同时是狮子和老虎。不过,要小心这种编码方式,因为要使协作正常工作是很困难的。例如,您不能更改方法签名并期望它在协作的多重继承情况下正常工作(除非您只使用关键字参数,并且在**kwargs中传递任何未识别的参数)。在

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

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

相关问题 更多 >