The main thing I want is type safety. I want Python to complain if the callee uses the wrong argument types, and to provide suggestions on what's needed and info about it.
Without a base class I can just have docstrings and type annotations to achieve that. What can I use that will require all implementers to have a minimum of the same properties and arguments, but also allow them to add new properties and arguments? Preferably I would like this all to happen before compile/interpret time. This also opens it up to AST driven stub generation; as can be found in various IDEs (and also a little project I wrote that `import ast`). What are my options here? - It doesn't seem like the metaclass or decorator approaches will help here… Samuel Marks Charity <https://sydneyscientific.org> | consultancy <https://offscale.io> | open-source <https://github.com/offscale> | LinkedIn <https://linkedin.com/in/samuelmarks> Samuel Marks wrote at 2020-8-24 18:24 +1000: >After a discussion on #python on Freenode, I'm here. > >The gist of it is: >> Falc - Signature of method 'Pharm.foo()' does not match signature of base >> method in class 'Base' > >What's the right way of specialising the children and leaving the Base >pretty much empty? > >Specifically I want: >• All implementers to be forced to implement Base's method >• Base to be able to do very basic things with kwargs, namely log it >(to a file like stdout or a db) >• Support for [at least] Python 3.6–3.9 (I don't think `Protocol` has >been backported?) >• Implementors to have access to the proper name, rather than having >to unpack kwargs > >Should I be using a Base class? - Metaclass? - Something else >entirely? - I know giving `b` a default value would resolve the >[PyCharm] linter error… but I want it to be a required argument. > >Full example: > >from abc import ABC, abstractmethod > > >class Base(ABC): > @abstractmethod > def foo(self, a, **kwargs): > ... >class Pharm(Base): > def foo(self, a, b): > ... Python make a distinction between positional and keyword arguments. A positional argument is identified by its position in the parameter list; a keyword argument is identified by its name. `**` introduces arbitrary keyword arguments. In a call, all those arguments must be passed as "name=value". In your case above, `b` is not a keyword argument and thus is not matched by `**kwargs`. The error you observe is justified. You can try: class Base(ABC): @abstractmethod def foo(self, a, *args, **kwargs): ... class Pharm(Base): def foo(self, a, b, *args, **kwargs): ... Note that the base method signature allows arbitrary positional and keyword arguments. As a consequence, derived methods must do the same. If this is not what you want, you might want to explore the use of a decorator or a meta class rather than a base class. -- https://mail.python.org/mailman/listinfo/python-list