【问题标题】:How to specify which __init__ should be called based on the parameters?如何根据参数指定调用哪个__init__?
【发布时间】:2018-04-30 11:05:13
【问题描述】:

所以我最近开始学习 python,现在我被一个任务困住了,我应该实现一个 UML 图。 它看起来像这样:

基本上是模特儿、成人、儿童和退休人士。现在我被卡住的部分是任务是一个参数说“alter”(eng.=age)定义应该初始化哪个类。 18 岁以下的人(alter

现在我的问题是我不知道如何实现这种区分......

这是我目前所拥有的:

class Person:
    def __init__(self, name, male, alter):
        self.name = name
        self.male = male
        self.__alter = alter

    def print_beschreibung(self):
        if self.male:
            print("Ich heiße " + self.name + ", bin männlich,", self.__alter, "Jahre alt")
        else:
            print("Ich heiße " + self.name +  ", bin weiblich,", self.__alter, "Jahre alt")    

    def get_alter(self):
        return self.__alter    

    def set_alter(self, neues_alter):
        self.__alter = neues_alter

class Erwachsener(Person):
    def __init__(self, name, male, alter, lohn, ist_verheiratet, kinder):
        super().__init__(name, male, alter)
        self.__lohn = lohn
        self.ist_verheiratet = ist_verheiratet
        self.kinder = kinder    


peter = Person("Peter Lustig", True, 52)
peter.print_beschreibung()

【问题讨论】:

  • 您是说Person 构造函数应该根据人的年龄返回相应子类的实例?所以peter 会是Erwachsener
  • 没错,从来没有这样想过。构造函数可以有return语句吗?
  • 但这不起作用。您只将 3 个参数传递给构造函数:Person("Peter Lustig", True, 52),但 Erwachsener 构造函数需要更多参数:name, male, alter, lohn, ist_verheiratet, kinder。您必须像 Person('Peter Lustig', True, 52, 12345, False, 0) 这样调用构造函数。

标签: python python-3.x class inheritance uml


【解决方案1】:

有不同的方法来实现这种行为。最简单的方法是拥有一个与您当前的Person 类相同的_Person 类:

class _Person:
    def __init__(self, name, male, alter):
        self.name = name
        self.male = male
        self.__alter = alter

    def print_beschreibung(self):
        if self.male:
            print("Ich heiße " + self.name + ", bin männlich,", self.__alter, "Jahre alt")
        else:
            print("Ich heiße " + self.name + ", bin weiblich,", self.__alter, "Jahre alt")

    def get_alter(self):
        return self.__alter

    def set_alter(self, neues_alter):
        self.__alter = neues_alter


class Kind(_Person):
    pass


class Erwachsener(_Person):
    def __init__(self, name, male, alter, lohn, ist_verheiratet, kinder):
        super().__init__(name, male, alter)
        self.__lohn = lohn
        self.ist_verheiratet = ist_verheiratet
        self.kinder = kinder


class Pensionierter(_Person):
    pass

然后你有一个函数Person,它的行为类似于一个类并返回一个对应的ErwachsenerKindPensionierter 类:

def Person(*args, **kwargs):
    alter = args[2]
    if alter < 18:
        return Kind(*args, **kwargs)
    elif 18 <= alter <= 61:
        return Erwachsener(*args, **kwargs)
    else:
        return Pensionierter(*args, **kwargs)

那么你可以像这样使用这个函数:

peter = Person("Peter Lustig", True, 52, 0, False, 0)
print(isinstance(peter, Erwachsener))
peter.print_beschreibung()

如果你想让Person 成为一个班级,你将不得不做一些魔法:

class Person:
    def __new__(cls, *args, **kwargs):
        alter = args[2]
        if alter < 18:
            cls = Kind
        elif alter < 61:
            cls = Erwachsener
        else:
            cls = Pensionierter
        return object.__new__(cls)
     # The rest of the class

那么就可以像上面那样使用了:

peter = Person("Peter Lustig", True, 52,0,False,0)
print(isinstance(peter, Erwachsener)) # prints True
peter.print_beschreibung()

但你也可以这样:

print(isinstance(peter, Person)) # prints True

【讨论】:

  • 我不喜欢这个解决方案。人们会认为Person 是一个类,即使它不是。如果有人尝试像isinstance(peter, Person) 一样使用它,他们会收到错误消息。我认为将此功能合并到类中而不是将其导出到单独的函数中会更好。
  • @Aran-Fey 公平点。但我不介意这个答案的逻辑。我会保留原来的 Person 类并拥有一个 make_person 工厂函数,因此从名称中可以清楚地看出它不是一个类。但我也有兴趣看到替代解决方案。
  • 就个人而言,我会将其实现为Person.from_age 类方法。
  • @Aran-Fey 我添加了另一个建议。这样更好吗?
  • 是的,我认为__new__ 解决方案在这种情况下很好。一般来说,如果构造函数返回子类的实例可能会造成混淆,但在这种情况下,我认为这是可以接受的,因为Person 看起来像一个抽象类。
猜你喜欢
  • 2018-01-02
  • 1970-01-01
  • 2010-09-13
  • 2018-11-12
  • 1970-01-01
  • 1970-01-01
  • 2012-02-13
相关资源
最近更新 更多