This file is indexed.

/usr/share/doc/python-attr/html/why.html is in python-attr-doc 17.4.0-2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Why not… &#8212; attrs 17.4.0 documentation</title>
    <link rel="stylesheet" href="_static/alabaster.css" type="text/css" />
    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
    <script type="text/javascript">
      var DOCUMENTATION_OPTIONS = {
        URL_ROOT:    './',
        VERSION:     '17.4.0',
        COLLAPSE_INDEX: false,
        FILE_SUFFIX: '.html',
        HAS_SOURCE:  true,
        SOURCELINK_SUFFIX: '.txt'
      };
    </script>
    <script type="text/javascript" src="_static/jquery.js"></script>
    <script type="text/javascript" src="_static/underscore.js"></script>
    <script type="text/javascript" src="_static/doctools.js"></script>
    <link rel="index" title="Index" href="genindex.html" />
    <link rel="search" title="Search" href="search.html" />
    <link rel="next" title="attrs by Example" href="examples.html" />
    <link rel="prev" title="Overview" href="overview.html" />
   
  <link rel="stylesheet" href="_static/custom.css" type="text/css" />
  
  <meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9" />

  </head>
  <body>
  

    <div class="document">
      <div class="documentwrapper">
        <div class="bodywrapper">
          <div class="body" role="main">
            
  <div class="section" id="why-not">
<span id="why"></span><h1>Why not…<a class="headerlink" href="#why-not" title="Permalink to this headline"></a></h1>
<p>If you’d like third party’s account why <code class="docutils literal"><span class="pre">attrs</span></code> is great, have a look at Glyph’s <a class="reference external" href="https://glyph.twistedmatrix.com/2016/08/attrs.html">The One Python Library Everyone Needs</a>!</p>
<div class="section" id="tuples">
<h2>…tuples?<a class="headerlink" href="#tuples" title="Permalink to this headline"></a></h2>
<div class="section" id="readability">
<h3>Readability<a class="headerlink" href="#readability" title="Permalink to this headline"></a></h3>
<p>What makes more sense while debugging:</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">Point</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">y</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
</pre></div>
</div>
<p>or:</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
</pre></div>
</div>
<p>?</p>
<p>Let’s add even more ambiguity:</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">Customer</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">42</span><span class="p">,</span> <span class="n">reseller</span><span class="o">=</span><span class="mi">23</span><span class="p">,</span> <span class="n">first_name</span><span class="o">=</span><span class="s2">&quot;Jane&quot;</span><span class="p">,</span> <span class="n">last_name</span><span class="o">=</span><span class="s2">&quot;John&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>or:</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="p">(</span><span class="mi">42</span><span class="p">,</span> <span class="mi">23</span><span class="p">,</span> <span class="s2">&quot;Jane&quot;</span><span class="p">,</span> <span class="s2">&quot;John&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>?</p>
<p>Why would you want to write <code class="docutils literal"><span class="pre">customer[2]</span></code> instead of <code class="docutils literal"><span class="pre">customer.first_name</span></code>?</p>
<p>Don’t get me started when you add nesting.
If you’ve never run into mysterious tuples you had no idea what the hell they meant while debugging, you’re much smarter than yours truly.</p>
<p>Using proper classes with names and types makes program code much more readable and <a class="reference external" href="https://arxiv.org/pdf/1304.5257.pdf">comprehensible</a>.
Especially when trying to grok a new piece of software or returning to old code after several months.</p>
</div>
<div class="section" id="extendability">
<h3>Extendability<a class="headerlink" href="#extendability" title="Permalink to this headline"></a></h3>
<p>Imagine you have a function that takes or returns a tuple.
Especially if you use tuple unpacking (eg. <code class="docutils literal"><span class="pre">x,</span> <span class="pre">y</span> <span class="pre">=</span> <span class="pre">get_point()</span></code>), adding additional data means that you have to change the invocation of that function <em>everywhere</em>.</p>
<p>Adding an attribute to a class concerns only those who actually care about that attribute.</p>
</div>
</div>
<div class="section" id="namedtuples">
<h2>…namedtuples?<a class="headerlink" href="#namedtuples" title="Permalink to this headline"></a></h2>
<p><a class="reference external" href="/usr/share/doc/python3-doc/html/library/collections.html#collections.namedtuple" title="(in Python v3.6)"><code class="xref py py-func docutils literal"><span class="pre">collections.namedtuple()</span></code></a>s are tuples with names, not classes. <a class="footnote-reference" href="#history" id="id1">[1]</a>
Since writing classes is tiresome in Python, every now and then someone discovers all the typing they could save and gets really excited.
However that convenience comes at a price.</p>
<p>The most obvious difference between <code class="docutils literal"><span class="pre">namedtuple</span></code>s and <code class="docutils literal"><span class="pre">attrs</span></code>-based classes is that the latter are type-sensitive:</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">attr</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">C1</span> <span class="o">=</span> <span class="n">attr</span><span class="o">.</span><span class="n">make_class</span><span class="p">(</span><span class="s2">&quot;C1&quot;</span><span class="p">,</span> <span class="p">[</span><span class="s2">&quot;a&quot;</span><span class="p">])</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">C2</span> <span class="o">=</span> <span class="n">attr</span><span class="o">.</span><span class="n">make_class</span><span class="p">(</span><span class="s2">&quot;C2&quot;</span><span class="p">,</span> <span class="p">[</span><span class="s2">&quot;a&quot;</span><span class="p">])</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">i1</span> <span class="o">=</span> <span class="n">C1</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">i2</span> <span class="o">=</span> <span class="n">C2</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">i1</span><span class="o">.</span><span class="n">a</span> <span class="o">==</span> <span class="n">i2</span><span class="o">.</span><span class="n">a</span>
<span class="go">True</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">i1</span> <span class="o">==</span> <span class="n">i2</span>
<span class="go">False</span>
</pre></div>
</div>
<p>…while a <code class="docutils literal"><span class="pre">namedtuple</span></code> is <em>intentionally</em> <a class="reference external" href="https://docs.python.org/3/tutorial/datastructures.html#tuples-and-sequences">behaving like a tuple</a> which means the type of a tuple is <em>ignored</em>:</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">collections</span> <span class="k">import</span> <span class="n">namedtuple</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">NT1</span> <span class="o">=</span> <span class="n">namedtuple</span><span class="p">(</span><span class="s2">&quot;NT1&quot;</span><span class="p">,</span> <span class="s2">&quot;a&quot;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">NT2</span> <span class="o">=</span> <span class="n">namedtuple</span><span class="p">(</span><span class="s2">&quot;NT2&quot;</span><span class="p">,</span> <span class="s2">&quot;b&quot;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">t1</span> <span class="o">=</span> <span class="n">NT1</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">t2</span> <span class="o">=</span> <span class="n">NT2</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">t1</span> <span class="o">==</span> <span class="n">t2</span> <span class="o">==</span> <span class="p">(</span><span class="mi">1</span><span class="p">,)</span>
<span class="go">True</span>
</pre></div>
</div>
<p>Other often surprising behaviors include:</p>
<ul>
<li><p class="first">Since they are a subclass of tuples, <code class="docutils literal"><span class="pre">namedtuple</span></code>s have a length and are both iterable and indexable.
That’s not what you’d expect from a class and is likely to shadow subtle typo bugs.</p>
</li>
<li><p class="first">Iterability also implies that it’s easy to accidentally unpack a <code class="docutils literal"><span class="pre">namedtuple</span></code> which leads to hard-to-find bugs. <a class="footnote-reference" href="#iter" id="id2">[3]</a></p>
</li>
<li><p class="first"><code class="docutils literal"><span class="pre">namedtuple</span></code>s have their methods <em>on your instances</em> whether you like it or not. <a class="footnote-reference" href="#pollution" id="id3">[2]</a></p>
</li>
<li><p class="first"><code class="docutils literal"><span class="pre">namedtuple</span></code>s are <em>always</em> immutable.
Not only does that mean that you can’t decide for yourself whether your instances should be immutable or not, it also means that if you want to influence your class’ initialization (validation?  default values?), you have to implement <a class="reference external" href="/usr/share/doc/python3-doc/html/reference/datamodel.html#object.__new__" title="(in Python v3.6)"><code class="xref py py-meth docutils literal"><span class="pre">__new__()</span></code></a> which is a particularly hacky and error-prone requirement for a very common problem. <a class="footnote-reference" href="#immutable" id="id4">[4]</a></p>
</li>
<li><p class="first">To attach methods to a <code class="docutils literal"><span class="pre">namedtuple</span></code> you have to subclass it.
And if you follow the standard library documentation’s recommendation of:</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Point</span><span class="p">(</span><span class="n">namedtuple</span><span class="p">(</span><span class="s1">&#39;Point&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;x&#39;</span><span class="p">,</span> <span class="s1">&#39;y&#39;</span><span class="p">])):</span>
    <span class="c1"># ...</span>
</pre></div>
</div>
<p>you end up with a class that has <em>two</em> <code class="docutils literal"><span class="pre">Point</span></code>s in its <a class="reference external" href="/usr/share/doc/python3-doc/html/library/stdtypes.html#class.__mro__" title="(in Python v3.6)"><code class="xref py py-attr docutils literal"><span class="pre">__mro__</span></code></a>: <code class="docutils literal"><span class="pre">[&lt;class</span> <span class="pre">'point.Point'&gt;,</span> <span class="pre">&lt;class</span> <span class="pre">'point.Point'&gt;,</span> <span class="pre">&lt;type</span> <span class="pre">'tuple'&gt;,</span> <span class="pre">&lt;type</span> <span class="pre">'object'&gt;]</span></code>.</p>
<p>That’s not only confusing, it also has very practical consequences:
for example if you create documentation that includes class hierarchies like <a class="reference external" href="http://www.sphinx-doc.org/en/stable/ext/autodoc.html">Sphinx’s autodoc</a> with <code class="docutils literal"><span class="pre">show-inheritance</span></code>.
Again: common problem, hacky solution with confusing fallout.</p>
</li>
</ul>
<p>All these things make <code class="docutils literal"><span class="pre">namedtuple</span></code>s a particularly poor choice for public APIs because all your objects are irrevocably tainted.
With <code class="docutils literal"><span class="pre">attrs</span></code> your users won’t notice a difference because it creates regular, well-behaved classes.</p>
<div class="admonition-summary admonition">
<p class="first admonition-title">Summary</p>
<p>If you want a <em>tuple with names</em>, by all means: go for a <code class="docutils literal"><span class="pre">namedtuple</span></code>. <a class="footnote-reference" href="#perf" id="id5">[5]</a>
But if you want a class with methods, you’re doing yourself a disservice by relying on a pile of hacks that requires you to employ even more hacks as your requirements expand.</p>
<p class="last">Other than that, <code class="docutils literal"><span class="pre">attrs</span></code> also adds nifty features like validators, converters, and (mutable!) default values.</p>
</div>
<p class="rubric">Footnotes</p>
<table class="docutils footnote" frame="void" id="history" rules="none">
<colgroup><col class="label" /><col /></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#id1">[1]</a></td><td><p class="first">The word is that <code class="docutils literal"><span class="pre">namedtuple</span></code>s were added to the Python standard library as a way to make tuples in return values more readable.
And indeed that is something you see throughout the standard library.</p>
<p class="last">Looking at what the makers of <code class="docutils literal"><span class="pre">namedtuple</span></code>s use it for themselves is a good guideline for deciding on your own use cases.</p>
</td></tr>
</tbody>
</table>
<table class="docutils footnote" frame="void" id="pollution" rules="none">
<colgroup><col class="label" /><col /></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#id3">[2]</a></td><td><code class="docutils literal"><span class="pre">attrs</span></code> only adds a single attribute: <code class="docutils literal"><span class="pre">__attrs_attrs__</span></code> for introspection.
All helpers are functions in the <code class="docutils literal"><span class="pre">attr</span></code> package.
Since they take the instance as first argument, you can easily attach them to your classes under a name of your own choice.</td></tr>
</tbody>
</table>
<table class="docutils footnote" frame="void" id="iter" rules="none">
<colgroup><col class="label" /><col /></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#id2">[3]</a></td><td><a class="reference internal" href="api.html#attr.astuple" title="attr.astuple"><code class="xref py py-func docutils literal"><span class="pre">attr.astuple()</span></code></a> can be used to get that behavior in <code class="docutils literal"><span class="pre">attrs</span></code> on <em>explicit demand</em>.</td></tr>
</tbody>
</table>
<table class="docutils footnote" frame="void" id="immutable" rules="none">
<colgroup><col class="label" /><col /></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#id4">[4]</a></td><td><code class="docutils literal"><span class="pre">attrs</span></code> offers <em>optional</em> immutability through the <code class="docutils literal"><span class="pre">frozen</span></code> keyword.</td></tr>
</tbody>
</table>
<table class="docutils footnote" frame="void" id="perf" rules="none">
<colgroup><col class="label" /><col /></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#id5">[5]</a></td><td>Although <code class="docutils literal"><span class="pre">attrs</span></code> would serve you just as well!
Since both employ the same method of writing and compiling Python code for you, the performance penalty is negligible at worst and in some cases <code class="docutils literal"><span class="pre">attrs</span></code> is even faster if you use <code class="docutils literal"><span class="pre">slots=True</span></code> (which is generally a good idea anyway).</td></tr>
</tbody>
</table>
</div>
<div class="section" id="dicts">
<h2>…dicts?<a class="headerlink" href="#dicts" title="Permalink to this headline"></a></h2>
<p>Dictionaries are not for fixed fields.</p>
<p>If you have a dict, it maps something to something else.
You should be able to add and remove values.</p>
<p><code class="docutils literal"><span class="pre">attrs</span></code> lets you be specific about those expectations; a dictionary does not.
It gives you a named entity (the class) in your code, which lets you explain in other places whether you take a parameter of that class or return a value of that class.</p>
<p>In other words: if your dict has a fixed and known set of keys, it is an object, not a hash.
So if you never iterate over the keys of a dict, you should use a proper class.</p>
</div>
<div class="section" id="hand-written-classes">
<h2>…hand-written classes?<a class="headerlink" href="#hand-written-classes" title="Permalink to this headline"></a></h2>
<p>While we’re fans of all things artisanal, writing the same nine methods all over again doesn’t qualify for me.
I usually manage to get some typos inside and there’s simply more code that can break and thus has to be tested.</p>
<p>To bring it into perspective, the equivalent of</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="nd">@attr</span><span class="o">.</span><span class="n">s</span>
<span class="gp">... </span><span class="k">class</span> <span class="nc">SmartClass</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="gp">... </span>   <span class="n">a</span> <span class="o">=</span> <span class="n">attr</span><span class="o">.</span><span class="n">ib</span><span class="p">()</span>
<span class="gp">... </span>   <span class="n">b</span> <span class="o">=</span> <span class="n">attr</span><span class="o">.</span><span class="n">ib</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">SmartClass</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="go">SmartClass(a=1, b=2)</span>
</pre></div>
</div>
<p>is</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="k">class</span> <span class="nc">ArtisanalClass</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="gp">... </span>    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span>
<span class="gp">... </span>        <span class="bp">self</span><span class="o">.</span><span class="n">a</span> <span class="o">=</span> <span class="n">a</span>
<span class="gp">... </span>        <span class="bp">self</span><span class="o">.</span><span class="n">b</span> <span class="o">=</span> <span class="n">b</span>
<span class="gp">...</span>
<span class="gp">... </span>    <span class="k">def</span> <span class="nf">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="gp">... </span>        <span class="k">return</span> <span class="s2">&quot;ArtisanalClass(a=</span><span class="si">{}</span><span class="s2">, b=</span><span class="si">{}</span><span class="s2">)&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">a</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">b</span><span class="p">)</span>
<span class="gp">...</span>
<span class="gp">... </span>    <span class="k">def</span> <span class="nf">__eq__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="gp">... </span>        <span class="k">if</span> <span class="n">other</span><span class="o">.</span><span class="vm">__class__</span> <span class="ow">is</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="p">:</span>
<span class="gp">... </span>            <span class="k">return</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">a</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">b</span><span class="p">)</span> <span class="o">==</span> <span class="p">(</span><span class="n">other</span><span class="o">.</span><span class="n">a</span><span class="p">,</span> <span class="n">other</span><span class="o">.</span><span class="n">b</span><span class="p">)</span>
<span class="gp">... </span>        <span class="k">else</span><span class="p">:</span>
<span class="gp">... </span>            <span class="k">return</span> <span class="bp">NotImplemented</span>
<span class="gp">...</span>
<span class="gp">... </span>    <span class="k">def</span> <span class="nf">__ne__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="gp">... </span>        <span class="n">result</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="fm">__eq__</span><span class="p">(</span><span class="n">other</span><span class="p">)</span>
<span class="gp">... </span>        <span class="k">if</span> <span class="n">result</span> <span class="ow">is</span> <span class="bp">NotImplemented</span><span class="p">:</span>
<span class="gp">... </span>            <span class="k">return</span> <span class="bp">NotImplemented</span>
<span class="gp">... </span>        <span class="k">else</span><span class="p">:</span>
<span class="gp">... </span>            <span class="k">return</span> <span class="ow">not</span> <span class="n">result</span>
<span class="gp">...</span>
<span class="gp">... </span>    <span class="k">def</span> <span class="nf">__lt__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="gp">... </span>        <span class="k">if</span> <span class="n">other</span><span class="o">.</span><span class="vm">__class__</span> <span class="ow">is</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="p">:</span>
<span class="gp">... </span>            <span class="k">return</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">a</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">b</span><span class="p">)</span> <span class="o">&lt;</span> <span class="p">(</span><span class="n">other</span><span class="o">.</span><span class="n">a</span><span class="p">,</span> <span class="n">other</span><span class="o">.</span><span class="n">b</span><span class="p">)</span>
<span class="gp">... </span>        <span class="k">else</span><span class="p">:</span>
<span class="gp">... </span>            <span class="k">return</span> <span class="bp">NotImplemented</span>
<span class="gp">...</span>
<span class="gp">... </span>    <span class="k">def</span> <span class="nf">__le__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="gp">... </span>        <span class="k">if</span> <span class="n">other</span><span class="o">.</span><span class="vm">__class__</span> <span class="ow">is</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="p">:</span>
<span class="gp">... </span>            <span class="k">return</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">a</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">b</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="p">(</span><span class="n">other</span><span class="o">.</span><span class="n">a</span><span class="p">,</span> <span class="n">other</span><span class="o">.</span><span class="n">b</span><span class="p">)</span>
<span class="gp">... </span>        <span class="k">else</span><span class="p">:</span>
<span class="gp">... </span>            <span class="k">return</span> <span class="bp">NotImplemented</span>
<span class="gp">...</span>
<span class="gp">... </span>    <span class="k">def</span> <span class="nf">__gt__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="gp">... </span>        <span class="k">if</span> <span class="n">other</span><span class="o">.</span><span class="vm">__class__</span> <span class="ow">is</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="p">:</span>
<span class="gp">... </span>            <span class="k">return</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">a</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">b</span><span class="p">)</span> <span class="o">&gt;</span> <span class="p">(</span><span class="n">other</span><span class="o">.</span><span class="n">a</span><span class="p">,</span> <span class="n">other</span><span class="o">.</span><span class="n">b</span><span class="p">)</span>
<span class="gp">... </span>        <span class="k">else</span><span class="p">:</span>
<span class="gp">... </span>            <span class="k">return</span> <span class="bp">NotImplemented</span>
<span class="gp">...</span>
<span class="gp">... </span>    <span class="k">def</span> <span class="nf">__ge__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="gp">... </span>        <span class="k">if</span> <span class="n">other</span><span class="o">.</span><span class="vm">__class__</span> <span class="ow">is</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="p">:</span>
<span class="gp">... </span>            <span class="k">return</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">a</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">b</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="p">(</span><span class="n">other</span><span class="o">.</span><span class="n">a</span><span class="p">,</span> <span class="n">other</span><span class="o">.</span><span class="n">b</span><span class="p">)</span>
<span class="gp">... </span>        <span class="k">else</span><span class="p">:</span>
<span class="gp">... </span>            <span class="k">return</span> <span class="bp">NotImplemented</span>
<span class="gp">...</span>
<span class="gp">... </span>    <span class="k">def</span> <span class="nf">__hash__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="gp">... </span>        <span class="k">return</span> <span class="nb">hash</span><span class="p">((</span><span class="bp">self</span><span class="o">.</span><span class="n">a</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">b</span><span class="p">))</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">ArtisanalClass</span><span class="p">(</span><span class="n">a</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">b</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
<span class="go">ArtisanalClass(a=1, b=2)</span>
</pre></div>
</div>
<p>which is quite a mouthful and it doesn’t even use any of <code class="docutils literal"><span class="pre">attrs</span></code>’s more advanced features like validators or defaults values.
Also: no tests whatsoever.
And who will guarantee you, that you don’t accidentally flip the <code class="docutils literal"><span class="pre">&lt;</span></code> in your tenth implementation of <code class="docutils literal"><span class="pre">__gt__</span></code>?</p>
<p>It also should be noted that <code class="docutils literal"><span class="pre">attrs</span></code> is not an all-or-nothing solution.
You can freely choose which features you want and disable those that you want more control over:</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="nd">@attr</span><span class="o">.</span><span class="n">s</span><span class="p">(</span><span class="nb">repr</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="gp">... </span><span class="k">class</span> <span class="nc">SmartClass</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="gp">... </span>   <span class="n">a</span> <span class="o">=</span> <span class="n">attr</span><span class="o">.</span><span class="n">ib</span><span class="p">()</span>
<span class="gp">... </span>   <span class="n">b</span> <span class="o">=</span> <span class="n">attr</span><span class="o">.</span><span class="n">ib</span><span class="p">()</span>
<span class="gp">...</span>
<span class="gp">... </span>   <span class="k">def</span> <span class="nf">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="gp">... </span>       <span class="k">return</span> <span class="s2">&quot;&lt;SmartClass(a=</span><span class="si">%d</span><span class="s2">)&gt;&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">a</span><span class="p">,)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">SmartClass</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="go">&lt;SmartClass(a=1)&gt;</span>
</pre></div>
</div>
<div class="admonition-summary admonition">
<p class="first admonition-title">Summary</p>
<p>If you don’t care and like typing, we’re not gonna stop you.</p>
<p>However it takes a lot of bias and determined rationalization to claim that <code class="docutils literal"><span class="pre">attrs</span></code> raises the mental burden on a project given how difficult it is to find the important bits in a hand-written class and how annoying it is to ensure you’ve copy-pasted your code correctly over all your classes.</p>
<p class="last">In any case, if you ever get sick of the repetitiveness and drowning important code in a sea of boilerplate, <code class="docutils literal"><span class="pre">attrs</span></code> will be waiting for you.</p>
</div>
</div>
</div>


          </div>
        </div>
      </div>
      <div class="sphinxsidebar" role="navigation" aria-label="main navigation">
        <div class="sphinxsidebarwrapper">
            <p class="logo"><a href="index.html">
              <img class="logo" src="_static/attrs_logo.svg" alt="Logo"/>
            </a></p>
  <h3><a href="index.html">Table Of Contents</a></h3>
  <ul>
<li><a class="reference internal" href="#">Why not…</a><ul>
<li><a class="reference internal" href="#tuples">…tuples?</a><ul>
<li><a class="reference internal" href="#readability">Readability</a></li>
<li><a class="reference internal" href="#extendability">Extendability</a></li>
</ul>
</li>
<li><a class="reference internal" href="#namedtuples">…namedtuples?</a></li>
<li><a class="reference internal" href="#dicts">…dicts?</a></li>
<li><a class="reference internal" href="#hand-written-classes">…hand-written classes?</a></li>
</ul>
</li>
</ul>
<div class="relations">
<h3>Related Topics</h3>
<ul>
  <li><a href="index.html">Documentation overview</a><ul>
      <li>Previous: <a href="overview.html" title="previous chapter">Overview</a></li>
      <li>Next: <a href="examples.html" title="next chapter"><code class="docutils literal"><span class="pre">attrs</span></code> by Example</a></li>
  </ul></li>
</ul>
</div>
<div id="searchbox" style="display: none" role="search">
  <h3>Quick search</h3>
    <form class="search" action="search.html" method="get">
      <div><input type="text" name="q" /></div>
      <div><input type="submit" value="Go" /></div>
      <input type="hidden" name="check_keywords" value="yes" />
      <input type="hidden" name="area" value="default" />
    </form>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
        </div>
      </div>
      <div class="clearer"></div>
    </div>
    <div class="footer">
      &copy;2018, Hynek Schlawack.
      
      |
      Powered by <a href="http://sphinx-doc.org/">Sphinx 1.6.7</a>
      &amp; <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.8</a>
      
    </div>

    

    
  </body>
</html>