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