Python 中的参数化继承?

Parametrized inheritance in Python?

我很好奇是否有更好的方法来实现这样的目标? 我的意图是避免不必要的样板。提供的示例显然足够简单,足以让其他人理解我的想法。

def create_parametrized_class(animal):
    class SomeClass:
        def __init__(self, name):
            self.name = name

        def __str__(self):
            return "{}: {}".format(animal, self.name)

    return SomeClass

class Cat(create_parametrized_class("Cat")):
    pass

class Dog(create_parametrized_class("Dog")):
    pass

cat = Cat("Micka")
dog = Dog("Rex")
assert str(cat) == "Cat: Micka", "Cats..."
assert str(dog) == "Dog: Rex", "Dogs..."

我假设 type(self).__name__ 在这里是不够的(对于您的示例 classes,该值等于您传入的参数值)。

要在 class 定义时设置每个 class 值,从 Python 3.6 开始,您可以使用 __init_subclass__ classmethod:

class Animal:
    def __init_subclass__(cls, animal_name, **kw):
        super().__init_subclass__(**kw)
        self._animal_name = animal_name

    def __str__(self):
        return "{}: {}".format(self._animal_name, self.name)


class Cat(Animal, animal_name='Cat'):
    pass

class Dog(Animal, animal_name='Dog'):
    pass

__init_subclass__ 为所有新的 subclass 调用,并且您在 class Subclass(...) 行中指定的任何参数都被传递到该方法,让您参数化该特定的 subclass.

我认为你最好使用简单的继承和 class 变量:

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

    def __str__(self):
        return '{}: {}'.format(type(self).name, self.name)

class Cat(Animal):
    name = 'Cat'

class Dog(Animal):
    name = 'Dog'

这对我来说看起来更清晰(特别是如果你有更多的变量而不是一个),并且使用更少的 "advanced" 特征(即阅读你的代码的人不必 google 如何 __init_subclasses__ 有效)。

它也适用于 Python 2 和 3:

>>> cat = Cat('Micka')
>>> print(cat)
'Cat: Micka'

如果您要使用 classproperty,您甚至可以将它默认为 class 的名称,并可以用一个简单的 class 变量覆盖。但是,这可以防止您对 class 和实例变量使用相同的名称,因此您必须使用类似 animal_name:

的名称
class Animal(object):

    @classproperty
    def animal_name(cls):
        return cls.__name__

    def __init__(self, name):
        self.name = name

    def __str__(self):
        return '{}: {}'.format(self.animal_name, self.name)


class Cat(Animal):
    pass

class Dog(Animal):
    animal_name = 'Doggo'

用法示例:

>>> dog = Dog('Mike')
>>> cat = Cat('Bob')
>>> str(dog)
'Doggo: Mike'
>>> str(cat)
'Cat: Bob'