pymbolic icon indicating copy to clipboard operation
pymbolic copied to clipboard

Method for removing the `__getinitargs__` and `init_arg_names` boilerplate.

Open Erotemic opened this issue 4 years ago • 1 comments

I was playing with the library, and I noticed that expressions seem to require these boilerplate __getinitargs__ and init_arg_names methods. Given that this is Python 3.6+ it should be easy to automate that via introspection. Here is a proof of concpet:

from pymbolic.primitives import Expression

class AutoInspectable(object):
    """
    Helper to provide automatic defaults for pymbolic expressions
    """

    def init_arg_names(self):
        return tuple(self._initkw().keys())

    def __getinitargs__(self):
        return tuple(self._initkw().values())

    def _initkw(self):
        import inspect
        from collections import OrderedDict
        sig = inspect.signature(self.__class__)
        initkw = OrderedDict()
        for name, info in sig.parameters.items():
            if not hasattr(self, name):
                raise NotImplementedError((
                    'Unable to introspect init args because the class '
                    'did not have attributes with the same names as the '
                    'constructor arguments'))
            initkw[name] = getattr(self, name)
        return initkw


class AutoExpression(AutoInspectable, Expression):
    pass

Now classes that inherit from AutoInspectable will introspect their __init__ functions and as long a there are no *args **kwargs and all arguments have instance attributes with the same name, it provides a function to return an "initkw" dictionary (i.e. keyword arguments that you could pass to the class to construct a new instance).

There are edge cases where this doesn't work. Namely *args, **kwargs, and when the instance doesn't exactly register the constructor arguments with the same names, but in those cases it raises a NotImplementedError indicating that the user can fill these out manually.

Just thought I'd throw that out there.

Erotemic avatar May 05 '21 01:05 Erotemic

Thanks for the suggestion! With time, this might be something to look into. The name is a bit misleading though: __getinitargs__ is mainly used to find field names that matter, e.g. for __eq__ comparison and hashing. If I were starting the library today, I'd probably rely on dataclasses mechanisms for most of this.

inducer avatar May 05 '21 16:05 inducer