[Python-Dev] descriptor set_name and dataclasses (original) (raw)

Nick Coghlan ncoghlan at gmail.com
Mon Mar 26 11:08:57 EDT 2018


On 27 March 2018 at 00:40, Eric V. Smith <eric at trueblade.com> wrote:

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 setname(self, owner, name): self.name = name def get(self, instance, owner): if instance is not None: return 1 return self

@dataclass class C: d: int = field(default=D(), init=False) C.d.name is not set, because d.setname is never called. However, in this case: class X: d: int = D() X.d.name is set to 'd' when d.setname 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.setname(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 setname 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 setname 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 out.

Would it be feasible to define Field.__set_name__, and have that call default.__set_name__ when the latter exists, and be a no-op otherwise?

Cheers, Nick.

-- Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia



More information about the Python-Dev mailing list