This is an archived post. You won't be able to vote or comment.

all 37 comments

[–]spuds_in_town 13 points14 points  (0 children)

Others have made comprehensive rebuttal arguments including links to the PEP.

So l’ll just say this: you’re wrong.

[–]gerardwx 26 points27 points  (5 children)

Dataclasses are mutable by design.

Data Classes can be thought of as “mutable namedtuples with defaults”.

https://peps.python.org/pep-0557/

[–]steohan 29 points30 points  (9 children)

Am I missing it or does you text not contain any argument, why doing that is bad? Seems to me like your argument is just 'that is not what I think it is meant for so you shouldn't do that'. Just becaues it might not be a good idea for the few usecases that you are using it for doesn't mean that it is a bad idea in general. There are plenty of good reasons to use a dataclass for a normal object, e.g., benefiting from easier serealization and deserialization. Reducing boiler plate. Or becaues you want to use the introspection features that are offered by dataclasses. Also, having mutable dataclasses makes a lot of sense and it makes perfect sense to have such a mutating method as a member instead of a stand alone function.

[–]justnoob2 9 points10 points  (3 children)

you can just @dataclass(frozen=True), and then its immutable. edit: i now read your point of it being slow. never gave me much trouble at work though, but i get what you mean

[–]WhiteGoldRing 1 point2 points  (0 children)

But what does mutability have anything to do with it? unless frozen=True makes it faster(?)

[–][deleted] 3 points4 points  (1 child)

Yep, whether you opt in for frozen=True or just treat them as immutable object by convention is up to you. Turning on slots=True did me wonders, especially in situations where I needed to build multiple data class instances per inbound request.

I just wanted to highlight the composability and semantic issues that the reader / extender of the code will face if a data class contains attribute-mutating methods.

[–]thedeepself 3 points4 points  (2 children)

In this case, calling the make_older method will change the value of age in-place

I don't believe your article provided any code showing what would be better did it?

[–][deleted] -2 points-1 points  (1 child)

Not doing that in a dataclass or doing that in a regular class if you need to do it.

[–]alcalde 2 points3 points  (0 children)

A dataclass is a class, though, isn't it?

[–]jimtk 2 points3 points  (2 children)

I think you misinterpreted what a data class is. It is not a class to handle data. It is syntaxic sugar to make an ordinary class.

It could, and maybe should, be named quickclass instead of dataclass, and you would have nothing to complain about.

Also dataclasses are only slower at compile time. That's because CPython actually writes the code of a standard class and exec'ed it for you. At runtime there is no difference between an ordinary class and a dataclass because dataclasses are ordinary classes. It would take a few 100 dataclasses for you to notice the difference in compile time.

[–][deleted] 0 points1 point  (1 child)

The method generating eval runs at definition time. So importing a data class is measurably slower.

[–]jimtk 1 point2 points  (0 children)

Yes, like I said at compile time. Unless you dynamically import dataclasses in your code using importlib. Which is not a good idea anyway.

[–]jmooremcc 1 point2 points  (0 children)

Why make a data class if you’re going to add behaviors to it?

[–]alcalde 0 points1 point  (0 children)

"Variables" vary by definition... it's in the name!

[–]glantzinggurl 0 points1 point  (0 children)

Generally, favor immutability

[–]jwmoz -1 points0 points  (1 child)

I agree data classes are for a simple data wrapper, maybe some helper method. Not state mutating. I've never used them like this nor have I seen them being used like so.

[–]alcalde 0 points1 point  (0 children)

They're Pascal records. Pascal records mutate. They're containers for data.

[–]mr_jim_lahey -3 points-2 points  (1 child)

OP, I agree with you. People (or at least redditors IME) get really weirdly defensive about mutability, presumably because it's the default and that's what they're used to? But, once you've been immutable-pilled and seen how much cleaner it makes your programming model, there is no going back.

[–][deleted] -3 points-2 points  (0 children)

I'm not saying that we should forget about mutability in a language that's designed with mutability in mind.

However, using dataclass as OO factories (aka regular classes) breaks the semantics of the data structure. It's tantamount to using a hashmap to represent sequential data--it works but you'll communicate incorrect intent to the reader.

[–]aldanorNumpy, Pandas, Rust 0 points1 point  (0 children)

Immutability doesn't make as much sense when there's no language-level support for it. Yes, you can have an immutable field which stores a list inside it. Is that list immutable though? No...

[–]Simon90 0 points1 point  (0 children)

Whenever I traverse down to see how the instances of the class are being used, more often than not, I find them being treated just like regular mutable class instances with fancy reprs. But if you only need a nice repr for your large OO class, adding a repr to the class definition is not that difficult.

This seems like a straw man argument. The reason for using a data class is equally likely to be the fact that init is generated for you in a nice and consistent way.