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

RFC: using __call__ instead of __new__ #10

Closed
biqqles opened this issue Dec 16, 2020 · 1 comment
Closed

RFC: using __call__ instead of __new__ #10

biqqles opened this issue Dec 16, 2020 · 1 comment
Labels
enhancement New feature or request

Comments

@biqqles
Copy link
Owner

biqqles commented Dec 16, 2020

So it's that time of year when I finally have a bit more time to experiment with my projects. I've been thinking about the uninspiring performance when (and only when) a custom __init__ is used, as @TylerYep pointed out in #6 (comment). This arises because the current __call__ implementation used is generic and dynamically modifies the parameters to either __new__ or __init__ - what would be really good is to generate a static __call__ that does this with no overhead. To keep performance good and code simple, this method would both initialise the instance with its parameters and redirect any additional ones to __init__ if it's defined. However, because an object's __call__ method has to be defined on its type (i.e. in the case of a class its metaclass), this means we have to dynamically create a subclass of the metaclass at the time of decorator use.

I've implemented this, and though it works surprisingly well in my other tests, it breaking multiple inheritance (highlighted below) means it's nowhere near ready for rolling out in releases yet. Despite this, I'm curious to see how well it works in the code of others, if you would like to test it. The code is in the branch static-call.

Advantages

  • As-fast-as-possible initialiser performance
  • Even simpler code in dataclassy since it only has to work with one method (__call__), not __call__, __new__ and __signature__
  • The current use of __new__ could be considered hacky as it's not "supposed" to be used to initialise the class instance

Disadvantages

  • You (the user) can no longer call __new__ on a data class to instantiate it without __init__ being executed. I'm not sure if this is actually useful (or a good idea to do), but it is a feature nonetheless
  • Say class B is a subclass of A. With this method, type(A) is not type(B) which is unusual and surprising. Only issubclass(type(B), type(A)) is true. However, Python supports this "dynamic metaclass" paradigm fine. Besides looking odd (and how often do you compare the types of classes, really!) I've found no side effects other than...
  • Multiple inheritance now becomes ugly. Whereas before it worked perfectly (e.g. class C(A, B), now you have to do something like
class CMeta(type(A), type(B)):
    pass

@dataclass(meta=CMeta)
class C:
    ...
@biqqles biqqles added the enhancement New feature or request label Dec 16, 2020
@biqqles
Copy link
Owner Author

biqqles commented Jan 11, 2021

Superseded by #12.

@biqqles biqqles closed this as completed Jan 11, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant