On Mon, Dec 28, 2020 at 10:24 PM Ethan Furman <et...@stoneleaf.us> wrote:

> On 12/28/20 9:31 PM, Guido van Rossum wrote:
>
> > Let me see if I can unpack this.
> >
> > I observe that `type.__new__() ` is really the C function `type_new()`
> in typeobject.c, and hence I will refer to it by
> > that name.
> >
> > I understand that `type_new()` is the only way to create type objects,
> and it includes a call to `__init_subclass__()`.
> >
> > In the source code of `type_new()`, calling `__init_subclass__()` is the
> last thing it does before returning the newly
> > created class object, so at this point the class object is complete,
> *except* that any updates made by the caller of
> > `type_new()` after `type_new()` returns have not been made, of course.
> (For example, `new_class.some_attr = 9` from
> > Ethan's post, or `__abstractmethods__`, which is set by
> update_abstractmethods() in abc.py.)
>
> This is really the heart of the issue.  A major reason to write a custom
> metaclass is to be able to modify the returned
> class before giving it back to the user -- so even though `type_new` is
> complete the new class could easily not be
> complete, and calling `__init_subclass__` and `__set_name__` from
> `type_new` is premature.
>
> > Now here's something that Ethan said that I don't follow:
> >
> >> For Enum, this means that `__init_subclass__` doesn't have access to
> the new Enum's members (they haven't been added yet)
> >
> > I would presume that in an example like the following, the members *are*
> set by the time `type_new()` is called. What am
> > I missing?
> > ```
> > class Color(enum.Enum):
> >      RED = 1
> >      GREEN = 2
> >      BLUE = 4
> > ```
> > Maybe the problem is that the members are still set to their "naive"
> initial values (1, 2, 4) rather than to the
> > corresponding enum values (e.g. `<Color.Red: 1>`)?
>
> Before `type_new()` is called all the (future) members are removed from
> `namespace`, so they are not present when
> `__init_subclass__` is called.  Even if they were left in as `{'RED': 1,
> `GREEN`: 2, `BLUE`: 4}` it would not be
> possible for an `__init_subclass__` to customize the members further, or
> record them in custom data structures, or run
> validation code on them, or etc.
>
> > Without a more elaborate use case I can't give that more than a shrug.
> This is how the `__init_subclass__()` protocol is
> > designed.
>
> The `__init_subclass__` and `__set_name__` protocols are intended to be
> run before a new type is finished, but creating
> a new type has three major steps:
>
> - `__prepare__` to get the namespace
> - `__new__` to get the memory and data structures
> - `__init__` for any final polishing
>
> We can easily move the calls from `type_new()` to `type_init`.
>

No, we can't. There is a window where the subclass is initialized after
`typing_new()` returned before `__init__` starts, and you propose to move
the subclass after that window. There may be code that depends on the class
being initialized at that point, and you will break that code.

Honestly I disapprove of the shenanigans you're committing in enum.py, and
if those are in in the 3.10 (master) branch I recommend that you take them
out. It just looks too fragile and obscure.


> > Note that for ABC, if you add or change the abstraction status of some
> class attributes, you can just call
> > `update_abstractmethods()` and it will update `__abstractmethods__`
> based on the new contents of the class. This also
> > sounds like no biggie to me.
>
> The issue tracker sample code that fails (from #35815):
>
> ```
> import abc
>
> class Base(abc.ABC):
>      #
>      def __init_subclass__(cls, **kwargs):
>          instance = cls()
>          print(f"Created instance of {cls} easily: {instance}")
>      #
>      @abc.abstractmethod
>      def do_something(self):
>          pass
>
> class Derived(Base):
>      pass
> ```
>
> And the output:
>
> `Created instance of <class '__main__.Derived'> easily: <__main__.Derived
> object at 0x10a6dd6a0>`
>
> If `Base` had been completed before the call to `__init_subclass__`, then
> `Derived` would have raised an error -- and it
> does raise an error with the patch I have submitted on Github.
>

Again, big shrug. A static checker will catch that.

-- 
--Guido van Rossum (python.org/~guido)
*Pronouns: he/him **(why is my pronoun here?)*
<http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/HNLAXFRXAW3TOR6CZMXBGRLWQPTOKIN4/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to