A place to cache linked articles (think custom and personal wayback machine)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. <!doctype html><!-- This is a valid HTML5 document. -->
  2. <!-- Screen readers, SEO, extensions and so on. -->
  3. <html lang="fr">
  4. <!-- Has to be within the first 1024 bytes, hence before the `title` element
  5. See: https://www.w3.org/TR/2012/CR-html5-20121217/document-metadata.html#charset -->
  6. <meta charset="utf-8">
  7. <!-- Why no `X-UA-Compatible` meta: https://stackoverflow.com/a/6771584 -->
  8. <!-- The viewport meta is quite crowded and we are responsible for that.
  9. See: https://codepen.io/tigt/post/meta-viewport-for-2015 -->
  10. <meta name="viewport" content="width=device-width,initial-scale=1">
  11. <!-- Required to make a valid HTML5 document. -->
  12. <title>dataklasses: A different spin on dataclasses. (archive) — David Larlet</title>
  13. <meta name="description" content="Publication mise en cache pour en conserver une trace.">
  14. <!-- That good ol' feed, subscribe :). -->
  15. <link rel="alternate" type="application/atom+xml" title="Feed" href="/david/log/">
  16. <!-- Generated from https://realfavicongenerator.net/ such a mess. -->
  17. <link rel="apple-touch-icon" sizes="180x180" href="/static/david/icons2/apple-touch-icon.png">
  18. <link rel="icon" type="image/png" sizes="32x32" href="/static/david/icons2/favicon-32x32.png">
  19. <link rel="icon" type="image/png" sizes="16x16" href="/static/david/icons2/favicon-16x16.png">
  20. <link rel="manifest" href="/static/david/icons2/site.webmanifest">
  21. <link rel="mask-icon" href="/static/david/icons2/safari-pinned-tab.svg" color="#07486c">
  22. <link rel="shortcut icon" href="/static/david/icons2/favicon.ico">
  23. <meta name="msapplication-TileColor" content="#f7f7f7">
  24. <meta name="msapplication-config" content="/static/david/icons2/browserconfig.xml">
  25. <meta name="theme-color" content="#f7f7f7" media="(prefers-color-scheme: light)">
  26. <meta name="theme-color" content="#272727" media="(prefers-color-scheme: dark)">
  27. <!-- Documented, feel free to shoot an email. -->
  28. <link rel="stylesheet" href="/static/david/css/style_2021-01-20.css">
  29. <!-- See https://www.zachleat.com/web/comprehensive-webfonts/ for the trade-off. -->
  30. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  31. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  32. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  33. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  34. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  35. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  36. <script>
  37. function toggleTheme(themeName) {
  38. document.documentElement.classList.toggle(
  39. 'forced-dark',
  40. themeName === 'dark'
  41. )
  42. document.documentElement.classList.toggle(
  43. 'forced-light',
  44. themeName === 'light'
  45. )
  46. }
  47. const selectedTheme = localStorage.getItem('theme')
  48. if (selectedTheme !== 'undefined') {
  49. toggleTheme(selectedTheme)
  50. }
  51. </script>
  52. <meta name="robots" content="noindex, nofollow">
  53. <meta content="origin-when-cross-origin" name="referrer">
  54. <!-- Canonical URL for SEO purposes -->
  55. <link rel="canonical" href="https://github.com/dabeaz/dataklasses#questions-and-answers">
  56. <body class="remarkdown h1-underline h2-underline h3-underline em-underscore hr-center ul-star pre-tick" data-instant-intensity="viewport-all">
  57. <article>
  58. <header>
  59. <h1>dataklasses: A different spin on dataclasses.</h1>
  60. </header>
  61. <nav>
  62. <p class="center">
  63. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  64. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use>
  65. </svg> Accueil</a> •
  66. <a href="https://github.com/dabeaz/dataklasses#questions-and-answers" title="Lien vers le contenu original">Source originale</a>
  67. </p>
  68. </nav>
  69. <hr>
  70. <p>Dataklasses is a library that allows you to quickly define data
  71. classes using Python type hints. Here's an example of how you use it:</p>
  72. <p>```python
  73. from dataklasses import dataklass</p>
  74. <p>@dataklass
  75. class Coordinates:
  76. x: int
  77. y: int
  78. ```</p>
  79. <p>The resulting class works in a well civilised way, providing the usual
  80. <code>__init__()</code>, <code>__repr__()</code>, and <code>__eq__()</code> methods that you'd normally
  81. have to type out by hand:</p>
  82. <p>```python</p>
  83. <blockquote>
  84. <blockquote>
  85. <blockquote>
  86. <p>a = Coordinates(2, 3)
  87. a
  88. Coordinates(2, 3)
  89. a.x
  90. 2
  91. a.y
  92. 3
  93. b = Coordinates(2, 3)
  94. a == b
  95. True</p>
  96. <p>```</p>
  97. </blockquote>
  98. </blockquote>
  99. </blockquote>
  100. <p>It's easy! Almost too easy.</p>
  101. <h2>Wait, doesn't this already exist?</h2>
  102. <p>No, it doesn't. Yes, certain naysayers will be quick to point out the
  103. existence of <code>@dataclass</code> from the standard library. Ok, sure, THAT
  104. exists. However, it's slow and complicated. Dataklasses are neither
  105. of those things. The entire <code>dataklasses</code> module is less than 100
  106. lines. The resulting classes import 15-20 times faster than
  107. dataclasses. See the <code>perf.py</code> file for a benchmark.</p>
  108. <h2>Theory of Operation</h2>
  109. <p>While out walking with his puppy, Dave had a certain insight about the nature
  110. of Python byte-code. Coming back to the house, he had to try it out:</p>
  111. <p>```python</p>
  112. <blockquote>
  113. <blockquote>
  114. <blockquote>
  115. <p>def <strong>init1</strong>(self, x, y):
  116. ... self.x = x
  117. ... self.y = y
  118. ...
  119. def <strong>init2</strong>(self, foo, bar):
  120. ... self.foo = foo
  121. ... self.bar = bar
  122. ...
  123. <strong>init1</strong>.<strong>code</strong>.co_code == <strong>init2</strong>.<strong>code</strong>.co_code
  124. True</p>
  125. <p>```</p>
  126. </blockquote>
  127. </blockquote>
  128. </blockquote>
  129. <p>How intriguing! The underlying byte-code is exactly the same even
  130. though the functions are using different argument and attribute names.
  131. Aha! Now, we're onto something interesting.</p>
  132. <p>The <code>dataclasses</code> module in the standard library works by collecting
  133. type hints, generating code strings, and executing them using the
  134. <code>exec()</code> function. This happens for every single class definition
  135. where it's used. If it sounds slow, that's because it is. In fact, it
  136. defeats any benefit of module caching in Python's import system.</p>
  137. <p>Dataklasses are different. They start out in the same manner--code is
  138. first generated by collecting type hints and using <code>exec()</code>. However,
  139. the underlying byte-code is cached and reused in subsequent class
  140. definitions whenever possible. Caching is good. </p>
  141. <h2>A Short Story</h2>
  142. <p>Once upon a time, there was this programming language that I'll refer
  143. to as "Lava." Anyways, anytime you started a program written in Lava,
  144. you could just tell by the awkward silence and inactivity of your
  145. machine before the fans kicked in. "Ah shit, this is written in Lava"
  146. you'd exclaim.</p>
  147. <h2>Questions and Answers</h2>
  148. <p><strong>Q: What methods does <code>dataklass</code> generate?</strong></p>
  149. <p>A: By default <code>__init__()</code>, <code>__repr__()</code>, and <code>__eq__()</code> methods are generated.
  150. <code>__match_args__</code> is also defined to assist with pattern matching.</p>
  151. <p><strong>Q: Does <code>dataklass</code> enforce the specified types?</strong></p>
  152. <p>A: No. The types are merely clues about what the value might be and
  153. the Python language does not provide any enforcement on its own. </p>
  154. <p><strong>Q: Are there any additional features?</strong></p>
  155. <p>A: No. You can either have features or you can have performance. Pick one.</p>
  156. <p><strong>Q: Does <code>dataklass</code> use any advanced magic such as metaclasses?</strong></p>
  157. <p>A: No. </p>
  158. <p><strong>Q: How do I install <code>dataklasses</code>?</strong></p>
  159. <p>A: There is no <code>setup.py</code> file, installer, or an official release. You
  160. install it by copying the code into your own project. <code>dataklasses.py</code> is
  161. small. You are encouraged to modify it to your own purposes.</p>
  162. <p><strong>Q: What versions of Python does it work with?</strong></p>
  163. <p>A: The code will work with versions 3.9 and later.</p>
  164. <p><strong>Q: But what if new features get added?</strong></p>
  165. <p>A: What new features? The best new features are no new features. </p>
  166. <p><strong>Q: Who maintains dataklasses?</strong></p>
  167. <p>A: If you're using it, you do. You maintain dataklasses.</p>
  168. <p><strong>Q: Is this actually a serious project?</strong></p>
  169. <p>A: It's best to think of dataklasses as more of an idea than a project.
  170. There are many tools and libraries that perform some form of code generation.
  171. Dataklasses is a proof-of-concept for a different approach to that. If you're
  172. a minimalist like me, you'll find it to be perfectly functional. If you're
  173. looking for a lot of knobs to turn, you should probably move along.</p>
  174. <p><strong>Q: Should I give dataklasses a GitHub star?</strong></p>
  175. <p>A: Yes, because it will help me look superior to the other parents with
  176. kids in the middle-school robot club.</p>
  177. <p><strong>Q: Who wrote this?</strong></p>
  178. <p>A: <code>dataklasses</code> is the work of David Beazley. http://www.dabeaz.com.</p>
  179. </article>
  180. <hr>
  181. <footer>
  182. <p>
  183. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  184. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use>
  185. </svg> Accueil</a> •
  186. <a href="/david/log/" title="Accès au flux RSS"><svg class="icon icon-rss2">
  187. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-rss2"></use>
  188. </svg> Suivre</a> •
  189. <a href="http://larlet.com" title="Go to my English profile" data-instant><svg class="icon icon-user-tie">
  190. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-user-tie"></use>
  191. </svg> Pro</a> •
  192. <a href="mailto:david%40larlet.fr" title="Envoyer un courriel"><svg class="icon icon-mail">
  193. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-mail"></use>
  194. </svg> Email</a> •
  195. <abbr class="nowrap" title="Hébergeur : Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33184162340"><svg class="icon icon-hammer2">
  196. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-hammer2"></use>
  197. </svg> Légal</abbr>
  198. </p>
  199. <template id="theme-selector">
  200. <form>
  201. <fieldset>
  202. <legend><svg class="icon icon-brightness-contrast">
  203. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-brightness-contrast"></use>
  204. </svg> Thème</legend>
  205. <label>
  206. <input type="radio" value="auto" name="chosen-color-scheme" checked> Auto
  207. </label>
  208. <label>
  209. <input type="radio" value="dark" name="chosen-color-scheme"> Foncé
  210. </label>
  211. <label>
  212. <input type="radio" value="light" name="chosen-color-scheme"> Clair
  213. </label>
  214. </fieldset>
  215. </form>
  216. </template>
  217. </footer>
  218. <script src="/static/david/js/instantpage-5.1.0.min.js" type="module"></script>
  219. <script>
  220. function loadThemeForm(templateName) {
  221. const themeSelectorTemplate = document.querySelector(templateName)
  222. const form = themeSelectorTemplate.content.firstElementChild
  223. themeSelectorTemplate.replaceWith(form)
  224. form.addEventListener('change', (e) => {
  225. const chosenColorScheme = e.target.value
  226. localStorage.setItem('theme', chosenColorScheme)
  227. toggleTheme(chosenColorScheme)
  228. })
  229. const selectedTheme = localStorage.getItem('theme')
  230. if (selectedTheme && selectedTheme !== 'undefined') {
  231. form.querySelector(`[value="${selectedTheme}"]`).checked = true
  232. }
  233. }
  234. const prefersColorSchemeDark = '(prefers-color-scheme: dark)'
  235. window.addEventListener('load', () => {
  236. let hasDarkRules = false
  237. for (const styleSheet of Array.from(document.styleSheets)) {
  238. let mediaRules = []
  239. for (const cssRule of styleSheet.cssRules) {
  240. if (cssRule.type !== CSSRule.MEDIA_RULE) {
  241. continue
  242. }
  243. // WARNING: Safari does not have/supports `conditionText`.
  244. if (cssRule.conditionText) {
  245. if (cssRule.conditionText !== prefersColorSchemeDark) {
  246. continue
  247. }
  248. } else {
  249. if (cssRule.cssText.startsWith(prefersColorSchemeDark)) {
  250. continue
  251. }
  252. }
  253. mediaRules = mediaRules.concat(Array.from(cssRule.cssRules))
  254. }
  255. // WARNING: do not try to insert a Rule to a styleSheet you are
  256. // currently iterating on, otherwise the browser will be stuck
  257. // in a infinite loop…
  258. for (const mediaRule of mediaRules) {
  259. styleSheet.insertRule(mediaRule.cssText)
  260. hasDarkRules = true
  261. }
  262. }
  263. if (hasDarkRules) {
  264. loadThemeForm('#theme-selector')
  265. }
  266. })
  267. </script>
  268. </body>
  269. </html>