【问题标题】:Is there a "pythonic" approach to required properties (OOP)?是否有所需属性(OOP)的“pythonic”方法?
【发布时间】:2012-09-11 20:08:25
【问题描述】:

我正在努力为以下班级组织寻找“pythonic”方法:

我有一个基类,其属性在其构造函数中初始化,例如:

class Animal(object):
    def __init__(self, class_, species, is_domesticated):
        self.class_ = class_
        self.species = species
        self.is_domesticated = is_domesticated

然后,当我进行子类化时,我想“硬编码”这些属性中的一个或多个,如下所示:

class Mammal(Animal):
    def __init__(self, species, is_domesticated):
        Animal.__init__(self, 'Mammal', species, is_domesticated)

因此,哺乳动物的实例化如下:

monkey = Mammal('Primate', false)

问题是,我想使用 *args 以便在更改基类定义时不理会任何派生类。因此哺乳动物的定义变为:

class Mammal(Animal):
    def __init__(self, *args):
        Animal.__init(self, *(args + (class_='Mammal',)))

这(不用说)看起来很可怕。一些提示将不胜感激 =)

【问题讨论】:

  • 来自import this:显式优于隐式。我会说你的第一次尝试看起来不错!
  • 当您将参数添加到它们也应该接受的基类时,您并不是“独自离开派生类”。您只是通过不记录参数来使客户端代码作者变得困难。
  • 也许你可以使用带有默认值的可选参数(比如is_deomesticated=False...)?

标签: python oop inheritance args iterable-unpacking


【解决方案1】:

如果您在基类中只有一组固定的参数,则无需担心可变参数。只需按照您在第一个示例中所做的操作即可。如果您希望能够向基类随机添加参数,但将它们添加为位置参数并且没有默认值,那么就没有希望了;您不能随便更改基类并期望所有派生类继续工作。

但是,有一个相当常见的中间情况,您可能有大量属性,它们的各种组合可能会传递给层次结构中的任何类。您可能希望向基类添加新参数,但它们将具有默认值,因此派生类不需要显式了解它们;他们将优雅地降级为基类默认值。在这种情况下,使用**kwargs 而不是*args 通常会更好。

class Animal(object):
    def __init__(self, **kwargs):
        self.class_ = kwargs['class_']
        self.species = kwargs['species']
        # etc.
class Mammal(Animal):
    def __init__(self, **kwargs):
        Animal.__init__(self, class_="Mammal", **kwargs)

这需要通过关键字传递参数:

>>> Animal(class_='Fish', species='barracuda', is_domesticated=False)
4: <__main__.Animal object at 0x0177ABF0>
>>> Mammal(species="monkey", is_domesticated=False)
5: <__main__.Mammal object at 0x0177AFB0>

。 . .但如果它们有很多,那就更好了,因为如果你有 10 种不同的东西按位置传递,没有人会记得传递它们的顺序。这也意味着您可以轻松添加新参数;没有人需要知道在列表中的哪个位置放置新的,他们可以通过关键字将它们添加到任何地方。

在 Python 2 中,您必须像上面那样手动提取 kwargs。在 Python 3 中,您可以使用 keyword-only arguments 来简化此操作。

【讨论】:

  • 您发布了您的答案,正如我所建议的那样作为评论! +1
【解决方案2】:

好吧,你为什么不按你说的去做呢?让Mammal.__init__() 接受*args 参数,然后使用它。代码如下:

class Animal(object):
    def __init__(self, class_, species, is_domesticated):
        self.class_ = class_
        self.species = species
        self.is_domesticated = is_domesticated
    def __str__(self):
        s_dom = "dom" if self.is_domesticated else "wild"
        return ("Animal(%s, %s, %s)" % (self.class_, self.species, s_dom))

class Mammal(Animal):
    def __init__(self, *args):
        Animal.__init__(self, 'Mammal', *args)

cat = Mammal("cat", True)
print(cat)

lion = Mammal("lion", False)
print(lion)

输出:

Animal(Mammal, cat, dom)
Animal(Mammal, lion, wild)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-05
    • 1970-01-01
    • 2014-05-10
    • 2020-06-20
    相关资源
    最近更新 更多