Pythonic方法减少基类中的小子类数量?

时间:2014-10-24 22:43:04

标签: python inheritance subclass

我发现自己为预定义的对象编写了许多小子类。但是,我创建的每个子类都包含许多重复的代码(用于基类实例化)。本质上,我使用子类来存储特定于子类的默认初始化属性,以及基类的通用属性。

使用许多只有 init ()的小子类是否可以接受使用子类?

例如: 我创建了一个包含基类和子类的模块(我有30个子类,参数和默认参数略有不同)。

#animals.py
#Contains animal definitions and methods
class Animal(object):
    def __init__(self, name, weight, cute=False, kind=None, image=None):
        #Instantiation attributes
        self.name = name
        self.weight = weight
        self.cute = cute
        self.kind = kind
        self.image = image
        #Attributes common to all animals
        self.extinct = False

    def get_animal_stats(self):
        print arbitrary_animal_stat

class Dog(Animal):
    def __init__(self, name, weight, kind="Mixed Breed"):
        Animal.__init__(self, name, weight, cute=True, kind=kind, image="dog.com")

class Cat(Animal):
    def __init__(self, name, weight):
        Animal.__init__(self, name, weight, cute=True, image="cat.com")

通过一般Animal类或更具体的预定义动物子类在其他模块中创建实例(选项卡完成是必不可少的,因此我可以引用特定的动物子类)。

import animals    #Uses animal definitions from animals.py

my_animals = [
    animals.Animal("Python", 2.7, cute=False),
    animals.Dog("Snoopy", 60, kind="Cartoon"),
    animals.Cat("Tigger", 50, kind="Tiger"),]

for animal in my_animals:
    animal.get_animal_stats()

我发现使用具有许多预定义子类的基类可以创建更明确的代码,并允许将来扩展。但是,这会产生大量重复的代码,而且我目前没有子类的独特方法。感觉就像是不正确地使用了分类?

我尝试使用变量来替换子类定义。如果我想修改任何内容,这很麻烦,因为我必须记住默认值及其顺序,并且看起来不如子类化。

#Use of variables instead of subclasses
dog = ("True", "Mixed Breed", "dog.com")

Animal("default dog", 60, *animals.dog)
Animal("special dog", 60, cute=False, kind="Guard Dog", image=animals.dog[2])

字典几乎同样麻烦,因为它们的定义中存在与等效子类一样多的重复代码,并且它看起来不如更强大的子类对应字段。

#Use of dictionaries instead of subclasses
dog = {"cute": True, "kind": "Mixed Breed", "image": "dog.com"}

Animal("default dog", 60, **animals.dog)
Animal("special dog", 60, cute=False, kind="Guard Dog", image=animals.dog["image"])

我应该在这种情况下重新考虑使用子类吗?如果是这样,Pythonic的方法是什么?

我应该考虑@classmethod还是@staticmethod?我理解他们在理论上做了什么,但不知道如何/何时实施它们。


其他问题:

谢谢大家的回答。我在回复之前已多次阅读它们,并提出了一些略微修改过的例子,以澄清仍未找到的概念。我是StackOverflow的新手并以这种方式做出回应,以便我可以详细说明。如果这是对“编辑”的不当使用,请告诉我如何继续。

- 我认为你觉得子类化在这种情况下是可以接受的吗?

- 我喜欢你的类变量技术。我计划实现它。

- 我认为你使用** kwargs有希望,但没有引用源animals.py',你怎么知道在初始化子类时父类中哪些键值对是有效的?在实例化子类时,它们在上下文中不可用。

- 我考虑为每个子类定义一组默认的** kwargs,类似于你的类变量技术。但是,我不完全理解如果我超过键值然后输入** kwargs(其中相同的键在** kwargs中定义)会发生什么。

class Dog(Animal):
    WOOF, YAP, HUSH = 'woof', 'yap', 'hush_puppy'
    kwargs = {cute: True, kind: "Generic", image_path: "dog.com"}
    def __init__(self, name, weight, bark=WOOF, **kwargs):
        self.bark = bark
        super(Dog, self).__init__(name, weight, **kwargs)


dog1 = Dog("Snoopy", 60, **Dog.kwargs)
dog2 = Dog("Otis", 30, bark=Dog.YAP, cute=False, **Dog.kwargs)

这是有效的语法吗? Dog.kwargs中的cute = True会不会让我在实​​例化中设置cute = False?

关于分类学的有趣观点。幸运的是,我确实拥有有限数量的子类(我不需要保持专业化),而对于我的使用,通过Animal基类创建Dog不是类型(Dog)是可以接受的。

考虑到这一点,还需要考虑其他任何概念吗?

3 个答案:

答案 0 :(得分:2)

我会使用super和** kwargs并添加任何仅与该子类相关的特定属性。

class Dog(Animal):
    WOOF, YAP, HUSH = 'woof', 'yap', 'hush_puppy'
    def __init__(self, name, weight, bark=WOOF, **kwargs):
        self.bark = bark
        super(Dog, self).__init__(name, weight, **kwargs)

class Cat(Animal):
    HAIR_LONG, HAIR_SHORT = 'long', 'short'
    def __init__(self, name, weight,hair=HAIR_LONG, **kwargs):
        self.hair = hair
        super(Cat, self).__init__(name, weight, **kwargs)

dog = Dog("Snoopy", 60, bark=Dog.HUSH)
cat = Cat("Tigger", 50, kind="Tiger",hair=Cat.HAIR_SHORT)

答案 1 :(得分:0)

这一点,它不会创建子类来定义所有动物,但它确实提供了一种方法来定义它们的代码远远少于子类化。由于您无论如何都要在其他模块中创建子类的实例,您可以在其中指定实例化的功能,因此可能会以这种方式执行此操作。我正在使用**kwargs

你只有Animal基类,你只需创建它的实例,命名恰当,并填充定义属性(在任何情况下你会在其他模块中看到它?)。

class Animal(object):
    def __init__(self, **kwargs):
        self.features = {k:v for k, v in kwargs.items()}

创建一只狗:

>>> dog = Animal(name="Rover", kind="mixed breed", weight="10kg")
>>> print dog.features['name']
Rover
>>> print dog.features['kind']
mixed breed

或猫:

 >>> cat = Animal(name="Shredder", kind="tabby", cute="True")
 >>> print cat.features['name']
 Shredder

答案 2 :(得分:0)

您对Animal基类的专业化方式没有任何异常错误,但您正在使用为少量实用分类(与实现代码行为相关)而设计的分类系统(Python类和继承)并将其扩展为本体分类系统/分类法。

这意味着会有一些粗略的观点,偶尔的特质/违反直觉的结果/破坏。例如,如果您可以将Fido实例化为Animal而不是Dog,那么您将无法使用此结构来推理Fido。即使Fido是一只狗,isinstnace(fido, Dog)也会回答False。 Python只是没有足够丰富的分类结构来密切代表自然界中发现的变化。大多数语言都没有,但像CLOSProlog这样的语言可能会开始接近它。

这不是第一次出现这样的问题。 This recent question on programmers.stackexchange.com只是stackoverflow上更多关于程序理论的姐妹网站讨论的许多相关类层次结构挑战之一。


这里的第二个问题是关于简单,简洁的价值设定,而不是Python类分类法的相对弱点。您的问题和一些答案经历了各种选择:在每个子类中使用自定义__init__方法,使用纯粹的kwarg设置风格,基于类的准枚举等。它们都有优点和缺点。当我遇到类似问题时,基于委托的模型已被证明是有帮助的。而不是在此重述它,this is the relevant Stack Overflow answer,以及实现它的配置包:options