mirror of
https://github.com/jbranchaud/til
synced 2026-07-04 00:28:23 +00:00
Add Avoid Modification With Frozen Dataclass as a Python TIL
This commit is contained in:
@@ -10,7 +10,7 @@ working across different projects via [VisualMode](https://www.visualmode.dev/).
|
|||||||
|
|
||||||
For a steady stream of TILs, [sign up for my newsletter](https://visualmode.kit.com/newsletter).
|
For a steady stream of TILs, [sign up for my newsletter](https://visualmode.kit.com/newsletter).
|
||||||
|
|
||||||
_1766 TILs and counting..._
|
_1767 TILs and counting..._
|
||||||
|
|
||||||
See some of the other learning resources I work on:
|
See some of the other learning resources I work on:
|
||||||
|
|
||||||
@@ -1044,6 +1044,7 @@ If you've learned something here, support my efforts writing daily TILs by
|
|||||||
|
|
||||||
- [Access Instance Variables](python/access-instance-variables.md)
|
- [Access Instance Variables](python/access-instance-variables.md)
|
||||||
- [Access Most Recent Return Value In REPL](python/access-most-recent-return-value-in-repl.md)
|
- [Access Most Recent Return Value In REPL](python/access-most-recent-return-value-in-repl.md)
|
||||||
|
- [Avoid Modification With Frozen Dataclass](python/avoid-modification-with-frozen-dataclass.md)
|
||||||
- [Break Debugger On First Line Of Program](python/break-debugger-on-first-line-of-program.md)
|
- [Break Debugger On First Line Of Program](python/break-debugger-on-first-line-of-program.md)
|
||||||
- [Check If Package Is Installed With Pip](python/check-if-package-is-installed-with-pip.md)
|
- [Check If Package Is Installed With Pip](python/check-if-package-is-installed-with-pip.md)
|
||||||
- [Control Passing Of Time In Tests](python/control-passing-of-time-in-tests.md)
|
- [Control Passing Of Time In Tests](python/control-passing-of-time-in-tests.md)
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
# Avoid Modification With Frozen Dataclass
|
||||||
|
|
||||||
|
The `@dataclass` decorator can be set as _frozen_ to prevent modification of
|
||||||
|
values on instances of that `dataclass`.
|
||||||
|
|
||||||
|
Without making it frozen, I can easily subvert validations by changing the value
|
||||||
|
of attributes after the `__post_init__` validations are called.
|
||||||
|
|
||||||
|
```python
|
||||||
|
>>> config = BPEConfig(300, []) # passes validations
|
||||||
|
>>> config.vocab_size = 22 # this is invalid, wish this was prevented
|
||||||
|
```
|
||||||
|
|
||||||
|
Here is the updated `@dataclass` declaration with `frozen=True` passed as a
|
||||||
|
parameter.
|
||||||
|
|
||||||
|
```python
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import ClassVar
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class BPEConfig:
|
||||||
|
BASE_VOCAB_SIZE: ClassVar[int] = 256
|
||||||
|
|
||||||
|
vocab_size: int
|
||||||
|
special_tokens: list[str]
|
||||||
|
|
||||||
|
def __post_init__(self):
|
||||||
|
if self.vocab_size < self.BASE_VOCAB_SIZE:
|
||||||
|
msg = f"vocab_size ({self.vocab_size}) must be greater than or equal to BASE_VOCAB_SIZE ({self.BASE_VOCAB_SIZE})"
|
||||||
|
raise ValueError(msg)
|
||||||
|
```
|
||||||
|
|
||||||
|
Now I am prevented from modifying a scalar value like `vocab_size` after the
|
||||||
|
instance has been created.
|
||||||
|
|
||||||
|
```python
|
||||||
|
>>> config = BPEConfig(300, [])
|
||||||
|
>>> config.vocab_size = 22
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "<stdin>", line 1, in <module>
|
||||||
|
File "<string>", line 4, in __setattr__
|
||||||
|
dataclasses.FrozenInstanceError: cannot assign to field 'vocab_size'
|
||||||
|
```
|
||||||
|
|
||||||
|
This doesn't prevent you from modifying the contents of attributes that are
|
||||||
|
`list` or `dict` types.
|
||||||
Reference in New Issue
Block a user