Hi all, this is a general feeler for if this idea has any traction: All too often I see the following pattern in asyncio 3rd-party libs, either in their own source code or in the inusage: ``` inst = SomeClass() await inst.initialize() ``` What happens here is that, since coroutines cannot be used inside __init__ methods, the __init__ method only stores the parameters, and another, asynchronous method actually initializes the object. This led many 3rd-party libs to use factory methods to create their class instances, which is unideal for both users and developers. We see this pattern in nearly any async 3rd-party lib I came across. To solve this, I propose a new metaclass: `AsyncType`. The core difference between AsyncType and type is that when called, AsyncType will produce a coroutine that asynchronously calls __new__ and __init__, and returns the instance, allowing simply for `instance = await SomeClass()`. In classes of `AsyncType`, the __new__ and __init__ methods must be async methods (returning coroutines). As an additional syntactic sugar, we could also have an `async class(base)` declaration that implicitly sets the class's metaclass to be AsyncType (or raise a TypeError if that is impossible). This proposal is obviously incomplete, and there are many open questions: what about __del__? How would one easily make an async ABC (without a metaclass conflict)? How would an async class easily inherit from a sync class (suppose sync class A implements __new__, and async class B(A) implements __init__)? Perhaps `AsyncType` should only make the __init__ method async and leave __new__ synchronous? I'd just like to get ahead of the (not unjustified) argument that constructors should be lightweight: 1. Python's __init__ is not strictly a constructor. It is, as the name implies, an initializer, that makes the type usable. Constructing the type without initializing it makes no sense and has no usages, so why seperate the operations? 2. We can see numerous examples of (syncronous) connect-on-initialize classes in the standard library, including ftplib, smtplib, and pretty much most *lib modules in the standard library "Internet Protocols and Support" doc page. 3. The "initialize in a separate method" pattern produces some strange-looking code where the class holds on to its initialization params even though it doesn't really need them after the separate methods. The classes should now also consider and safe-guard against cases where the separate method is called twice, or not at all. What does the community think about this idea?
A while back I could make a proof of concept of this with current Python, no modifications needed. The text is in portuguese -by I believe automatic translation should be enough for the non-code parts. https://pt.stackoverflow.com/questions/390755/%c3%89-poss%c3%advel-definir-c... Maybe it is worth putting that thing on a Pypi package? On Wed, 25 Nov 2020 at 07:22, Ben Avrahami <avrahami.ben@gmail.com> wrote:
Hi all, this is a general feeler for if this idea has any traction:
All too often I see the following pattern in asyncio 3rd-party libs, either in their own source code or in the inusage: ``` inst = SomeClass() await inst.initialize() ```
What happens here is that, since coroutines cannot be used inside __init__ methods, the __init__ method only stores the parameters, and another, asynchronous method actually initializes the object. This led many 3rd-party libs to use factory methods to create their class instances, which is unideal for both users and developers. We see this pattern in nearly any async 3rd-party lib I came across.
To solve this, I propose a new metaclass: `AsyncType`. The core difference between AsyncType and type is that when called, AsyncType will produce a coroutine that asynchronously calls __new__ and __init__, and returns the instance, allowing simply for `instance = await SomeClass()`. In classes of `AsyncType`, the __new__ and __init__ methods must be async methods (returning coroutines).
As an additional syntactic sugar, we could also have an `async class(base)` declaration that implicitly sets the class's metaclass to be AsyncType (or raise a TypeError if that is impossible).
This proposal is obviously incomplete, and there are many open questions: what about __del__? How would one easily make an async ABC (without a metaclass conflict)? How would an async class easily inherit from a sync class (suppose sync class A implements __new__, and async class B(A) implements __init__)? Perhaps `AsyncType` should only make the __init__ method async and leave __new__ synchronous?
I'd just like to get ahead of the (not unjustified) argument that constructors should be lightweight: 1. Python's __init__ is not strictly a constructor. It is, as the name implies, an initializer, that makes the type usable. Constructing the type without initializing it makes no sense and has no usages, so why seperate the operations? 2. We can see numerous examples of (syncronous) connect-on-initialize classes in the standard library, including ftplib, smtplib, and pretty much most *lib modules in the standard library "Internet Protocols and Support" doc page. 3. The "initialize in a separate method" pattern produces some strange-looking code where the class holds on to its initialization params even though it doesn't really need them after the separate methods. The classes should now also consider and safe-guard against cases where the separate method is called twice, or not at all.
What does the community think about this idea? _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/DMTLZD... Code of Conduct: http://python.org/psf/codeofconduct/
On 11/25/20 2:19 AM, Ben Avrahami wrote:
All too often I see the following pattern in asyncio 3rd-party libs, either in their own source code or in the inusage: ``` inst = SomeClass() await inst.initialize() ```
[...] allowing simply for `instance = await SomeClass()`. In classes of `AsyncType`, the __new__ and __init__ methods must be async methods (returning coroutines).
I like the idea in principle but I don't currently use any async libraries so my opinion may not count much here. ;) -- David Foster | Seattle, WA, USA
participants (3)
-
Ben Avrahami
-
David Foster
-
Joao S. O. Bueno