Skip to content

Commit ca62436

Browse files
committed
Duck types
1 parent 088ea6d commit ca62436

File tree

2 files changed

+106
-26
lines changed

2 files changed

+106
-26
lines changed

README.md

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,31 +1083,71 @@ class MySortable:
10831083
return NotImplemented
10841084
```
10851085

1086+
### Iterable
1087+
* **Only required method for iterable is iter(), that should return an iterator of its contents.**
1088+
```python
1089+
class MyIterable:
1090+
def __init__(self, a):
1091+
self.a = a
1092+
def __iter__(self):
1093+
for el in self.a:
1094+
yield el
1095+
```
1096+
10861097
### Collection
1087-
* **Methods do not depend on each other, so they can be skipped if not needed.**
1088-
* **Any object with defined getitem() is considered iterable, even if it lacks iter().**
1098+
* **Every collection is also an iterable.**
1099+
* **This cheatsheet actually means `'<iterable>'` when it uses `'<collection>'`.**
1100+
* **I chose not to use the name iterable because it sounds scarier and more vague than collection.**
10891101
```python
10901102
class MyCollection:
10911103
def __init__(self, a):
10921104
self.a = a
1105+
def __iter__(self):
1106+
for el in self.a:
1107+
yield el
10931108
def __len__(self):
10941109
return len(self.a)
1095-
def __getitem__(self, i):
1096-
return self.a[i]
1097-
def __setitem__(self, i, el):
1098-
self.a[i] = el
10991110
def __contains__(self, el):
11001111
return el in self.a
1101-
def __iter__(self):
1102-
for el in self.a:
1103-
yield el
11041112
```
11051113

1114+
### Sequence
1115+
* **Every sequence is also an iterable.**
1116+
* **That is because iter() is automatically generated if getitem() is defined.**
11061117
```python
1107-
>>> from collections.abc import Sequence, Collection, Iterable
1108-
>>> a = MyCollection([1, 2, 3])
1109-
>>> isinstance(a, Sequence), isinstance(a, Collection), isinstance(a, Iterable)
1110-
(False, True, True)
1118+
class MySequence:
1119+
def __init__(self, a):
1120+
self.a = a
1121+
def __len__(self):
1122+
return len(self.a)
1123+
def __getitem__(self, i):
1124+
return self.a[i]
1125+
```
1126+
1127+
### Collections.abc.Sequence
1128+
* **A much richer interface than the basic sequence.**
1129+
* **Extending it generates contains(), iter(), reversed(), index(), and count().**
1130+
* **It is not a duck type, so `'issubclass(MySequence, collections.abc.Sequence)'` would return 'False' even if it had all the methods defined.**
1131+
```python
1132+
class MyAbcSequence(collections.abc.Sequence):
1133+
def __init__(self, a):
1134+
self.a = a
1135+
def __len__(self):
1136+
return len(self.a)
1137+
def __getitem__(self, i):
1138+
return self.a[i]
1139+
```
1140+
1141+
#### Table of provided methods:
1142+
```text
1143+
+------------+----------+------------+----------+--------------+
1144+
| | iterable | collection | sequence | abc.Sequence |
1145+
+------------+----------+------------+----------+--------------+
1146+
| iter() | yes | yes | yes | yes |
1147+
| len() | | yes | yes | yes |
1148+
| getitem() | | | yes | yes |
1149+
| contains() | | yes | | yes |
1150+
+------------+----------+------------+----------+--------------+
11111151
```
11121152

11131153
### Iterator

index.html

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,30 +1015,70 @@ <h3 id="sortable">Sortable</h3>
10151015
<span class="hljs-keyword">return</span> self.a &lt; other.a
10161016
<span class="hljs-keyword">return</span> <span class="hljs-built_in">NotImplemented</span>
10171017
</code></pre>
1018+
<h3 id="iterable">Iterable</h3>
1019+
<ul>
1020+
<li><strong>Only required method for iterable is iter(), that should return an iterator of its contents.</strong></li>
1021+
</ul>
1022+
<pre><code class="python language-python hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyIterable</span>:</span>
1023+
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span><span class="hljs-params">(self, a)</span>:</span>
1024+
self.a = a
1025+
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__iter__</span><span class="hljs-params">(self)</span>:</span>
1026+
<span class="hljs-keyword">for</span> el <span class="hljs-keyword">in</span> self.a:
1027+
<span class="hljs-keyword">yield</span> el
1028+
</code></pre>
10181029
<h3 id="collection">Collection</h3>
10191030
<ul>
1020-
<li><strong>Methods do not depend on each other, so they can be skipped if not needed.</strong></li>
1021-
<li><strong>Any object with defined getitem() is considered iterable, even if it lacks iter().</strong></li>
1031+
<li><strong>Every collection is also an iterable.</strong></li>
1032+
<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>
1033+
<li><strong>I chose not to use the name iterable because it sounds scarier and more vague than collection.</strong></li>
10221034
</ul>
10231035
<pre><code class="python language-python hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyCollection</span>:</span>
10241036
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span><span class="hljs-params">(self, a)</span>:</span>
10251037
self.a = a
1038+
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__iter__</span><span class="hljs-params">(self)</span>:</span>
1039+
<span class="hljs-keyword">for</span> el <span class="hljs-keyword">in</span> self.a:
1040+
<span class="hljs-keyword">yield</span> el
10261041
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__len__</span><span class="hljs-params">(self)</span>:</span>
10271042
<span class="hljs-keyword">return</span> len(self.a)
1028-
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__getitem__</span><span class="hljs-params">(self, i)</span>:</span>
1029-
<span class="hljs-keyword">return</span> self.a[i]
1030-
<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>
1031-
self.a[i] = el
10321043
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__contains__</span><span class="hljs-params">(self, el)</span>:</span>
10331044
<span class="hljs-keyword">return</span> el <span class="hljs-keyword">in</span> self.a
1034-
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__iter__</span><span class="hljs-params">(self)</span>:</span>
1035-
<span class="hljs-keyword">for</span> el <span class="hljs-keyword">in</span> self.a:
1036-
<span class="hljs-keyword">yield</span> el
10371045
</code></pre>
1038-
<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
1039-
<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>])
1040-
<span class="hljs-meta">&gt;&gt;&gt; </span>isinstance(a, Sequence), isinstance(a, Collection), isinstance(a, Iterable)
1041-
(<span class="hljs-keyword">False</span>, <span class="hljs-keyword">True</span>, <span class="hljs-keyword">True</span>)
1046+
<h3 id="sequence">Sequence</h3>
1047+
<ul>
1048+
<li><strong>Every sequence is also an iterable.</strong></li>
1049+
<li><strong>That is because iter() is automatically generated if getitem() is defined.</strong></li>
1050+
</ul>
1051+
<pre><code class="python language-python hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MySequence</span>:</span>
1052+
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span><span class="hljs-params">(self, a)</span>:</span>
1053+
self.a = a
1054+
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__len__</span><span class="hljs-params">(self)</span>:</span>
1055+
<span class="hljs-keyword">return</span> len(self.a)
1056+
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__getitem__</span><span class="hljs-params">(self, i)</span>:</span>
1057+
<span class="hljs-keyword">return</span> self.a[i]
1058+
</code></pre>
1059+
<h3 id="collectionsabcsequence">Collections.abc.Sequence</h3>
1060+
<ul>
1061+
<li><strong>A much richer interface than the basic sequence.</strong></li>
1062+
<li><strong>Extending it generates contains(), iter(), reversed(), index(), and count().</strong></li>
1063+
<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>
1064+
</ul>
1065+
<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>
1066+
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span><span class="hljs-params">(self, a)</span>:</span>
1067+
self.a = a
1068+
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__len__</span><span class="hljs-params">(self)</span>:</span>
1069+
<span class="hljs-keyword">return</span> len(self.a)
1070+
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__getitem__</span><span class="hljs-params">(self, i)</span>:</span>
1071+
<span class="hljs-keyword">return</span> self.a[i]
1072+
</code></pre>
1073+
<h4 id="tableofprovidedmethods">Table of provided methods:</h4>
1074+
<pre><code class="text language-text">+------------+----------+------------+----------+--------------+
1075+
| | iterable | collection | sequence | abc.Sequence |
1076+
+------------+----------+------------+----------+--------------+
1077+
| iter() | yes | yes | yes | yes |
1078+
| len() | | yes | yes | yes |
1079+
| getitem() | | | yes | yes |
1080+
| contains() | | yes | | yes |
1081+
+------------+----------+------------+----------+--------------+
10421082
</code></pre>
10431083
<h3 id="iterator-1">Iterator</h3>
10441084
<pre><code class="python language-python hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Counter</span>:</span>

0 commit comments

Comments
 (0)