equinox icon indicating copy to clipboard operation
equinox copied to clipboard

Class fields and instance fields behavior

Open ASEM000 opened this issue 3 years ago • 3 comments

Hello, Patrick

currently, data classes allow fields to be either class or instance variables for example

@dc.dataclass
class Test:
    a:int = 1
    def __init__(self) -> None:
        pass


Test().__dict__ # {}
Test.__dict__['a'] # 1 -> class variable

I think it is better to log a warning or to raise an uninitialized field error to disallow this behavior. As the user might be under the impression that a is a parameter of the Test instance (as shown in the Test repr ) while it's not.

ASEM000 avatar Mar 26 '23 09:03 ASEM000

Hmm, that's an interesting edge-case.

Probably the fix is to adjust this check to use in self.__dict__ instead of in dir(self)?

I could see this change having some unintended consequences -- it'd be worth running the Diffrax test suite against such a change as a test to see what happens.

patrick-kidger avatar Mar 26 '23 16:03 patrick-kidger

I think maybe you don't need to check for if field.init , AFAIK the field should be initialized at that point of your code, even if init=False. So that line could be something like this, missing_names = set(self.__dataclass_fields__)-set(vars(self))

To add on this issue, I think dataclasses has asymmetric handling for defaults.

For example this code does not raise any error and assign a as class var


import dataclasses as dc 

@dc.dataclass
class Test:
    a:int = dc.field(default=1)
    def __init__(self) -> None:
        pass

Test() # Test(a=1)

But this code raises an error

@dc.dataclass
class Test:
    a:int = dc.field(default_factory=lambda: 1)
    def __init__(self) -> None:
        pass

Test() # AttributeError

ASEM000 avatar Mar 26 '23 17:03 ASEM000

Yep, agreed.

patrick-kidger avatar Mar 26 '23 21:03 patrick-kidger