ABC with abstractmethod: kwargs on Base, explicit names on implementation

Samuel Marks samuelmarks at gmail.com
Sat Aug 29 06:46:19 EDT 2020


Putting Liskov substitution principal to one side, I had a suggestion
to follow PEP3102, and do `def train(self, *, epochs):`…


It's a rather simple suggestion that I just might take aboard.

In response to Dieter:
My purpose for using a base class is so that the highest level
interface—say a CLI, GUI, REST and RPC API—can all be configured in
one place, but enable the greatest possible divergence from a
parameter standpoint.

An alternative here [in this domain] would be to create a new
Keras/scikit.learn. I.e., one consistent interface that is to be
implemented in full by each framework.

The reason I don't want to take this alternative is manyfold, that I
don't need to get in here (happy to start a new thread if you're
interested).

Two major advantages of this approach are:
0. Implementers can be [pretty much] as divergent as they want, with
different default and required parameters; and even semantics [though
I do have `assert`s to force `method0` to be executed before
`method1`];
1. Implementers don't need to create their own CLIs, GUIs, REST and RPC APIs

Two major disadvantages:
0. Parameters aren't known ahead of time, so you can do the whole
`Animal` [duck type] trick where `Animal` could actually be `Dog` or
`Horse` [making the obvious Base `ABC` & `abstractmethod` approach
'wrong']
1. Each implementer framework can maintain wildly different internal
APIs, making more hardcore integrations—in a multi-ML sense—far more
difficult

Samuel Marks
Charity <https://sydneyscientific.org> | consultancy
<https://offscale.io> | open-source <https://github.com/offscale> |
LinkedIn <https://linkedin.com/in/samuelmarks>

On Sat, Aug 29, 2020 at 8:24 PM Dieter Maurer <dieter at handshake.de> wrote:
>
> Samuel Marks wrote at 2020-8-29 19:14 +1000:
> >So there is no way to get a AOT error when the two functions aren't
> >implemented, if the two functions have different required arguments on
> >implementors?
> >
> >To paint this picture for why I need this, say the first is:
> >
> >class Base(ABC):
> >    @abstractclass
> >    def train(self, epochs):
> >        asset epochs is not None and epochs > 0
> >
> >…and the implementation is:
> >
> >class TensorFlow(Base):
> >    def train(self, learning_rate, epochs, callbacks, metrics, loss, optimizer):
> >        super(Base, self).__init__(epochs=epochs)
> >
> >[+ docstrings and PEP484 types; excluded here for concision]
> >
> >So how do I enable this use-case? - Obviously it doesn't make sense to
> >include these on the base class, and giving them default values
> >probably doesn't make sense either.
> >
> >You're saying I shouldn't be using ABC for this. So what should I be using?
>
> What is your purpose to use a base class in the first place --
> and especially one where `train` has this signature?
>
> You signal with this base class, that it makes sense to
> call `train` with a single positional argument.
> But `train` in the derived class cannot be called in this way.
>
> Base classes are there to capture common features of several
> related classes. In your example above, this is not the case.
> Do not use base classes in this way.
>
> >The requirement I'm trying to enforce is that each implementor has a
> >`train` callable attached.
> >Preferably with one required field (but this is just a nice-to-have).
>
> Read the Python documentation about metaclasses and the special methods
> related to class derivation. Both approaches would allow you
> to check whatever you want.
>
> > ...
> >However if I only have functions which accept an instance of a class
> >as the argument, then that will make it less user-friendly to the API
> >caller. So I really am looking for handling both interfaces in a
> >straightforward manner.
>
> Any system makes some things easy and other things difficult.
> Try to stay with the essential paradigms underlaying the system --
> in order to use the easy things whenever possible.
>
> In your case, this means that the signature of an overriding
> method must be quite similar to that of the overridden method.


More information about the Python-list mailing list