<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://mscneuro.neuro.uni-bremen.de/index.php?action=history&amp;feed=atom&amp;title=Dataclass</id>
	<title>Dataclass - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://mscneuro.neuro.uni-bremen.de/index.php?action=history&amp;feed=atom&amp;title=Dataclass"/>
	<link rel="alternate" type="text/html" href="https://mscneuro.neuro.uni-bremen.de/index.php?title=Dataclass&amp;action=history"/>
	<updated>2026-06-17T16:28:02Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://mscneuro.neuro.uni-bremen.de/index.php?title=Dataclass&amp;diff=339&amp;oldid=prev</id>
		<title>Davrot at 16:26, 17 October 2025</title>
		<link rel="alternate" type="text/html" href="https://mscneuro.neuro.uni-bremen.de/index.php?title=Dataclass&amp;diff=339&amp;oldid=prev"/>
		<updated>2025-10-17T16:26:10Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 16:26, 17 October 2025&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l1&quot;&gt;Line 1:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;== The goal ==&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-added&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;There is a new build-in [https://docs.python.org/3/library/dataclasses.html dataclass] class which is highly interesting for data scientists. Obviously it is a class for storing your data. Who would have guessed…&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;There is a new build-in [https://docs.python.org/3/library/dataclasses.html dataclass] class which is highly interesting for data scientists. Obviously it is a class for storing your data. Who would have guessed…&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;

&lt;!-- diff cache key wiki:diff:1.41:old-164:rev-339:php=table --&gt;
&lt;/table&gt;</summary>
		<author><name>Davrot</name></author>
	</entry>
	<entry>
		<id>https://mscneuro.neuro.uni-bremen.de/index.php?title=Dataclass&amp;diff=164&amp;oldid=prev</id>
		<title>Davrot: Created page with &quot; == The goal == There is a new build-in [https://docs.python.org/3/library/dataclasses.html dataclass] class which is highly interesting for data scientists. Obviously it is a class for storing your data. Who would have guessed…  Questions to [mailto:davrot@uni-bremen.de David Rotermund]  &#039;&#039;&#039;Type annotations required!!!&#039;&#039;&#039;  This is the first construct in Python that requires type annotation.  If we do this, we get this nice error!&lt;syntaxhighlight lang=&quot;python&quot;&gt;from dat...&quot;</title>
		<link rel="alternate" type="text/html" href="https://mscneuro.neuro.uni-bremen.de/index.php?title=Dataclass&amp;diff=164&amp;oldid=prev"/>
		<updated>2025-10-16T15:10:23Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot; == The goal == There is a new build-in [https://docs.python.org/3/library/dataclasses.html dataclass] class which is highly interesting for data scientists. Obviously it is a class for storing your data. Who would have guessed…  Questions to [mailto:davrot@uni-bremen.de David Rotermund]  &amp;#039;&amp;#039;&amp;#039;Type annotations required!!!&amp;#039;&amp;#039;&amp;#039;  This is the first construct in Python that requires type annotation.  If we do this, we get this nice error!&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;from dat...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;br /&gt;
== The goal ==&lt;br /&gt;
There is a new build-in [https://docs.python.org/3/library/dataclasses.html dataclass] class which is highly interesting for data scientists. Obviously it is a class for storing your data. Who would have guessed…&lt;br /&gt;
&lt;br /&gt;
Questions to [mailto:davrot@uni-bremen.de David Rotermund]&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Type annotations required!!!&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
This is the first construct in Python that requires type annotation.&lt;br /&gt;
&lt;br /&gt;
If we do this, we get this nice error!&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;from dataclasses import dataclass&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@dataclass&lt;br /&gt;
class TestClass:&lt;br /&gt;
    a # -&amp;gt; NameError: name &amp;#039;a&amp;#039; is not defined&lt;br /&gt;
    b&amp;lt;/syntaxhighlight&amp;gt;With type annotations:&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;from dataclasses import dataclass&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@dataclass&lt;br /&gt;
class TestClass:&lt;br /&gt;
    a: int&lt;br /&gt;
    b: str&amp;lt;/syntaxhighlight&amp;gt;No error!!!&lt;br /&gt;
&lt;br /&gt;
== What is a dataclass? ==&lt;br /&gt;
[https://docs.python.org/3/library/dataclasses.html @dataclass] is a decorator that tells Python that this class is a dataclass. A dataclass is a class with different properties compared to a normal class.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;from dataclasses import dataclass&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@dataclass&lt;br /&gt;
class TestClassA:&lt;br /&gt;
    name: str&lt;br /&gt;
    number_of_electrodes: int&lt;br /&gt;
    sample_rate_in_hz: float&lt;br /&gt;
    dt: float&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
data_1 = TestClassA(&amp;quot;Dataset A&amp;quot;, 100, 1000, 1 / 1000)&lt;br /&gt;
print(data_1)&amp;lt;/syntaxhighlight&amp;gt;Output:&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;TestClassA(name=&amp;#039;Dataset A&amp;#039;, number_of_electrodes=100, sample_rate_in_hz=1000, dt=0.001)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Default values ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;from dataclasses import dataclass&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@dataclass&lt;br /&gt;
class TestClassA:&lt;br /&gt;
    name: str&lt;br /&gt;
    number_of_electrodes: int&lt;br /&gt;
    dt: float&lt;br /&gt;
    sample_rate_in_hz: float = 1000.0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
data_1 = TestClassA(&amp;quot;Dataset A&amp;quot;, 100, 1 / 1000)&lt;br /&gt;
print(data_1)&amp;lt;/syntaxhighlight&amp;gt;Output:&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;TestClassA(name=&amp;#039;Dataset A&amp;#039;, number_of_electrodes=100, dt=0.001, sample_rate_in_hz=1000.0)&amp;lt;/syntaxhighlight&amp;gt;An alternative is to use field with the default argument:&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;from dataclasses import dataclass, field&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@dataclass&lt;br /&gt;
class TestClassA:&lt;br /&gt;
    name: str&lt;br /&gt;
    number_of_electrodes: int&lt;br /&gt;
    dt: float&lt;br /&gt;
    sample_rate_in_hz: float = field(default=1000.0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
data_1 = TestClassA(&amp;quot;Dataset A&amp;quot;, 100, 1 / 1000)&lt;br /&gt;
print(data_1)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Default factory ==&lt;br /&gt;
We can use the field’s default_factory to put suitable generic default into attributes. default and default_factory can not used together. Why should we use a default_factory? Well, please see the problem with [https://docs.python.org/3/glossary.html#term-mutable mutable] objects in the [https://docs.python.org/3/tutorial/classes.html#class-and-instance-variables official Python documentation]. Or in other words: Using = [ ] as default will cause you pain.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;from dataclasses import dataclass, field&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@dataclass&lt;br /&gt;
class TestClassA:&lt;br /&gt;
    name: str = field(default_factory=str)&lt;br /&gt;
    number_of_electrodes: int = field(default_factory=int)&lt;br /&gt;
    dt: float = field(default_factory=float)&lt;br /&gt;
    sample_rate_in_hz: float = field(default_factory=float)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
data_1 = TestClassA()&lt;br /&gt;
print(data_1)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Keyword only attributes (Python &amp;amp;#x3E;= 3.10) ==&lt;br /&gt;
We can mark attributes as key word only (kw_only=true). Normally we would need them to put at the end of the definition of attributes. However, with this allows us to mix it in between:&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;from dataclasses import dataclass, field&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@dataclass&lt;br /&gt;
class TestClassA:&lt;br /&gt;
    name: str&lt;br /&gt;
    number_of_electrodes: int = field(kw_only=True, default=42)&lt;br /&gt;
    dt: float = field(init=False)&lt;br /&gt;
    sample_rate_in_hz: float = 1000.0&lt;br /&gt;
&lt;br /&gt;
    def __post_init__(self) -&amp;gt; None:&lt;br /&gt;
        self.dt = 1.0 / self.sample_rate_in_hz&lt;br /&gt;
&lt;br /&gt;
    def __str__(self) -&amp;gt; str:&lt;br /&gt;
        output: str = (&lt;br /&gt;
            f&amp;quot;Name: {self.name}&amp;quot;&lt;br /&gt;
            &amp;quot;\n&amp;quot;&lt;br /&gt;
            f&amp;quot;Number of electrodes: {self.number_of_electrodes}&amp;quot;&lt;br /&gt;
            &amp;quot;\n&amp;quot;&lt;br /&gt;
            f&amp;quot;dt: {self.dt:.4f}s&amp;quot;&lt;br /&gt;
            &amp;quot;\n&amp;quot;&lt;br /&gt;
            f&amp;quot;Sample Rate: {self.sample_rate_in_hz:.2f}Hz&amp;quot;&lt;br /&gt;
        )&lt;br /&gt;
        return output&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
data_1 = TestClassA(&amp;quot;Dataset A&amp;quot;, 500)&lt;br /&gt;
print(data_1)&lt;br /&gt;
print(&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
data_2 = TestClassA(&amp;quot;Dataset B&amp;quot;, 500, number_of_electrodes=33)&lt;br /&gt;
print(data_2)&amp;lt;/syntaxhighlight&amp;gt;Output:&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;Name: Dataset A&lt;br /&gt;
Number of electrodes: 42&lt;br /&gt;
dt: 0.0020s&lt;br /&gt;
Sample Rate: 500.00Hz&lt;br /&gt;
&lt;br /&gt;
Name: Dataset B&lt;br /&gt;
Number of electrodes: 33&lt;br /&gt;
dt: 0.0020s&lt;br /&gt;
Sample Rate: 500.00Hz&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== def __post_init__(self): ==&lt;br /&gt;
We can do operations after the init:&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;from dataclasses import dataclass, field&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@dataclass&lt;br /&gt;
class TestClassA:&lt;br /&gt;
    name: str&lt;br /&gt;
    number_of_electrodes: int&lt;br /&gt;
    dt: float = field(init=False)&lt;br /&gt;
    sample_rate_in_hz: float = 1000.0&lt;br /&gt;
&lt;br /&gt;
    def __post_init__(self) -&amp;gt; None:&lt;br /&gt;
        self.dt = 1.0 / self.sample_rate_in_hz&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
data_1 = TestClassA(&amp;quot;Dataset A&amp;quot;, 100, 500)&lt;br /&gt;
print(data_1)&amp;lt;/syntaxhighlight&amp;gt;Output:&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;TestClassA(name=&amp;#039;Dataset A&amp;#039;, number_of_electrodes=100, dt=0.002, sample_rate_in_hz=500)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== def __str__(self): ==&lt;br /&gt;
Make the print output nicer:&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;from dataclasses import dataclass, field&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@dataclass&lt;br /&gt;
class TestClassA:&lt;br /&gt;
    name: str&lt;br /&gt;
    number_of_electrodes: int&lt;br /&gt;
    dt: float = field(init=False)&lt;br /&gt;
    sample_rate_in_hz: float = 1000.0&lt;br /&gt;
&lt;br /&gt;
    def __post_init__(self) -&amp;gt; None:&lt;br /&gt;
        self.dt = 1.0 / self.sample_rate_in_hz&lt;br /&gt;
&lt;br /&gt;
    def __str__(self) -&amp;gt; str:&lt;br /&gt;
        output: str = (&lt;br /&gt;
            f&amp;quot;Name: {self.name}&amp;quot;&lt;br /&gt;
            &amp;quot;\n&amp;quot;&lt;br /&gt;
            f&amp;quot;Number of electrodes: {self.number_of_electrodes}&amp;quot;&lt;br /&gt;
            &amp;quot;\n&amp;quot;&lt;br /&gt;
            f&amp;quot;dt: {self.dt:.4f}s&amp;quot;&lt;br /&gt;
            &amp;quot;\n&amp;quot;&lt;br /&gt;
            f&amp;quot;Sample Rate: {self.sample_rate_in_hz:.2f}Hz&amp;quot;&lt;br /&gt;
        )&lt;br /&gt;
        return output&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
data_1 = TestClassA(&amp;quot;Dataset A&amp;quot;, 100, 500)&lt;br /&gt;
print(data_1)&amp;lt;/syntaxhighlight&amp;gt;Output&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;Name: Dataset A&lt;br /&gt;
Number of electrodes: 100&lt;br /&gt;
dt: 0.0020s&lt;br /&gt;
Sample Rate: 500.00Hz&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Read Only data ==&lt;br /&gt;
We can protect the data from being modified later. Note: If we need to modify data in e.g. the __post_init__ function then we need to use object.__setattr__.&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;from dataclasses import dataclass, field&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@dataclass(frozen=True)&lt;br /&gt;
class TestClassA:&lt;br /&gt;
    name: str&lt;br /&gt;
    number_of_electrodes: int&lt;br /&gt;
    dt: float = field(init=False)&lt;br /&gt;
    sample_rate_in_hz: float = 1000.0&lt;br /&gt;
&lt;br /&gt;
    def __post_init__(self) -&amp;gt; None:&lt;br /&gt;
        object.__setattr__(self, &amp;quot;dt&amp;quot;, 1.0 / self.sample_rate_in_hz)&lt;br /&gt;
&lt;br /&gt;
    def __str__(self) -&amp;gt; str:&lt;br /&gt;
        output: str = (&lt;br /&gt;
            f&amp;quot;Name: {self.name}&amp;quot;&lt;br /&gt;
            &amp;quot;\n&amp;quot;&lt;br /&gt;
            f&amp;quot;Number of electrodes: {self.number_of_electrodes}&amp;quot;&lt;br /&gt;
            &amp;quot;\n&amp;quot;&lt;br /&gt;
            f&amp;quot;dt: {self.dt:.4f}s&amp;quot;&lt;br /&gt;
            &amp;quot;\n&amp;quot;&lt;br /&gt;
            f&amp;quot;Sample Rate: {self.sample_rate_in_hz:.2f}Hz&amp;quot;&lt;br /&gt;
        )&lt;br /&gt;
        return output&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
data_1 = TestClassA(&amp;quot;Dataset A&amp;quot;, 100, 500)&lt;br /&gt;
data_1.name = &amp;quot;New Name&amp;quot; #  -&amp;gt; FrozenInstanceError: cannot assign to field &amp;#039;name&amp;#039;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Inheritance ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;from dataclasses import dataclass&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@dataclass&lt;br /&gt;
class BasicDataset:&lt;br /&gt;
    x: int = 1&lt;br /&gt;
    y: int = 2&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@dataclass&lt;br /&gt;
class NewDataSet(BasicDataset):&lt;br /&gt;
    a: int = 3&lt;br /&gt;
    x: int = 4&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
data_1 = BasicDataset()&lt;br /&gt;
print(data_1)&lt;br /&gt;
data_2 = NewDataSet()&lt;br /&gt;
print(data_2)&amp;lt;/syntaxhighlight&amp;gt;Output:&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;BasicDataset(x=1, y=2)&lt;br /&gt;
NewDataSet(x=4, y=2, a=3)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Why should want we to use a data class? ==&lt;br /&gt;
&lt;br /&gt;
=== Comparing datasets ===&lt;br /&gt;
We can compare datasets now&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;from dataclasses import dataclass&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@dataclass&lt;br /&gt;
class MyDataset:&lt;br /&gt;
    x: int&lt;br /&gt;
    y: int&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
data_1a = MyDataset(x=1, y=1)&lt;br /&gt;
data_1b = MyDataset(x=1, y=1)&lt;br /&gt;
print(data_1a == data_1b)&lt;br /&gt;
data_2 = MyDataset(x=1, y=2)&lt;br /&gt;
print(data_1a == data_2)&amp;lt;/syntaxhighlight&amp;gt;Output:&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;True&lt;br /&gt;
False&amp;lt;/syntaxhighlight&amp;gt;We can remove attributes from the comparison&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;from dataclasses import dataclass, field&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@dataclass&lt;br /&gt;
class MyDataset:&lt;br /&gt;
    x: int&lt;br /&gt;
    y: int = field(compare=False)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
data_1a = MyDataset(x=1, y=1)&lt;br /&gt;
data_1b = MyDataset(x=1, y=1)&lt;br /&gt;
print(data_1a == data_1b)&lt;br /&gt;
data_2 = MyDataset(x=1, y=2)&lt;br /&gt;
print(data_1a == data_2)&amp;lt;/syntaxhighlight&amp;gt;Output:&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;True&lt;br /&gt;
True&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Sorting datasets ===&lt;br /&gt;
We can add a custom sort_index attribute. Which we can also hide with [https://docs.python.org/3/library/dataclasses.html#dataclasses.field repr=False]:&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;from dataclasses import dataclass&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@dataclass(order=True)&lt;br /&gt;
class MyDataset:&lt;br /&gt;
    sort_index: int = field(init=False, repr=False)&lt;br /&gt;
    x: int&lt;br /&gt;
    y: int&lt;br /&gt;
&lt;br /&gt;
    def __post_init__(self):&lt;br /&gt;
        self.sort_index = self.x + self.y * 10&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
data_0 = MyDataset(x=2, y=2)&lt;br /&gt;
data_1 = MyDataset(x=1, y=1)&lt;br /&gt;
data_2 = MyDataset(x=1, y=2)&lt;br /&gt;
data_3 = MyDataset(x=1, y=2)&lt;br /&gt;
&lt;br /&gt;
print([data_0, data_1, data_2, data_3])&lt;br /&gt;
print(&amp;quot;&amp;quot;)&lt;br /&gt;
print(sorted([data_0, data_1, data_2, data_3]))&amp;lt;/syntaxhighlight&amp;gt;Output:&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;[MyDataset(x=2, y=2), MyDataset(x=1, y=1), MyDataset(x=1, y=2), MyDataset(x=1, y=2)]&lt;br /&gt;
&lt;br /&gt;
[MyDataset(x=1, y=1), MyDataset(x=1, y=2), MyDataset(x=1, y=2), MyDataset(x=2, y=2)]&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Slots (Python &amp;amp;#x3E;= 3.10) ==&lt;br /&gt;
{: .topic-optional} This is an optional topic!&lt;br /&gt;
&lt;br /&gt;
What? Slots?&lt;br /&gt;
&lt;br /&gt;
[https://docs.python.org/3/reference/datamodel.html#slots 3.3.2.4. __slots__] &amp;amp;#x3E; The space saved over using __dict__ can be significant. Attribute lookup speed can be significantly improved as well.&lt;br /&gt;
&lt;br /&gt;
Normally:&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;from dataclasses import dataclass&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@dataclass&lt;br /&gt;
class MyDataset:&lt;br /&gt;
    x: int&lt;br /&gt;
    y: int&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
data_0 = MyDataset(x=2, y=2)&lt;br /&gt;
print(data_0.__dict__)&lt;br /&gt;
data_0.a = 1&lt;br /&gt;
print(data_0.__dict__)&amp;lt;/syntaxhighlight&amp;gt;Output:&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;{&amp;#039;x&amp;#039;: 2, &amp;#039;y&amp;#039;: 2}&lt;br /&gt;
{&amp;#039;x&amp;#039;: 2, &amp;#039;y&amp;#039;: 2, &amp;#039;a&amp;#039;: 1}&amp;lt;/syntaxhighlight&amp;gt;With slots=True:&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;from dataclasses import dataclass&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@dataclass(slots=True)&lt;br /&gt;
class MyDataset:&lt;br /&gt;
    x: int&lt;br /&gt;
    y: int&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
data_0 = MyDataset(x=2, y=2)&lt;br /&gt;
print(data_0.__dict__)  # -&amp;gt; AttributeError: &amp;#039;MyDataset&amp;#039; object has no attribute &amp;#039;__dict__&amp;#039;&lt;br /&gt;
data_0.a = 1  # -&amp;gt; AttributeError: &amp;#039;MyDataset&amp;#039; object has no attribute &amp;#039;a&amp;#039;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Convert to tuple / dictionary ==&lt;br /&gt;
We can easily convert a dataclass object and convert it into a tuple or dictionary:&amp;lt;pre class=&amp;quot;python:&amp;quot;&amp;gt;from dataclasses import dataclass, astuple, asdict&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@dataclass&lt;br /&gt;
class MyDataset:&lt;br /&gt;
    x: int&lt;br /&gt;
    y: int&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
data_0 = MyDataset(x=2, y=2)&lt;br /&gt;
data_tuple = astuple(data_0)&lt;br /&gt;
data_dict = asdict(data_0)&lt;br /&gt;
print(data_tuple)&lt;br /&gt;
print(data_dict)&amp;lt;/pre&amp;gt;Output:&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;(2, 2)&lt;br /&gt;
{&amp;#039;x&amp;#039;: 2, &amp;#039;y&amp;#039;: 2}&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== dataclasses_json ==&lt;br /&gt;
If this third party package is missing:&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;pip install dataclasses-json&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== JSON ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;from dataclasses import dataclass, field&lt;br /&gt;
import dataclasses_json&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@dataclasses_json.dataclass_json&lt;br /&gt;
@dataclass(frozen=True)&lt;br /&gt;
class TestClassA:&lt;br /&gt;
    name: str&lt;br /&gt;
    number_of_electrodes: int&lt;br /&gt;
    dt: float = field(init=False)&lt;br /&gt;
    sample_rate_in_hz: float = 1000.0&lt;br /&gt;
&lt;br /&gt;
    def __post_init__(self) -&amp;gt; None:&lt;br /&gt;
        object.__setattr__(self, &amp;quot;dt&amp;quot;, 1.0 / self.sample_rate_in_hz)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
data_1 = TestClassA(&amp;quot;Dataset A&amp;quot;, 100, 500)&lt;br /&gt;
print(data_1)&lt;br /&gt;
print(&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;as JSON:&amp;quot;)&lt;br /&gt;
string_json = data_1.to_json()&lt;br /&gt;
print(string_json)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
data_2 = TestClassA.from_json(string_json)&lt;br /&gt;
print(data_2)&amp;lt;/syntaxhighlight&amp;gt;Output:&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;TestClassA(name=&amp;#039;Dataset A&amp;#039;, number_of_electrodes=100, dt=0.002, sample_rate_in_hz=500)&lt;br /&gt;
&lt;br /&gt;
as JSON:&lt;br /&gt;
{&amp;quot;name&amp;quot;: &amp;quot;Dataset A&amp;quot;, &amp;quot;number_of_electrodes&amp;quot;: 100, &amp;quot;dt&amp;quot;: 0.002, &amp;quot;sample_rate_in_hz&amp;quot;: 500}&lt;br /&gt;
&lt;br /&gt;
TestClassA(name=&amp;#039;Dataset A&amp;#039;, number_of_electrodes=100, dt=0.002, sample_rate_in_hz=500)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dict ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;from dataclasses import dataclass, field&lt;br /&gt;
import dataclasses_json&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@dataclasses_json.dataclass_json&lt;br /&gt;
@dataclass(frozen=True)&lt;br /&gt;
class TestClassA:&lt;br /&gt;
    name: str&lt;br /&gt;
    number_of_electrodes: int&lt;br /&gt;
    dt: float = field(init=False)&lt;br /&gt;
    sample_rate_in_hz: float = 1000.0&lt;br /&gt;
&lt;br /&gt;
    def __post_init__(self) -&amp;gt; None:&lt;br /&gt;
        object.__setattr__(self, &amp;quot;dt&amp;quot;, 1.0 / self.sample_rate_in_hz)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
data_1 = TestClassA(&amp;quot;Dataset A&amp;quot;, 100, 500)&lt;br /&gt;
print(data_1)&lt;br /&gt;
print(&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;as dict:&amp;quot;)&lt;br /&gt;
string_dict = data_1.to_dict()&lt;br /&gt;
print(string_dict)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
data_2 = TestClassA.from_dict(string_dict)&lt;br /&gt;
print(data_2)&amp;lt;/syntaxhighlight&amp;gt;Output:&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;TestClassA(name=&amp;#039;Dataset A&amp;#039;, number_of_electrodes=100, dt=0.002, sample_rate_in_hz=500)&lt;br /&gt;
&lt;br /&gt;
as dict:&lt;br /&gt;
{&amp;#039;name&amp;#039;: &amp;#039;Dataset A&amp;#039;, &amp;#039;number_of_electrodes&amp;#039;: 100, &amp;#039;dt&amp;#039;: 0.002, &amp;#039;sample_rate_in_hz&amp;#039;: 500}&lt;br /&gt;
&lt;br /&gt;
TestClassA(name=&amp;#039;Dataset A&amp;#039;, number_of_electrodes=100, dt=0.002, sample_rate_in_hz=500)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Pickle (deals with numpy ndarray) ===&lt;br /&gt;
While JSON doesn’t like numpy ndarrays, pickle has no problem with it. But we loose the human readability. An example:&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;from dataclasses import dataclass&lt;br /&gt;
import numpy as np&lt;br /&gt;
import pickle&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@dataclass&lt;br /&gt;
class TestClassA:&lt;br /&gt;
    name: str&lt;br /&gt;
    measured_data: np.ndarray&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
rng = np.random.default_rng()&lt;br /&gt;
data_1 = TestClassA(name=&amp;quot;Recording X&amp;quot;, measured_data=rng.random((3, 6)))&lt;br /&gt;
print(data_1)&lt;br /&gt;
print(&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;as pickle string:&amp;quot;)&lt;br /&gt;
string_pickle = pickle.dumps(data_1)&lt;br /&gt;
print(string_pickle)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
data_2 = pickle.loads(string_pickle)&lt;br /&gt;
print(data_2)&amp;lt;/syntaxhighlight&amp;gt;Output&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;TestClassA(name=&amp;#039;Recording X&amp;#039;, measured_data=array([[0.03041124, 0.90241323, 0.06146134, 0.0207697 , 0.03924572,&lt;br /&gt;
        0.62343829],&lt;br /&gt;
       [0.03930966, 0.34830424, 0.53869473, 0.76964259, 0.64897337,&lt;br /&gt;
        0.76441662],&lt;br /&gt;
       [0.40438748, 0.95079476, 0.44350839, 0.17806159, 0.31114876,&lt;br /&gt;
        0.59675174]]))&lt;br /&gt;
&lt;br /&gt;
as pickle string:&lt;br /&gt;
b&amp;#039;\x80\x04\x95a\x01\x00\x00\x00\x00\x00\x00\x8c\x08__main__\x94\x8c\nTestClassA\x94\x93\x94)\x81\x94}\x94(\x8c\x04name\x94\x8c\x0bRecording X\x94\x8c\rmeasured_data\x94\x8c\x15numpy.core.multiarray\x94\x8c\x0c_reconstruct\x94\x93\x94\x8c\x05numpy\x94\x8c\x07ndarray\x94\x93\x94K\x00\x85\x94C\x01b\x94\x87\x94R\x94(K\x01K\x03K\x06\x86\x94h\x0b\x8c\x05dtype\x94\x93\x94\x8c\x02f8\x94\x89\x88\x87\x94R\x94(K\x03\x8c\x01&amp;lt;\x94NNNJ\xff\xff\xff\xffJ\xff\xff\xff\xffK\x00t\x94b\x89C\x90\xe0\xd1r\xb1\x1f$\x9f?\xbe\xa8\xb8\xb5\x91\xe0\xec?\xc0i\xf35\xdcw\xaf?\x00NT)\xa7D\x95?\xe0\xca\x9e\xdc\x03\x18\xa4?\xc0\x12&amp;amp;\xdb4\xf3\xe3?\xe0.\xd2Xe \xa4?\x16\xb4\xbc\xde\x9dJ\xd6?\x95\x00\x03\xbc\xfc&amp;lt;\xe1?5\xb3U\x80\xe9\xa0\xe8?-\r\x8d\xccc\xc4\xe4?4\x1e8\xd7\x19v\xe8?\\c\xb3\t|\xe1\xd9?\xcf\xaf\xbb#\xe9l\xee?R/5\x07qb\xdc?\xecr\xdd\xe3\xb8\xca\xc6?\x10\x12R~\xdc\xe9\xd3?\xcfz;\x1d\x97\x18\xe3?\x94t\x94bub.&amp;#039;&lt;br /&gt;
&lt;br /&gt;
TestClassA(name=&amp;#039;Recording X&amp;#039;, measured_data=array([[0.03041124, 0.90241323, 0.06146134, 0.0207697 , 0.03924572,&lt;br /&gt;
        0.62343829],&lt;br /&gt;
       [0.03930966, 0.34830424, 0.53869473, 0.76964259, 0.64897337,&lt;br /&gt;
        0.76441662],&lt;br /&gt;
       [0.40438748, 0.95079476, 0.44350839, 0.17806159, 0.31114876,&lt;br /&gt;
        0.59675174]]))&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Davrot</name></author>
	</entry>
</feed>