python-pyfields icon indicating copy to clipboard operation
python-pyfields copied to clipboard

Separate makers for hash, dict, eq, and repr

Open pfw opened this issue 5 years ago • 3 comments

I've found myself using make_init with arguments rather than @autoclass with parameters as it is more convenient for the cases where I need to write a customise the various dunder methods for hash, dict, eq and repr. For some cases I need init, to_dict and repr to include different fields - make_init makes this easy with the usage like:

init = make_init(height)

particularly useful when subclassing makes sense and it can include fields from the parent.

What do you think about exposing the builders for hash, dict, eq, and repr rather than having them in _apply_decorator of @autoclass?

pfw avatar Nov 27 '20 22:11 pfw

This would be a great addition @pfw , thanks for suggesting it ! Would you like to propose such mod yourself in a PR ? I think the code change would be fairly small, however as always there is also some time to spend on updating the doc and tests :)

Otherwise I'll try to find some time in the upcoming weeks.

smarie avatar Nov 28 '20 15:11 smarie

Great. I'll have a look and see if I understand the code enough to propose sensible changes.

I'm finding myself putting together classes like below and I very much like that pyfields lets you build up the functionality rather than having to turn things off or override. Nice work.

def std_repr(self, ...):
     print(...)

def std_field(doc, **kwargs):
    return field(doc=doc, check_type=True, **kwargs)

@total_ordering
class Test(Parent):
    x: int = std_field(...)
    y: str = std_field(...)

    __init__ = make_init(Parent.z, x, y)
    __repr__ = std_repr

    def __eq__(self, ...):

    def __lt__(self, ...):

pfw avatar Nov 28 '20 23:11 pfw

Great thanks for the feedback @pfw ! For the implementation, the only tricky thing is that you'll see that make_init returns a class descriptor (InitDescriptor) for the method, that is replaced with the method on first (__get__) access. This is mandatory because when the method is created, the fields are not necessarily all yet set on the class. For example the field name and type annotation are provided by python only when the class is finalized.

If we follow the same pattern with the methods you suggest (e.g. make_hash + HashDescriptor, etc.) it should be a copy/paste of what is done for init for most of the contents.

smarie avatar Nov 29 '20 21:11 smarie