Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate makers for hash, dict, eq, and repr #82

Open
pfw opened this issue Nov 27, 2020 · 3 comments
Open

Separate makers for hash, dict, eq, and repr #82

pfw opened this issue Nov 27, 2020 · 3 comments

Comments

@pfw
Copy link

pfw commented Nov 27, 2020

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?

@smarie
Copy link
Owner

smarie commented Nov 28, 2020

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.

@pfw
Copy link
Author

pfw commented Nov 28, 2020

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, ...):

@smarie
Copy link
Owner

smarie commented Nov 29, 2020

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants