2017-08-03 45 views
4

我很好奇是否有更好的方法來實現這樣的事情?我的意圖是避免不必要的樣板。提供的例子顯然非常簡單,足以讓其他人理解我腦海中的想法。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..." 
+2

什麼Python版本是什麼?看起來像3.6+,因爲Martijn Pieters的回答已經夠了,但是你應該爲其他可能遇到同樣問題的人添加標籤。 '__init_subclass__'在3.6之前不工作。 –

+0

好的,我添加Python 3.6標記。我不知道__init_subclass__,所以我不確定它是什麼Python版本。 –

+0

您應該始終使用您正在使用的版本標記*,以便人們可以基於此提供答案。你可以用'python --version'或'python3 --version' –

回答

8

我要去假定type(self).__name__是不夠這裏(對於你的例子類,數值等於你傳遞的參數值)。

要設置每個類的值在類定義時,像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__被稱爲所有新的子類,並且您在class Subclass(...)指定任何參數行傳入該方法,讓你參數化該特定的子類。

+1

有人想過一個無聊的'返回類型(動物,(SomeClass,),{})'...... –

+1

@MarkusMeskanen:現在明確指出了答案。 –

+0

另外,不是因爲答案很重要,但是因爲我們已經在3.6了,爲什麼不''返回f'{self._animal_name}:{self.name}''; –

1

我覺得你用簡單的繼承和類變量更好:

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' 

這看起來比較清爽,我(尤其是如果你已經不僅僅是一個更多的變量),並使用更少的「先進」的特點(即有人讀你的代碼不必谷歌如何__init_subclasses__工作)。

而且它適用於Python 2和3兩個:

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

如果你使用classproperty,你甚至可以把它默認爲類的名稱,並overriddable用一個簡單的類變量。這可以防止使用相同的名稱爲類和實例變量的,所以你必須使用像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' 
+0

是的,看起來不錯。謝謝。我寧願保留Python 3.6解決方案,因爲我的初衷是要學習新的東西。 :) –