[Python-Dev] descriptor __set_name__ and dataclasses

Eric V. Smith eric at trueblade.com
Mon Mar 26 10:40:10 EDT 2018

https://bugs.python.org/issue33141 points out an interesting issue with 
dataclasses and descriptors.

Given this code:

from dataclasses import *

class D:
     """A descriptor class that knows its name."""
     def __set_name__(self, owner, name):
         self.name = name
     def __get__(self, instance, owner):
         if instance is not None:
             return 1
         return self

class C:
     d: int = field(default=D(), init=False)

C.d.name is not set, because d.__set_name__ is never called. However, in 
this case:

class X:
     d: int = D()

X.d.name is set to 'd' when d.__set_name__ is called during type.__new__.

The problem of course, is that in the dataclass case, when class C is 
initialized, and before the decorator is called, C.d is set to a Field() 
object, not to D(). It's only when the dataclass decorator is run that I 
change C.d from a Field to the value of D(). That means that the call to 
d.__set_name__(C, 'd') is skipped. See 
https://www.python.org/dev/peps/pep-0487/#implementation-details for 
details on how type.__new__ works.

The only workaround I can think of is to emulate the part of PEP 487 
where __set_name__ is called. I can do this from within the @dataclass 
decorator when I'm initializing C.d. I'm not sure how great this 
solution is, since it's moving the call from class creation time to 
class decorator time. I think in 99+% of cases this would be fine, but 
you could likely write code that depends on side effects of being called 
during type.__new__.

Unless anyone has strong objections, I'm going to make the call to 
__set_name__ in the @datacalss decorator. Since this is such a niche use 
case, I don't feel strongly that it needs to be in today's beta release, 
but if possible I'll get it in. I already have the patch written. And if 
it does get in but the consensus is that it's a bad idea, we can back it 


More information about the Python-Dev mailing list