除了超类之外,两个Python类相同 - 如何避免重复?

时间:2013-04-16 01:36:02

标签: python oop inheritance

我在Python类(classa)中包含了一些功能。 classa继承自另一个班级supera

除了我想从classa继承之外,我想要与superb完全相同的功能。

我可以将类classa复制到新的类classb,然后更改classb的超类,但显然这非常俗气,维护很头疼,而且我很确定有更好的方法 - 谁能告诉我它是什么?


编辑:到目前为止,感谢您的回答。我应该首先说我的classa在其方法中调用super来调用supera方法。在将mixins视为一种选择时,这似乎有一些意义

1 个答案:

答案 0 :(得分:4)

如果没有一个方法需要调用super(),可以使用Python的多重继承来完成。

class Dog(object):
    name = "Spot"

class Cat(object):
    name = "Whiskers"

class SpeakingAnimalMixin(object):
    def speak(self):
        print "My name is", self.name, "and I can speak!"

class SpeakingDog(SpeakingAnimalMixin, Dog):
    pass

class SpeakingCat(SpeakingAnimalMixin, Cat):
    pass

SpeakingDog().speak()
  

我的名字是Spot,我可以说!


如果确实需要从方法中调用super(),则需要动态创建类。这样可以正常工作,但生成的类的名称不太有用,IDE和其他静态分析工具可能没那么有用。

您可以使用函数创建类,将超类作为参数传递:

def make_speaking_animal_class(SpeechlessAnimal):
    class SpeakingAnimal(SpeechlessAnimal):
        def get_name(self):
            return "Speaking " + super(SpeakingAnimal, self).get_name()

        def speak(self):
            print "My name is", self.get_name()

    return SpeakingAnimal

class Dog(object):
    def get_name(self):
        return "Spot"

class Cat(object):
    def get_name(self):
        return "Whiskers"

SpeakingDog = make_speaking_animal_class(Dog)
SpeakingCat = make_speaking_animal_class(Cat)

SpeakingCat().speak()
  

我的名字是Speaking Whiskers

但是如上所述,班级的__name__属性可能不是您所期望的。

print SpeakingDog
print SpeakingDog()
<class '__main__.SpeakingAnimal'>
<__main__.SpeakingAnimal object at 0x1004a3b50>

您可以自行为其分配唯一的__name__属性来解决此问题:

SpeakingDog.__name__ = 'SpeakingDog'
print SpeakingDog
<class '__main__.SpeakingDog'>

(感谢Andrew Jaffe在答案中建议这一点,但他删除了它。)

还有另一种动态创建类的方法,但除非你需要,否则我不鼓励你使用它;它甚至不太清楚。除了确定对象类的主要内容之外,The type function还有第二种用途:它可用于动态创建新类。

以这种方式使用时,type函数有三个参数:

  • name,新课程的__name__
  • bases,新类将继承的基类元组。
  • dict,一个包含新类将具有的方法和属性的字典。

您可以像这样使用它:

def make_speaking_animal_class(SpeechlessAnimal, name):
    def get_name(self):
        return "Speaking " + super(SpeakingAnimal, self).get_name()

    def speak(self):
        print "My name is", self.get_name()

    bases = (SpeechlessAnimal,)

    # We need to define SpeakingAnimal in a variable so that get_name can refer
    # to it for the super() call, otherwise we could just return it directly.
    SpeakingAnimal = type(name, bases, {
        'get_name': get_name,
        'speak': speak
    })

    return SpeakingAnimal

class Dog(object):
    def get_name(self):
        return "Spot"

class Cat(object):
    def get_name(self):
        return "Whiskers"

SpeakingDog = make_speaking_animal_class(Dog, 'SpeakingDog')
SpeakingCat = make_speaking_animal_class(Cat, 'SpeakingCat')

SpeakingDog().speak()
SpeakingCat().speak()
  

我的名字是Speaking Spot
  我的名字是Speaking Whiskers