Search code examples
pythonenumspropertiesgetter-setterpython-dataclasses

Property in dataclass


Description


I am trying to implement a simple dataclass that just holds a few parameters.

@dataclass
class ReconstructionParameters:

    img_size: int
    CR: int
    denoise: bool
    epochs: int
    learning_rate: float
    step_size: int
    gamma: float
    batch_size: int
    regularization: float
    N0: float
    sig: float

    arch_name: InitVar[str]

    net_arch: int = field(init=False)


    def __post_init__(self, arch_name):
        self.net_arch = arch_name

    @property
    def net_arch(self):
        return str(netType(self.net_arch))

    @net_arch.setter
    def net_arch(self, arch_name):
        self.net_arch = int(netType[arch_name])
    

An user should be able to pass a string containing a string arch_name during initialization of the class, but the class should keep an equivalent integer defined in the following IntEnum:

class netType(IntEnum):
    
    c0mp = 0
    comp = 1
    pinv = 2
    free = 3

However, if the user wants obtain the net_arch contained in a previously created class, they should have access to the same string used for initialization instead of the integer representation. I am trying to use the @property decorator and a setter. Ideally, I would like to use a __post_init__() method to initialize net_arch that uses its setter.

Error


When running the following code I get an error:

a = ReconstructionParameters(
    img_size=64, 
    CR=1024,
    denoise=True,
    epochs=20, 
    learning_rate=1e-6,
    step_size=10,
    gamma=1e-7,
    batch_size=256,
    regularization=1e-6, 
    N0=2500,
    sig=0.5,
    arch_name='c0mp')
Traceback (most recent call last):

  File "C:\spas\Programs\Python\test.py", line 51, in <module>
    a = ReconstructionParameters(

  File "<string>", line 14, in __init__

  File "C:\spas\Programs\Python\test.py", line 48, in net_arch
    self.net_arch = int(netType[arch_name])

  File "C:\Users\user\Anaconda3\envs\singlepixelenv\lib\enum.py", line 349, in __getitem__
    return cls._member_map_[name]

KeyError: <property object at 0x000001CF7C26BA40>

Solution

  • The dataclass field and the property cannot have the same name. But you can add a leading underscore to the field, then the property will work.

    from dataclasses import InitVar, dataclass, field
    from enum import IntEnum
    
    
    @dataclass
    class ReconstructionParameters:
        img_size: int
        CR: int
        denoise: bool
        epochs: int
        learning_rate: float
        step_size: int
        gamma: float
        batch_size: int
        regularization: float
        N0: float
        sig: float
    
        arch_name: InitVar[str]
    
        _net_arch: int = field(init=False)
    
        def __post_init__(self, arch_name):
            self.net_arch = arch_name
    
        @property
        def net_arch(self):
            return str(netType(self._net_arch))
    
        @net_arch.setter
        def net_arch(self, arch_name):
            self._net_arch = int(netType[arch_name])
    
    
    class netType(IntEnum):
        c0mp = 0
        comp = 1
        pinv = 2
        free = 3
    
    
    a = ReconstructionParameters(
        img_size=64,
        CR=1024,
        denoise=True,
        epochs=20,
        learning_rate=1e-6,
        step_size=10,
        gamma=1e-7,
        batch_size=256,
        regularization=1e-6,
        N0=2500,
        sig=0.5,
        arch_name='c0mp')
    
    print(a)
    # ReconstructionParameters(img_size=64, CR=1024, denoise=True, epochs=20, learning_rate=1e-06, step_size=10, gamma=1e-07, batch_size=256, regularization=1e-06, N0=2500, sig=0.5, _net_arch=0)
    print(a.net_arch)
    # netType.c0mp