-
-
Notifications
You must be signed in to change notification settings - Fork 386
Freezing an attribute in __attrs_post_init__
#1412
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
It sounds like you want your @define
class LightModelInfo:
wavelength: int = field(
validator=validators.instance_of(int),
metadata={"description": "Wavelength in nm."},
)
@property
def wavecolor(self) -> str:
return wavelength_to_hex(self.wavelength) Of course, this calculates the value every time you access it, which might not be ideal. You can combat this with from functools import lru_cache
@define(hash=True) # add this here or implement your own __hash__
class LightModelInfo:
wavelength: int = field(
validator=validators.instance_of(int),
metadata={"description": "Wavelength in nm."},
)
@property
@lru_cache
def wavecolor(self) -> str:
return wavelength_to_hex(self.wavelength) This will cache frequently accessed instances automatically, essentially bringing it in line with primitive attribute getting. The downside of these methods is that it prevents the wavelength property from inheriting the other goodies from attrs (such as a meaningful If you do need all the associated helpers with def read_only(self, attr, value):
raise AttributeError(f"{attr.name} is read-only")
@define
class LightModelInfo:
wavelength: int = field(
validator=validators.instance_of(int),
metadata={"description": "Wavelength in nm."},
)
wavecolor: str = field(
init=False,
on_setattr=read_only, # make sure attempting to set this *specific* attribute results in an error
metadata={"description": "Hexadecimal representation of the light color."},
)
@wavecolor.default
def calculate_wavecolor(self):
return wavelength_to_hex(self.wavelength) # wavelength is populated by this point
a = LightModelInfo(wavelength=750)
print(a) # LightModelInfo(wavelength=750, wavecolor='red')
a.wavecolor = "blue" # AttributeError: wavecolor is read-only Note that with this method modifying a.wavelength = 450
print(a) # LightModelInfo(wavelength=450, wavecolor='red') Which follows the axiom that frozen attributes cannot change after initialization. The property methods above don't have this limitation, and will properly work with any dynamic wavelength value. |
@redruin1 wonderful, thank you so much for the in-depth explanation. This is exactly what I needed. Closing. |
I have a class like this:
I would like to freeze the
wavecolor
attribute during post initialization, or an alternative approach which allows me to compute the value ofwavecolor
based onwavelength
and then freeze it. Is it possible?The text was updated successfully, but these errors were encountered: