【问题标题】:How do I get rid of unneeded parameters in a class initiation?如何摆脱课堂启动中不需要的参数?
【发布时间】:2017-07-20 19:24:01
【问题描述】:

所以我试图在 Python 中掌握 OOP 的窍门。我遇到的问题是在为子类初始化对象时,我仍然需要输入我不需要的信息。

具体来说,我正在尝试创建一个 Person 对象,而无需指定 can_speak。所以我可以这样做:

John = person("John Anderson")

无需在初始化过程中输入can_speak

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

class Dog(Animal):
    pass

class Person(Animal):
    def __init__(self, name, can_speak):
        self.name = name
        self.can_speak = True

Bob = Person("Bob the Builder", 3.141)
print(Bob.name)
print(Bob.can_speak)
# Bob the Builder
# True

Sam = Dog("Sam the Mutt", 0.00059)
print(Sam.name)
print(Sam.can_speak)
# Sam the Mutt
# False

在这里,我必须将一些内容作为第二个输入放入初始化中,否则会出错。像这样浪费。

【问题讨论】:

  • def __init__(self, name, can_speak=False): 默认参数。
  • 不必如果已修复,则必须将can_speak 作为参数:只需def __init__(self, name):

标签: python python-3.x oop


【解决方案1】:

您确实不必为对象的每个属性添加参数。您可以简单地在Animal 级别填写它,然后在Person 级别覆盖它,例如:

class Animal(object):
    def __init__(self, name):  # look ma, no can_speak parameter
        self.name = name
        self.can_speak = False

class Dog(Animal):
    pass

class Person(Animal):
    def __init__(self, name):   # look ma, no can_speak parameter
        super().__init__(name)  # perform a super call
        self.can_speak = True   # override the can_speak

您只需要添加一个参数,如果这样的对象应该如何构造取决于输入

另外请注意,您确实不必将这样的属性添加到对象。您可以将属性附加到类,或定义方法。例如:

class Animal(object):

    can_speak = False

    def __init__(self, name):  # look ma, no can_speak parameter
        self.name = name

class Dog(Animal):
    pass

class Person(Animal):

    can_speak = True

现在我们存储Animal 是否可以类中讲话。这将导致更少的内存使用,而我们仍然可以得到动物是否会说话:

>>> a = Animal('foo')
>>> a.can_speak
False
>>> p = Person('bar')
>>> p.can_speak
True

然而,我们仍然可以为单个狗添加属性can_speak(例如,在比利时,有一个关于虚构会说话的狗名叫Samson的电视节目) :

>>> samson = Dog('Samson')
>>> samson.can_speak = True
>>> samson.can_speak
True
>>> foo = Dog('other dog')
>>> foo.can_speak
False

【讨论】:

  • 我什至会将can_speak 定义为 class 属性。
  • @Jean-FrançoisFabre:这是我目前要补充的一点:)
  • 这个问题很奇怪,但你的回答很好。
  • 我以为会有一个优雅的解决方案,但没想到会这么优雅。非常感谢。 :)
【解决方案2】:

假设Animal 是具有can_speak 属性的基类,默认为传递给构造函数的变量,该变量再次默认为False。

在子类中Dog 正在调用它的基本构造函数,所以它不能说话。但是Person 正在使用Truecan_speak 值调用基本构造函数。

因此,您可以创建不会说话的人以及会说话的动物(例如鹦鹉)的对象。通过遵循以下方法,can_speak 变量在所有类中保持不变,并且不会在子类中重复,并且可以通过传递参数来更改,而不是在子类中手动更改。

试试下面的

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

class Dog(Animal):
    pass

class Person(Animal):
    def __init__(self, name, can_speak=True):
        super(Person, self).__init__(name, can_speak)

Bob = Person("Bob the Builder")
print(Bob.name)
print(Bob.can_speak)
# Bob the Builder
# True

Sam = Dog("Sam the Mutt")
print(Sam.name)
print(Sam.can_speak)
# Sam the Mutt
# False

【讨论】:

  • Animal.can_speak 的默认值为 False。所以狗不能说话,如果人它被覆盖为真
  • 使用您的方法,您就可以创建一个 不会 说话的Person。那是存在的(即使我们对这个问题的解释太多了......)
  • 是的,但是在某些情况下人不会说话,而在某些情况下动物会说话(鹦鹉),因此这种方式更通用,并且具有更多的骑乘属性。
  • 我喜欢保持这种方式,因为默认值始终为 False,您只需传递 true 即可更改它,而无需覆盖子类中的属性。
  • 你说得对。但是您应该edit您的答案,并附上一些解释和对您的 cmets 的总结,以确保答案是好的。评论不是答案的一部分。
【解决方案3】:

首先,您应该始终使用内置函数super() 并调用父母的__init__(),除非您确实确定不想这样做。父级可以初始化的不仅仅是这两个属性,您必须将其复制到子级的__init__() 中,这很容易出错。

现在您可以通过多种方式完成任务:

  • 使用默认值

    class Person(Animal):
        def __init__(self, name, can_speak = True):
            super().__init__(name, can_speak)
    

    在这种情况下,您仍然可以创建Person 的实例并设置他不能说话(他可以无语)。

  • 如果你不想支持无语的人,那么你可以这样做:

    class Person(Animal):
        def __init__(self, name, can_speak = True):
            super().__init__(name, True)
    
  • 但是该参数可能会产生误导,因此您可以省略它(从这一点开始,父子节点具有不同的构造函数参数,这通常不是问题):

    class Person(Animal):
        def __init__(self, name):
            super().__init__(name, True)
    

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-25
    • 1970-01-01
    • 2021-12-02
    • 1970-01-01
    • 2017-04-03
    • 2016-07-20
    相关资源
    最近更新 更多