-
-
Notifications
You must be signed in to change notification settings - Fork 32.6k
Description
Bug report
Bug description:
Generally speaking, any objects present in the namespace of a class Foo
that define the special __set_name__
method will have that method called on them as part of the creation of the class Foo
. (__set_name__
is generally only used for descriptors, but can be defined on any class.)
For example:
Python 3.12.0 (tags/v3.12.0:0fb18b0, Oct 2 2023, 13:03:39) [MSC v.1935 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> class Annoying:
... def __set_name__(self, owner, name):
... raise Exception('no')
...
>>> class Foo:
... attr = Annoying()
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __set_name__
Exception: no
Error calling __set_name__ on 'Annoying' instance 'attr' in 'Foo'
Descriptors inside typing.NamedTuple
namespaces generally work the same way as in other class namespaces...
>>> from typing import NamedTuple
>>> class Foo(NamedTuple):
... bar = property(lambda self: 42)
...
>>> Foo().bar
42
...but with one notable exception: they don't have __set_name__
called on them!
>>> class Annoying:
... def __set_name__(self, owner, name):
... raise Exception('no')
...
>>> from typing import NamedTuple
>>> class Foo(NamedTuple):
... bar = Annoying() # this should cause the creation of the `Foo` class to fail...
...
>>> # ...but it didn't!
Why does this happen?
__set_name__
would normally be called on all members of a class dictionary during the class's creation. But the NamedTuple
class Foo
is created here:
Lines 2721 to 2723 in 97c4c06
nm_tpl = _make_nmtuple(typename, types.items(), | |
defaults=[ns[n] for n in default_names], | |
module=ns['__module__']) |
And the bar
attribute is only monkey-patched onto the Foo
class after the class has actually been created. This happens a few lines lower down in typing.py
, here:
Lines 2732 to 2733 in 97c4c06
elif key not in _special and key not in nm_tpl._fields: | |
setattr(nm_tpl, key, ns[key]) |
__set_name__
isn't called on Foo.bar
as part of the creation of the Foo
class, because the Foo
class doesn't have a bar
attribute at the point in time when it's actually being created.
CPython versions tested on:
3.8, 3.11, 3.12, CPython main branch
Operating systems tested on:
Windows