简体   繁体   中英

What is the proper way to add an attribute to a base class in a Python library and have it inherited?

I am trying to extend a Python library to add functionality I desire. The library provides a number of HTML form objects (such as Textbox , Dropdown , Checkbox , etc.), all derived from an Input object. I want to add an additional attribute to all of these derived objects. What is the proper way of proceeding?

I can:

  1. Modify the original source code for the Input class, adding the attribute I want.
  2. Create a new class that inherits Input and adds my attribute, and then create a bunch of new classes that inherit Textbox , Dropdown , and my new Input class.
  3. Create new classes for Textbox , Dropdown , etc. with the attribute.

Solution 1 is the easiest and simplest, but is inherently wrong, whereas the other two seem like much more work and code-repetition than this task should call for.

Is there a solution I'm missing?

The 4th solution is monkey patching and might be a good idea. Before you try this, make sure this won't break anything now or in the future:

def additional_method(self, arg):
    print("hello", arg)

Input.additional_method = additional_method

or for short stuff:

Input.additional_method = lambda self, arg: do_something(arg)

now all existing and future Input instances (and therefore instances of all Input subclasses) have an additional_method attached to them.

This works also for any future subclasses of Input that might not even exist yet, or you might not be aware of, at the time of adding the method, so is therefore better (ie more generic) than creating an alternative inheritance hierarchy, which you'll have to then maintain and keep in sync with upstream changes.

NOTE: before you downvote just because it contains the phrase "monkey patching", consider that monkey patching doesn't have to be dangerous/fragile, and is a first class (as in "respected") feature in many languages.

You can use a mixin (multiple inheritance). It's a class that just contains your extra attribute, and add this class to the parent class of a subclass of Textbox, Dropdown, Checkbox... like this:

from ... import TextBox

class Mixin:
    def __init__(self):
        self.new_attribude = ...

class TextBox_with_new_attribute(Mixin, TextBox):
    pass

But, it depends tightly on your goals...

Edit: base on @Veedrac comment, in case of third party library.

If there are a lot of classes you could dynamically apply a mixin:

for cls in list_of_classes_to_patch:
    patched = type(cls.__name__, (my_mixin, cls), {})
    setattr(place_to_export, cls.__name__, patched)

place_to_export can be defined as import this_module as place_to_export .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM