Browse Source

Duck types

pull/36/head
Jure Šorn 5 years ago
parent
commit
ca624367e0
2 changed files with 106 additions and 26 deletions
  1. 66
      README.md
  2. 66
      index.html

66
README.md

@ -1083,31 +1083,71 @@ class MySortable:
return NotImplemented
```
### Iterable
* **Only required method for iterable is iter(), that should return an iterator of its contents.**
```python
class MyIterable:
def __init__(self, a):
self.a = a
def __iter__(self):
for el in self.a:
yield el
```
### Collection
* **Methods do not depend on each other, so they can be skipped if not needed.**
* **Any object with defined getitem() is considered iterable, even if it lacks iter().**
* **Every collection is also an iterable.**
* **This cheatsheet actually means `'<iterable>'` when it uses `'<collection>'`.**
* **I chose not to use the name iterable because it sounds scarier and more vague than collection.**
```python
class MyCollection:
def __init__(self, a):
self.a = a
def __iter__(self):
for el in self.a:
yield el
def __len__(self):
return len(self.a)
def __getitem__(self, i):
return self.a[i]
def __setitem__(self, i, el):
self.a[i] = el
def __contains__(self, el):
return el in self.a
def __iter__(self):
for el in self.a:
yield el
```
### Sequence
* **Every sequence is also an iterable.**
* **That is because iter() is automatically generated if getitem() is defined.**
```python
>>> from collections.abc import Sequence, Collection, Iterable
>>> a = MyCollection([1, 2, 3])
>>> isinstance(a, Sequence), isinstance(a, Collection), isinstance(a, Iterable)
(False, True, True)
class MySequence:
def __init__(self, a):
self.a = a
def __len__(self):
return len(self.a)
def __getitem__(self, i):
return self.a[i]
```
### Collections.abc.Sequence
* **A much richer interface than the basic sequence.**
* **Extending it generates contains(), iter(), reversed(), index(), and count().**
* **It is not a duck type, so `'issubclass(MySequence, collections.abc.Sequence)'` would return 'False' even if it had all the methods defined.**
```python
class MyAbcSequence(collections.abc.Sequence):
def __init__(self, a):
self.a = a
def __len__(self):
return len(self.a)
def __getitem__(self, i):
return self.a[i]
```
#### Table of provided methods:
```text
+------------+----------+------------+----------+--------------+
| | iterable | collection | sequence | abc.Sequence |
+------------+----------+------------+----------+--------------+
| iter() | yes | yes | yes | yes |
| len() | | yes | yes | yes |
| getitem() | | | yes | yes |
| contains() | | yes | | yes |
+------------+----------+------------+----------+--------------+
```
### Iterator

66
index.html

@ -1015,30 +1015,70 @@ Z = dataclasses.make_dataclass(<span class="hljs-string">'Z'</span>, [<span clas
<span class="hljs-keyword">return</span> self.a &lt; other.a
<span class="hljs-keyword">return</span> <span class="hljs-built_in">NotImplemented</span>
</code></pre>
<h3 id="iterable">Iterable</h3>
<ul>
<li><strong>Only required method for iterable is iter(), that should return an iterator of its contents.</strong></li>
</ul>
<pre><code class="python language-python hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyIterable</span>:</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span><span class="hljs-params">(self, a)</span>:</span>
self.a = a
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__iter__</span><span class="hljs-params">(self)</span>:</span>
<span class="hljs-keyword">for</span> el <span class="hljs-keyword">in</span> self.a:
<span class="hljs-keyword">yield</span> el
</code></pre>
<h3 id="collection">Collection</h3>
<ul>
<li><strong>Methods do not depend on each other, so they can be skipped if not needed.</strong></li>
<li><strong>Any object with defined getitem() is considered iterable, even if it lacks iter().</strong></li>
<li><strong>Every collection is also an iterable.</strong></li>
<li><strong>This cheatsheet actually means <code class="python hljs"><span class="hljs-string">'&lt;iterable&gt;'</span></code> when it uses <code class="python hljs"><span class="hljs-string">'&lt;collection&gt;'</span></code>.</strong></li>
<li><strong>I chose not to use the name iterable because it sounds scarier and more vague than collection.</strong></li>
</ul>
<pre><code class="python language-python hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyCollection</span>:</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span><span class="hljs-params">(self, a)</span>:</span>
self.a = a
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__iter__</span><span class="hljs-params">(self)</span>:</span>
<span class="hljs-keyword">for</span> el <span class="hljs-keyword">in</span> self.a:
<span class="hljs-keyword">yield</span> el
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__len__</span><span class="hljs-params">(self)</span>:</span>
<span class="hljs-keyword">return</span> len(self.a)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__getitem__</span><span class="hljs-params">(self, i)</span>:</span>
<span class="hljs-keyword">return</span> self.a[i]
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__setitem__</span><span class="hljs-params">(self, i, el)</span>:</span>
self.a[i] = el
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__contains__</span><span class="hljs-params">(self, el)</span>:</span>
<span class="hljs-keyword">return</span> el <span class="hljs-keyword">in</span> self.a
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__iter__</span><span class="hljs-params">(self)</span>:</span>
<span class="hljs-keyword">for</span> el <span class="hljs-keyword">in</span> self.a:
<span class="hljs-keyword">yield</span> el
</code></pre>
<pre><code class="python language-python hljs"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">from</span> collections.abc <span class="hljs-keyword">import</span> Sequence, Collection, Iterable
<span class="hljs-meta">&gt;&gt;&gt; </span>a = MyCollection([<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>])
<span class="hljs-meta">&gt;&gt;&gt; </span>isinstance(a, Sequence), isinstance(a, Collection), isinstance(a, Iterable)
(<span class="hljs-keyword">False</span>, <span class="hljs-keyword">True</span>, <span class="hljs-keyword">True</span>)
<h3 id="sequence">Sequence</h3>
<ul>
<li><strong>Every sequence is also an iterable.</strong></li>
<li><strong>That is because iter() is automatically generated if getitem() is defined.</strong></li>
</ul>
<pre><code class="python language-python hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MySequence</span>:</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span><span class="hljs-params">(self, a)</span>:</span>
self.a = a
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__len__</span><span class="hljs-params">(self)</span>:</span>
<span class="hljs-keyword">return</span> len(self.a)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__getitem__</span><span class="hljs-params">(self, i)</span>:</span>
<span class="hljs-keyword">return</span> self.a[i]
</code></pre>
<h3 id="collectionsabcsequence">Collections.abc.Sequence</h3>
<ul>
<li><strong>A much richer interface than the basic sequence.</strong></li>
<li><strong>Extending it generates contains(), iter(), reversed(), index(), and count().</strong></li>
<li><strong>It is not a duck type, so <code class="python hljs"><span class="hljs-string">'issubclass(MySequence, collections.abc.Sequence)'</span></code> would return 'False' even if it had all the methods defined.</strong></li>
</ul>
<pre><code class="python language-python hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyAbcSequence</span><span class="hljs-params">(collections.abc.Sequence)</span>:</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span><span class="hljs-params">(self, a)</span>:</span>
self.a = a
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__len__</span><span class="hljs-params">(self)</span>:</span>
<span class="hljs-keyword">return</span> len(self.a)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__getitem__</span><span class="hljs-params">(self, i)</span>:</span>
<span class="hljs-keyword">return</span> self.a[i]
</code></pre>
<h4 id="tableofprovidedmethods">Table of provided methods:</h4>
<pre><code class="text language-text">+------------+----------+------------+----------+--------------+
| | iterable | collection | sequence | abc.Sequence |
+------------+----------+------------+----------+--------------+
| iter() | yes | yes | yes | yes |
| len() | | yes | yes | yes |
| getitem() | | | yes | yes |
| contains() | | yes | | yes |
+------------+----------+------------+----------+--------------+
</code></pre>
<h3 id="iterator-1">Iterator</h3>
<pre><code class="python language-python hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Counter</span>:</span>

Loading…
Cancel
Save