从内置类继承是否正确?

时间:2008-11-13 23:06:06

标签: python inheritance oop

我想以某种方式使用python程序解析Apache access.log 文件,虽然我对面向对象编程完全不熟悉,但我现在想开始这样做。 / p>

我将创建一个类 ApacheAccessLog ,而我现在唯一想象的就是' readline '方法。在这种情况下,从内置的文件类继承是否通常正确,因此该类的行为就像文件类本身的实例一样,是不是?这样做的最佳方式是什么?

6 个答案:

答案 0 :(得分:15)

在这种情况下,我会使用委托而不是继承。这意味着您的类应该包含文件对象作为属性,并在其上调用readline方法。您可以在记录器类的构造函数中传递文件对象。

至少有两个原因:

  1. 委托减少耦合,例如代替文件对象,您可以使用任何其他实现readline方法的对象( duck typing 在这里很方便)。
  2. 从文件继承时,您的类的公共接口变得不必要地广泛。它包括在文件中定义的所有方法,即使这些方法在Apache日志中没有意义。

答案 1 :(得分:6)

我来自Java背景,但我相信相同的原则将适用于Python。根据经验,除非该类专为继承而设计,否则从不继承自您不理解和控制其实现的类。如果它是以这种方式设计的,它应该在其文档中清楚地描述。

原因是继承可能会将您绑定到您继承的类的实现细节。

使用Josh Bloch的书“Effective Java”中的一个例子

如果我们要扩展类ArrayList类以便能够计算在其生命周期中添加到它的项目数(不一定是它当前包含的数量),我们可能会受到诱惑写这样的东西。

public class CountingList extends ArrayList {
    int counter = 0;

    public void add(Object o) {
        counter++;
        super.add(0);
    }

    public void addAll(Collection c) {
        count += c.size();
        super.addAll(c);
    }

    // Etc.
}

现在这个扩展看起来会准确计算添加到列表中的元素数量,但事实上它可能没有。如果ArrayList通过迭代所提供的addAll并为每个元素调用其接口方法Collection来实现addAll,那么我们将计算通过addAll添加的每个元素方法两次。现在我们类的行为取决于ArrayList的实现细节。

这当然是除了无法使用我们的List类的CountingList的其他实现的缺点。再加上从上面讨论的具体类继承的缺点。

据我所知,Python使用与Java类似(如果不相同)的方法调度机制,因此会受到相同的限制。如果有人能在Python中提供一个例子,我相信它会更有用。

答案 2 :(得分:1)

从内置类继承是完全可以接受的。在这种情况下,我会说你的钱是正确的。
日志“是一个”文件,因此告诉你继承是正确的。

一般规则。
狗“是一种动物,因此继承动物。” 所有者“有一只动物”,因此不会继承动物。

答案 3 :(得分:1)

虽然在某些情况下从内置继承是有用的,但真正的问题是你想要对输出做什么以及你的大画面设计是什么。我通常会编写一个阅读器(使用文件对象)并吐出我需要的任何数据类来保存我刚读过的信息。然后很容易设计出数据类以适应我的其余设计。

答案 4 :(得分:1)

从“内置”类继承你应该是相当安全的,因为后来对这些类的修改通常与当前版本兼容。

但是,您应该认真考虑是否真的希望将您的课程与内置课程提供的其他功能联系起来。正如在另一个答案中提到的,您应该考虑(甚至更喜欢)使用委托

如果您不需要继承,为什么要避免继承,您可以查看 java.util.Stack 类。当它扩展Vector时,它继承了Vector上所有的方法。大多数这些方法违反了Stack隐含的合同,例如:后进先出法。在内部使用Vector实现Stack会好得多,只是将Stack方法暴露为API。然后很容易将实现更改为ArrayList或其他更新的东西,由于继承,现在都无法实现。

答案 5 :(得分:0)

您似乎找到了答案,在这种情况下,委派是更好的策略。不过,我想补充一点,除了委托之外,扩展内置类没有任何问题,特别是如果您的替代方案(取决于语言)是“猴子修补”(请参阅​​http://en.wikipedia.org/wiki/Monkey_patch