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

The __init__ topic #2

Closed
smarie opened this issue Sep 7, 2019 · 5 comments
Closed

The __init__ topic #2

smarie opened this issue Sep 7, 2019 · 5 comments

Comments

@smarie
Copy link
Owner

smarie commented Sep 7, 2019

Several cases to support

1. user writes his own init entirely. This is already supported and he can set the fields correctly (or not, for the optional)
2. user writes his own entirely but not the type hints, doc and defaults (they have already been declared, why copying again). Support the case where he uses all, or some of, the fields as constructor arguments. (will not be fixed for now)
3. user writes his own but does not want to write all the argument names so he could use a special variable fields in the constructor, and anywhere in his constructor do fields.assign() or fields.init(). (fixed in #13 - @inject_fields)
4. user writes his own but wished object creation to be faster than the above. In that case (to benchmark though), we would be rather interested by some kind of a __post_init__ support like in @dataclass (fixed in 0.5.0 - @init_fields and make_init)
5. user wants fully automatic init creation (fixed in 0.5.0 - make_init)

In all these cases,

@smarie
Copy link
Owner Author

smarie commented Sep 9, 2019

In all the above scenarii, having a skip_validation option could be nice to get fast object creation routes. New issue #25

@smarie smarie transferred this issue from smarie/python-mixture Sep 25, 2019
@smarie
Copy link
Owner Author

smarie commented Sep 25, 2019

Possible ideas for the following example:

class Wall(object):
    height: int = field(doc="Height of the wall in mm.")
    color: str = field(default='white', doc="Color of the wall.")

feature 2

user writes his own __init__ entirely but not the type hints, doc and defaults (they have already been declared, why copying again). Support the case where he uses all, or some of, the fields as constructor arguments.

2a- most intuitive:

        @height.inject
        @color.inject
        def __init__(self, height, color):
            self.height = height
            self.color = color

pros:

  • you can use autocompletion so it is fast to type the decorators
  • you only declare the fields that you need

cons:

  • many decorator lines
  • you still have to type each attribute name in the init signature
  • implementation will not be as efficient as a single decorator application since each decorator call can not know if it is the last or not

2b- fancy:

    @(height & color).inject
    def __init__(self, height, color):
        self.height = height
        self.color = color

Solves the "many decorator lines" issue but does not solve the rest.

2+ auto-assign

like in @autoargs from autoclass, whatever the above option we could add an argument to auto-assign the fields before init. And also allow after init ? Would probably not make sense.

@smarie
Copy link
Owner Author

smarie commented Sep 25, 2019

Feature 3

user writes his own but does not want to write all the argument names so he could use a special variable fields in the constructor, and anywhere in his constructor do fields.assign() or fields.init().

        @inject_fields(height, color)
        def __init__(self, fields):
            fields.init()

pros:

  • you can use autocompletion so it is fast to type the decorators
  • you only declare the fields that you need, in the order that you like
  • you control when init happens
  • you can easily debug what happens during field initialization

cons:

  • it does not seem possible to have @inject_fields work without arguments, or even with the class as argument, to say "use all fields from class", except if we allow introspection to be used. Indeed, at the time where the __init__ method is decorated, it is not yet bound to the class. EDIT actually it is possible: we can create a non-data descriptor on the class (this was inspired by this link).

@smarie
Copy link
Owner Author

smarie commented Sep 26, 2019

feature 5

user wants fully automatic init creation

5a with decorator

@auto_init('height')
class Wall(object):
    height: int = field(doc="Height of the wall in mm.")
    color: str = field(default='white', doc="Color of the wall.")

pros

  • a simple decorator, and "all fields" is easy to declare: decorator without arguments.

cons

  • fields are referenced by name: no autocompletion if a particular selection needs to be made.
  • decorator = a bit harder to debug and can be frightening

5b with decorator but fields declare if they are in init

@auto_init
class Wall(object):
    height: int = field(doc="Height of the wall in mm.", in_init=True)
    color: str = field(default='white', doc="Color of the wall.", in_init=False)

pros

  • more compact decoration

cons

  • I do not like the fact that the inclusion in init is a property of the fields. This will cause trouble in inheritance and mixin scenarii.

5c explicit method

class Wall(object):
    height: int = field(doc="Height of the wall in mm.")
    color: str = field(default='white', doc="Color of the wall.")
    __init__ = make_init(height, color)

pros

  • compact
  • autocompletion works if an explicit list or order needs to be provided
  • this can probably be smoothly extended to support scenario 4 as well (a __post_init__ method or even any method using make_init(..., post=<method_post>) or make_init(color, my_post_init_method, height) so as to control precisely which part of the signature will go where)

I do not see much cons here

@smarie
Copy link
Owner Author

smarie commented Oct 4, 2019

Closing - other tickets have been created for each aspect

@smarie smarie closed this as completed Oct 4, 2019
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

1 participant