从内置类继承是否正确?

时间:2022-09-25 12:28:39

I want to parse an Apache access.log file with a python program in a certain way, and though I am completely new to object-oriented programming, I want to start doing it now.

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

I am going to create a class ApacheAccessLog, and the only thing I can imagine now, it will be doing is 'readline' method. Is it conventionally correct to inherit from the builtin file class in this case, so the class will behave just like an instance of the file class itself, or not? What is the best way of doing that?

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

6 个解决方案

#1


15  

In this case I would use delegation rather than inheritance. It means that your class should contain the file object as an attribute and invoke a readline method on it. You could pass a file object in the constructor of the logger class.

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

There are at least two reasons for this:

至少有两个原因:

  1. Delegation reduces coupling, for example in place of file objects you can use any other object that implements a readline method (duck typing comes handy here).
  2. 委托减少耦合,例如代替文件对象,您可以使用任何其他实现readline方法的对象(鸭子输入在这里很方便)。

  3. When inheriting from file the public interface of your class becomes unnecessarily broad. It includes all the methods defined on file even if these methods don't make sense in case of Apache log.
  4. 从文件继承时,您的类的公共接口变得不必要地广泛。它包括在文件中定义的所有方法,即使这些方法在Apache日志中没有意义。

#2


6  

I am coming from a Java background but I am fairly confident that the same principles will apply in Python. As a rule of thumb you should never inherit from a class whose implementation you don't understand and control unless that class has been designed specifically for inheritance. If it has been designed in this way it should describe this clearly in its documentation.

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

The reason for this is that inheritance can potentially bind you to the implementation details of the class that you are inheriting from.

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

To use an example from Josh Bloch's book 'Effective Java'

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

If we were to extend the class ArrayList class in order to be able to count the number of items that were added to it during its life-time (not necessarily the number it currently contains) we may be tempted to write something like this.

如果我们要扩展类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.
}

Now this extension looks like it would accurately count the number of elements that were added to the list but in fact it may not. If ArrayList has implemented addAll by iterating over the Collection provided and calling its interface method addAll for each element then we will count each element added through the addAll method twice. Now the behaviour of our class is dependent on the implementation details of ArrayList.

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

This is of course in addition to the disadvantage of not being able to use other implementations of List with our CountingList class. Plus the disadvantages of inheriting from a concrete class that are discussed above.

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

It is my understanding that Python uses a similar (if not identical) method dispatch mechanism to Java and will therefore be subject to the same limitations. If someone could provide an example in Python I'm sure it would be even more useful.

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

#3


1  

It is perfectly acceptable to inherit from a built in class. In this case I'd say you're right on the money.
The log "is a" file so that tells you inheritance is ok..

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

General rule.
Dog "is a"n animal, therefore inherit from animal.
Owner "has a"n animal therefore don't inherit from animal.

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

#4


1  

Although it is in some cases useful to inherit from builtins, the real question here is what you want to do with the output and what's your big-picture design. I would usually write a reader (that uses a file object) and spit out whatever data class I need to hold the information I just read. It's then easy to design that data class to fit in with the rest of my design.

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

#5


1  

You should be fairly safe inheriting from a "builtin" class, as later modifications to these classes will usually be compatible with the current version.

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

However, you should think seriously about wether you really want to tie your class to the additional functionality provided by the builtin class. As mentioned in another answer you should consider (perhaps even prefer) using delegation instead.

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

As an example of why to avoid inheritance if you don't need it you can look at the java.util.Stack class. As it extends Vector it inherits all of the methods on Vector. Most of these methods break the contract implied by Stack, e.g. LIFO. It would have been much better to implement Stack using a Vector internally, only exposing Stack methods as the API. It would then have been easy to change the implementation to ArrayList or something else later, none of which is possible now due to inheritance.

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

#6


0  

You seem to have found your answer that in this case delegation is the better strategy. Nevertheless, I would like to add that, excepting delegation, there is nothing wrong with extending a built-in class, particularly if your alternative, depending on the language, is "monkey patching" (see http://en.wikipedia.org/wiki/Monkey_patch)

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

#1


15  

In this case I would use delegation rather than inheritance. It means that your class should contain the file object as an attribute and invoke a readline method on it. You could pass a file object in the constructor of the logger class.

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

There are at least two reasons for this:

至少有两个原因:

  1. Delegation reduces coupling, for example in place of file objects you can use any other object that implements a readline method (duck typing comes handy here).
  2. 委托减少耦合,例如代替文件对象,您可以使用任何其他实现readline方法的对象(鸭子输入在这里很方便)。

  3. When inheriting from file the public interface of your class becomes unnecessarily broad. It includes all the methods defined on file even if these methods don't make sense in case of Apache log.
  4. 从文件继承时,您的类的公共接口变得不必要地广泛。它包括在文件中定义的所有方法,即使这些方法在Apache日志中没有意义。

#2


6  

I am coming from a Java background but I am fairly confident that the same principles will apply in Python. As a rule of thumb you should never inherit from a class whose implementation you don't understand and control unless that class has been designed specifically for inheritance. If it has been designed in this way it should describe this clearly in its documentation.

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

The reason for this is that inheritance can potentially bind you to the implementation details of the class that you are inheriting from.

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

To use an example from Josh Bloch's book 'Effective Java'

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

If we were to extend the class ArrayList class in order to be able to count the number of items that were added to it during its life-time (not necessarily the number it currently contains) we may be tempted to write something like this.

如果我们要扩展类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.
}

Now this extension looks like it would accurately count the number of elements that were added to the list but in fact it may not. If ArrayList has implemented addAll by iterating over the Collection provided and calling its interface method addAll for each element then we will count each element added through the addAll method twice. Now the behaviour of our class is dependent on the implementation details of ArrayList.

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

This is of course in addition to the disadvantage of not being able to use other implementations of List with our CountingList class. Plus the disadvantages of inheriting from a concrete class that are discussed above.

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

It is my understanding that Python uses a similar (if not identical) method dispatch mechanism to Java and will therefore be subject to the same limitations. If someone could provide an example in Python I'm sure it would be even more useful.

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

#3


1  

It is perfectly acceptable to inherit from a built in class. In this case I'd say you're right on the money.
The log "is a" file so that tells you inheritance is ok..

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

General rule.
Dog "is a"n animal, therefore inherit from animal.
Owner "has a"n animal therefore don't inherit from animal.

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

#4


1  

Although it is in some cases useful to inherit from builtins, the real question here is what you want to do with the output and what's your big-picture design. I would usually write a reader (that uses a file object) and spit out whatever data class I need to hold the information I just read. It's then easy to design that data class to fit in with the rest of my design.

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

#5


1  

You should be fairly safe inheriting from a "builtin" class, as later modifications to these classes will usually be compatible with the current version.

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

However, you should think seriously about wether you really want to tie your class to the additional functionality provided by the builtin class. As mentioned in another answer you should consider (perhaps even prefer) using delegation instead.

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

As an example of why to avoid inheritance if you don't need it you can look at the java.util.Stack class. As it extends Vector it inherits all of the methods on Vector. Most of these methods break the contract implied by Stack, e.g. LIFO. It would have been much better to implement Stack using a Vector internally, only exposing Stack methods as the API. It would then have been easy to change the implementation to ArrayList or something else later, none of which is possible now due to inheritance.

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

#6


0  

You seem to have found your answer that in this case delegation is the better strategy. Nevertheless, I would like to add that, excepting delegation, there is nothing wrong with extending a built-in class, particularly if your alternative, depending on the language, is "monkey patching" (see http://en.wikipedia.org/wiki/Monkey_patch)

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