1. 7
  1.  

  2. 3

    So, why not simply extend the class directly? For e.g, given a Circle class,

    class Circle(Circle):
        def area(self):
             ...
    

    Older Circle instances are not affected (and hence will not do random things if you are redefining a method) and newer instances will answer to shape.area().

    1. 0

      So…you think that it’s “simpler” to have some Circle objects have “AttributeError” when you call area, and some not. Also, where do you plan to put this code? In the library that’s not yours? How are you going to make sure that all parts of your code generate only newer circles?

      I’m not sure the word “simply” means what you think it means.

      1. 3

        I was not being dismissive of your post, however, you haven’t explained why one should use the specified library. What are the pitfalls of the approach you dismissed as “While it is possible to reach into a class and add a method, this is a bad idea: nobody expects their class to grow new methods, and things might break in weird ways.”.

        The approach I outlined is simple, with the caveat I outlined, and I do not think that is a wrong meaning of simple.

    2. 2

      One nice thing about doing things this way is that if someone else writes a new shape that is intended to play well with our code, they can implement the get_area themselves

      I get why you might use singledispatch to add methods to classes someone else “owns”, but if you were implementing a new class why wouldn’t you just add the methods normally to the class, rather than going through the singledispatch route:

      class Ellipse:
          horizontal_axis: float
          vertical_axis: float
      
        def get_area():
          return math.pi * shape.horizontal_axis * shape.vertical_axis
      

      This seems a lot more conventional than implementing get_area for the new Ellipse class in the manner the article suggests?

      1. 2

        This way someone can call get_area(shape) without worrying whether the shape is a circle or an ellipse.

        1. 1

          Oh 🤦‍♂️ - I totally misunderstood what singledispatch was doing here. Thanks :)

      2. 1

        Swift has a fairly clean way to do this with “extensions”. Extensions tack new methods onto a type in a way that doesn’t change the type’s storage (so no stored properties) and that is scoped to the module where the extension is defined (even if the original type came from somewhere else). The Python interpreter could probably be extended to allow something similar. https://docs.swift.org/swift-book/LanguageGuide/Extensions.html

        1. 1

          I didn’t know about functools.singledispatch before! This is a really cool application of python’s type annotations!

          1. 1

            If you’re importing from shapes to register implementations of get_area, and them the maintainer of shapes decides to implement a “get_area friendly” new shape class, won’t that cause a infinite import loop? Because area_calculation imports shapes and then shapes imports area_calculation?

            1. 0

              No.

              1. 1

                That’s not a very helpful reply.

                1. 0

                  You’re right.