This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Surprising and possibly incorrect passing of InitVar to __post_init__ method of data classes
Type: Stage:
Components: Library (Lib) Versions: Python 3.9
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: eric.smith Nosy List: Aaron Ecay, eric.smith, xtreak
Priority: normal Keywords:

Created on 2019-11-06 12:50 by Aaron Ecay, last changed 2022-04-11 14:59 by admin.

Messages (4)
msg356125 - (view) Author: Aaron Ecay (Aaron Ecay) Date: 2019-11-06 12:50
I have discovered that InitVar's are passed in a surprising way to the __post_init__ method of python dataclasses.  The following program illustrates the problem:

=====

from dataclasses import InitVar, dataclass

@dataclass
class Foo:
    bar: InitVar[str]
    quux: InitVar[str]

    def __post_init__(self, quux: str, bar: str) -> None:
        print(f"bar is {bar}; quux is {quux}")

Foo(bar="a", quux="b")

=====

The output (on python 3.7.3 and 3.8.0a3) is (incorrectly):

bar is b; quux is a

This behavior seems like a bug to me, do you agree?

I have not looked into the reason why it behaves this way, but I suspect that the InitVar args are passed positionally, rather than as key words, to __post_init__.  This requires the order of arguments in the definition of __post_init__ to be identical to the order in which they are specified in the class.  I would expect the arguments to be passed as keywords instead, which would remove the ordering dependency.  If there is agreement that the current behavior is undesirable, I can look into creating a patch to change it.
msg356128 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2019-11-06 13:14
I think using named parameters in the call to __post_init__ is reasonable. It's currently positional.
msg356129 - (view) Author: Karthikeyan Singaravelan (xtreak) * (Python committer) Date: 2019-11-06 13:29
Should we also be checking for __post_init__ to have positional only arguments / syntax in the signature. I tried a simple fix of f.name + "=" + f.name to pass them as keyword always where current tests and reported example passes but with positional arguments it could be a problem.

https://github.com/python/cpython/blob/5c0c325453a175350e3c18ebb10cc10c37f9595c/Lib/dataclasses.py#L516
msg356130 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2019-11-06 13:36
I don't think that's necessary. We should just document that parameters are passed by name to __post_init__. This would have to be a 3.9 feature, since it's not strictly backward compatible.
History
Date User Action Args
2022-04-11 14:59:22adminsetgithub: 82900
2019-11-06 13:36:38eric.smithsetmessages: + msg356130
versions: + Python 3.9, - Python 3.7
2019-11-06 13:29:49xtreaksetnosy: + xtreak
messages: + msg356129
2019-11-06 13:14:11eric.smithsetassignee: eric.smith
messages: + msg356128
2019-11-06 13:03:19xtreaksetnosy: + eric.smith
2019-11-06 12:50:00Aaron Ecaycreate