3 ms·
Counterpoint: Named tuples are immutable, while dataclasses are mutable by default. You can use frozen=true to "simulate" immutability, but that just overwrite
by xg15 2y ago
Counterpoint: Named tuples are immutable, while dataclasses are mutable by default.
You can use frozen=true to "simulate" immutability, but that just overwrites the setter with a dummy implementation, something you (or your very clever coworker) can circumvent by using object.__setattr__()
So you neither get the performance benefits nor the invariants of actual immutability.
- notpushkin 2y ago> something you (or your very clever coworker) can circumvent by using object.__setattr__() This fits pretty well with a lot of other stuff in Python (e.g. there’s no real private members in classes). There’s a bunch of escape hatches that you should avoid (but that can still be useful sometimes), and those usually are pretty obvious (e.g. if you see code using object.__setattr__, something is definitely not right). Can’t tell whether this is good design or not, but personally I like it.
- eyegor 2y agoIs there a difference between global setattr(object, v) and object.__setattr__(v)? I've seen setattr() in the wild all over but I've never encountered the dunder one.
- notpushkin 2y agoNote that `object` here is not a placeholder variable but actually refers to the global object type (basically a superclass of pretty much every other type in Python). It allows you to bypass the classes’ __setattr__ and set the value regardless (the setattr() function can’t do that): In [1]: from dataclasses import dataclass In [2]: @dataclass(frozen=True) ...: class Foo: ...: a: int ...: In [3]: foo = Foo(5) In [4]: foo.a = 10 FrozenInstanceError: cannot assign to field 'a' In [5]: setattr(foo, "a", 10) FrozenInstanceError: cannot assign to field 'a' In [6]: object.__setattr__(foo, "a", 10) In [7]: foo.a Out[7]: 10
- jfktrey 2y agoCounterpoint: I've used `object.__setattr__` pretty often when setting values in the `__post_init__` of frozen dataclasses
- xg15 2y agoI'd argue, that's about the only correct usage of this stuff.
- quotemstr 2y agoIt's Python. You can override practically any behavior. Hell, use ctypes and mutate immutable tuples! Doing so is well-defined in the C API! What bugs me more about frozen dataclasses is how post-init methods have to use the setattr hack.
- hansvm 2y agoCounter-counterpoint: - Everything in Python is mutable, including the definitions of constants like `3` and `True`. It's much like "unsafe" in Rust; you can do stupid things, but when you see somebody reaching for `__setattr__` or `ctypes` then you know to take out your magnifying glass on the PR, find a better solution, ban them from the repo, or start searching for a new job. - Performance-wise, named tuples are sometimes better because more work happens in C for every line of Python, not because of any magic immutability benefits. It's similar to how you should prefer comprehensions to loops (most of the time) if you're stuck with Python but performance still matters a little bit. Yes, maybe still use named tuples for performance reasons, but don't give the credit to immutability.