Ariel Ortiz - The Perils of Inheritance: Why We Should Prefer Composition - PyCon 2019

แชร์
ฝัง
  • เผยแพร่เมื่อ 5 ส.ค. 2024
  • "Speaker: Ariel Ortiz
    Inheritance is among the first concepts we learn when studying object-oriented programming. But inheritance comes with some unhappy strings attached. Inheritance, by its very nature, tends to bind a subclass to its superclass. This means that modifying the behavior of a superclass might alter the behavior of all its subclasses, sometimes in unanticipated ways. Furthermore, it’s commonly accepted that inheritance actually breaks encapsulation. So, if inheritance has these issues, what alternative do we have? More than two decades ago, The Gang of Four (Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides) suggested in their famous Design Patterns book that we should favor object composition over class inheritance.
    In this talk I will show some code examples in Python where inheritance goes astray and demonstrate how to correct them by using composition. My intention is not to demonize inheritance, but instead present how to use it wisely in order to improve the design of our object-oriented software so that it’s more flexible and easier to maintain.
    Slides can be found at: speakerdeck.com/pycon2019 and github.com/PyCon/2019-slides"

ความคิดเห็น • 19

  • @rodelias9378
    @rodelias9378 3 หลายเดือนก่อน

    Awesome talk! A must watch for anyone doing OOP

  • @rayluo4665
    @rayluo4665 5 ปีที่แล้ว +1

    Thanks for the talk! A very effective way to demonstrate one of the surprising disadvantage of inheritance.

  • @mudskippy3903
    @mudskippy3903 4 ปีที่แล้ว +1

    Really great presentation! Another thing I took away from this: The change in the list super class is a perfect example, why -- especially in a dynamic language like python -- you want unit tests. The tests serve as a specification and document intent and make it easy to detect errors like this, where the code works perfectly well, but is behaving in a weird way. Rules of thumb don't solve problems in communication; documentation and discussions do (whereas well written tests are a form of both)

  • @rob876
    @rob876 3 ปีที่แล้ว +2

    When a language has only single inheritance and no multiple inheritance, it's often advisable to use composition in order to roll your own multiple inheritance. In fact it is better to not use inheritance at all in that case.

  • @kevincornally8392
    @kevincornally8392 5 ปีที่แล้ว +1

    Great talk !

  • @rosameltrozo4964
    @rosameltrozo4964 4 ปีที่แล้ว

    Gracias por el tuto

  • @MagnusAnand
    @MagnusAnand 4 ปีที่แล้ว

    Nice video

  • @4rph3n
    @4rph3n 5 ปีที่แล้ว +4

    I think many of the disadvantages of OOP presented here most often occur when not following SOLID principles of OOP. (Robert Martin)

    • @feddeschaeffer7116
      @feddeschaeffer7116 4 ปีที่แล้ว +4

      I've found that, given that Robert C. Martin phrased it in terms of statically typed languages such as Java and C++, it can be non-trivial to interpret how the principles apply to Python. Applying the mental models of those other languages to Python is what causes the perils listed in this talk. For instance, Python has a strong culture of duck typing, where the type of an object is determined by what you can ask it to do rather than what it ‘inherits’, so there's no good reason to apply the Liskov Substitution Principle, and the idea of ‘is-a’, to Python subclasses. Instead, something is a subtype if it responds to methods that people will expect to do the same thing-so make sure that if you implement .__len__() on a class, it takes no further arguments and returns an integer that's semantically the ‘length’ of the instance.

    • @feddeschaeffer7116
      @feddeschaeffer7116 4 ปีที่แล้ว +1

      To avoid the actual pitfalls of inheritance in Python, without the boilerplate code suggested in this talk, you just have to keep a few things in mind when you write a class that might ever be reused as a base class: `self` and `super()` don't refer to the class you're writing right now, but to (the ancestors of) your subclassers.
      For one, this means that when you call methods on them you'll probably want to forward arguments you don't recognise with `*args` and `**kwargs`. And secondly, whenever you do something with `self` you should think about whether the relation is part of the external interface, or an internal detail.
      In the talk, the relation between `.__init__()` and `.header` was part of the interface, but the relation between `.insert()` and `.insert_all()` should not have been. That last situation is the (sole) reason why double-underscore name mangling exists in Python: all it takes to resolve the problem is adding an internal reference to the base class with `__insert_all = insert_all`, and calling that instead of deferring to the bottom of the inheritance chain.

    • @feddeschaeffer7116
      @feddeschaeffer7116 4 ปีที่แล้ว +2

      With these double-underscore class internal references, Python's inheritance supports the encapsulation that this talk lists as one of the advantages of composition. The other advantages listed are supported with multiple inheritance-although number 3, the ripple effect of interface changes, comes back to the Single-Responsibility Principle: if these interface changes actually involve the one concern for which the subclass chose to re-use the code of the base class, reflecting them may actually be desirable. For more explanation of how to use subclassing in Python effectively, I recommend a few talks by Raymond Hettinger, long-time core developer of the language: ‘Python's class development toolkit’, ‘The art of subclassing’ and ‘Super considered super!’.

  • @FinallyAFreeUsername
    @FinallyAFreeUsername 5 ปีที่แล้ว +6

    Talk starts at 2:48 .

  • @ShortGiant1
    @ShortGiant1 5 ปีที่แล้ว

    Nice talk! Wonder how the "forwardable" way from counter3.py work in a language like C++.
    Also, great slides!

    • @devaggarwal1220
      @devaggarwal1220 5 ปีที่แล้ว +1

      forwardable's implementation seems to solely rely on the dynamic behaviour of languages like Ruby and Python.

    • @movax20h
      @movax20h 4 ปีที่แล้ว

      @@devaggarwal1220 Not true. This is trivially done in many static languages. Most notably this can be done in 4 different ways in D languages. 1) Using builtin 'alias foo this;' in the class. 2) Using metaprograming and code generation using mixins, to automatically generate all forwarding methods, but it is somehow messy, complex and messy. 3) Using metaprograming, with templates and traits, even more messy imho. 4) Using 'opDispatch' forwarding and variadic templates and automatic types, which is more generic than 'alias foo this', and also pretty easy to do. About 3 lines in a simplest case. Usage of such classes can be streamlined by using interfaces if you want to use them in many places, or using generic template metaprograming in D, which would devirtualize most of the code, at the cost of extra code generated.