diff --git a/README.md b/README.md index 8230b3b..aa2a877 100644 --- a/README.md +++ b/README.md @@ -1082,7 +1082,7 @@ class MyHashable: ``` ### Sortable -* **With 'total_ordering' decorator you only need to provide one of lt(), gt(), le() or ge() special methods.** +* **With 'total_ordering' decorator you only need to provide eq() and one of lt(), gt(), le() or ge() special methods.** ```python from functools import total_ordering @@ -1100,73 +1100,6 @@ 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 -* **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 __contains__(self, el): - return el in self.a -``` - -### Sequence -* **Every sequence is also an iterable.** -* **That is because iter() is automatically generated if getitem() is defined.** -```python -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 the methods that each (duck) type provides: -```text -+------------+----------+------------+----------+--------------+ -| | Iterable | Collection | Sequence | abc.Sequence | -+------------+----------+------------+----------+--------------+ -| iter() | yes | yes | yes | yes | -| len() | | yes | yes | yes | -| getitem() | | | yes | yes | -| contains() | | yes | | yes | -+------------+----------+------------+----------+--------------+ -``` - ### Iterator ```python class Counter: @@ -1235,6 +1168,86 @@ con = sqlite3.connect('<path>'); with con: con.execute('<insert_query>') ``` +Iterable Duck Types +------------------- + +### Iterable +* **Only required method for iterable is iter(), that should return an iterator of its contents.** +* **Contains() is automatically generated whenever iter() is present.** +```python +class MyIterable: + def __init__(self, a): + self.a = a + def __iter__(self): + for el in self.a: + yield el +``` + +```python +>>> a = MyIterable([1, 2, 3]) +>>> iter(a) +<generator object MyIterable.__iter__ at 0x1026c18b8> +>>> 1 in a +True +``` + +### Collection +* **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 __contains__(self, el): + return el in self.a + def __len__(self): + return len(self.a) + def __iter__(self): + for el in self.a: + yield el +``` + +### Sequence +* **Every sequence is also a collection.** +* **Iter() and reversed() are automatically generated whenever getitem() is present.** +```python +class MySequence: + def __init__(self, a): + self.a = a + def __getitem__(self, i): + return self.a[i] + def __len__(self): + return len(self.a) +``` + +### Collections.abc.Sequence +* **It's a richer interface than the basic sequence.** +* **Extending it generates contains(), iter(), reversed(), index(), and count().** +* **Unlike `'abc.Iterable'` and `'abc.Collection'`, it is not a duck type. That's why `'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 __getitem__(self, i): + return self.a[i] + def __len__(self): + return len(self.a) +``` + +#### Table of the methods that each (duck) type provides: +```text ++------------+----------+------------+----------+--------------+ +| | Iterable | Collection | Sequence | abc.Sequence | ++------------+----------+------------+----------+--------------+ +| iter() | yes | yes | yes | yes | +| len() | | yes | yes | yes | +| getitem() | | | yes | yes | +| contains() | | yes | | yes | ++------------+----------+------------+----------+--------------+ +``` + + Enum ---- ```python diff --git a/index.html b/index.html index 36fd517..ed776a2 100644 --- a/index.html +++ b/index.html @@ -1016,7 +1016,7 @@ Z = dataclasses.make_dataclass(<span class="hljs-string">'Z'</span>, [<span clas </code></pre> <h3 id="sortable">Sortable</h3> <ul> -<li><strong>With 'total_ordering' decorator you only need to provide one of lt(), gt(), le() or ge() special methods.</strong></li> +<li><strong>With 'total_ordering' decorator you only need to provide eq() and one of lt(), gt(), le() or ge() special methods.</strong></li> </ul> <pre><code class="python language-python hljs"><span class="hljs-keyword">from</span> functools <span class="hljs-keyword">import</span> total_ordering @@ -1033,9 +1033,62 @@ Z = dataclasses.make_dataclass(<span class="hljs-string">'Z'</span>, [<span clas <span class="hljs-keyword">return</span> self.a < other.a <span class="hljs-keyword">return</span> <span class="hljs-built_in">NotImplemented</span> </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> + <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span><span class="hljs-params">(self)</span>:</span> + self.i = <span class="hljs-number">0</span> + <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__next__</span><span class="hljs-params">(self)</span>:</span> + self.i += <span class="hljs-number">1</span> + <span class="hljs-keyword">return</span> self.i + <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">return</span> self +</code></pre> +<pre><code class="python language-python hljs"><span class="hljs-meta">>>> </span>counter = Counter() +<span class="hljs-meta">>>> </span>next(counter), next(counter), next(counter) +(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>) +</code></pre> +<h3 id="callable">Callable</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> + <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span><span class="hljs-params">(self)</span>:</span> + self.i = <span class="hljs-number">0</span> + <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__call__</span><span class="hljs-params">(self)</span>:</span> + self.i += <span class="hljs-number">1</span> + <span class="hljs-keyword">return</span> self.i +</code></pre> +<pre><code class="python language-python hljs"><span class="hljs-meta">>>> </span>counter = Counter() +<span class="hljs-meta">>>> </span>counter(), counter(), counter() +(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>) +</code></pre> +<h3 id="contextmanager">Context Manager</h3> +<pre><code class="python language-python hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyOpen</span><span class="hljs-params">()</span>:</span> + <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span><span class="hljs-params">(self, filename)</span>:</span> + self.filename = filename + <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__enter__</span><span class="hljs-params">(self)</span>:</span> + self.file = open(self.filename) + <span class="hljs-keyword">return</span> self.file + <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__exit__</span><span class="hljs-params">(self, *args)</span>:</span> + self.file.close() +</code></pre> +<pre><code class="python language-python hljs"><span class="hljs-meta">>>> </span><span class="hljs-keyword">with</span> open(<span class="hljs-string">'test.txt'</span>, <span class="hljs-string">'w'</span>) <span class="hljs-keyword">as</span> file: +<span class="hljs-meta">... </span> file.write(<span class="hljs-string">'Hello World!'</span>) +<span class="hljs-meta">>>> </span><span class="hljs-keyword">with</span> MyOpen(<span class="hljs-string">'test.txt'</span>) <span class="hljs-keyword">as</span> file: +<span class="hljs-meta">... </span> print(file.read()) +Hello World! +</code></pre> +<h4 id="contextmanagers">Context managers:</h4> +<pre><code class="python language-python hljs"><span class="hljs-keyword">with</span> open(<span class="hljs-string">'<path>'</span>, ...) <span class="hljs-keyword">as</span> file: ... +<span class="hljs-keyword">with</span> wave.open(<span class="hljs-string">'<path>'</span>, ...) <span class="hljs-keyword">as</span> wave_file: ... +<span class="hljs-keyword">with</span> memoryview(<bytes/bytearray/array>) <span class="hljs-keyword">as</span> view: ... +</code></pre> +<h4 id="reusablecontextmanagers">Reusable context managers:</h4> +<pre><code class="python language-python hljs">lock = threading.RLock(); <span class="hljs-keyword">with</span> lock: ... +con = sqlite3.connect(<span class="hljs-string">'<path>'</span>); <span class="hljs-keyword">with</span> con: con.execute(<span class="hljs-string">'<insert_query>'</span>) +</code></pre> +<h2 id="iterableducktypes"><a href="#iterableducktypes" name="iterableducktypes">#</a>Iterable Duck Types</h2> <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> +<li><strong>Contains() is automatically generated whenever iter() is present.</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> @@ -1044,6 +1097,12 @@ Z = dataclasses.make_dataclass(<span class="hljs-string">'Z'</span>, [<span clas <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">>>> </span>a = MyIterable([<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]) +<span class="hljs-meta">>>> </span>iter(a) +<generator object MyIterable.__iter__ at <span class="hljs-number">0x1026c18b8</span>> +<span class="hljs-meta">>>> </span><span class="hljs-number">1</span> <span class="hljs-keyword">in</span> a +<span class="hljs-keyword">True</span> +</code></pre> <h3 id="collection">Collection</h3> <ul> <li><strong>Every collection is also an iterable.</strong></li> @@ -1053,40 +1112,40 @@ Z = dataclasses.make_dataclass(<span class="hljs-string">'Z'</span>, [<span clas <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">__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">__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">__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">__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 </code></pre> <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> +<li><strong>Every sequence is also a collection.</strong></li> +<li><strong>Iter() and reversed() are automatically generated whenever getitem() is present.</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] + <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) </code></pre> <h3 id="collectionsabcsequence">Collections.abc.Sequence</h3> <ul> -<li><strong>A much richer interface than the basic sequence.</strong></li> +<li><strong>It's a 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> +<li><strong>Unlike <code class="python hljs"><span class="hljs-string">'abc.Iterable'</span></code> and <code class="python hljs"><span class="hljs-string">'abc.Collection'</span></code>, it is not a duck type. That's why <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] + <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) </code></pre> <h4 id="tableofthemethodsthateachducktypeprovides">Table of the methods that each (duck) type provides:</h4> <pre><code class="text language-text">┏━━━━━━━━━━━━┯━━━━━━━━━━┯━━━━━━━━━━━━┯━━━━━━━━━━┯━━━━━━━━━━━━━━┓ @@ -1094,61 +1153,10 @@ Z = dataclasses.make_dataclass(<span class="hljs-string">'Z'</span>, [<span clas ┠────────────┼──────────┼────────────┼──────────┼──────────────┨ ┃ iter() │ ✓ │ ✓ │ ✓ │ ✓ ┃ ┃ len() │ │ ✓ │ ✓ │ ✓ ┃ -┃ getitem() │ │ │ ✓ │ ✓ ┃ +┃ getitem() │ │ + │ ✓ │ ✓ ┃ ┃ contains() │ │ ✓ │ │ ✓ ┃ ┗━━━━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━━━━━━━┛ </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> - <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span><span class="hljs-params">(self)</span>:</span> - self.i = <span class="hljs-number">0</span> - <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__next__</span><span class="hljs-params">(self)</span>:</span> - self.i += <span class="hljs-number">1</span> - <span class="hljs-keyword">return</span> self.i - <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">return</span> self -</code></pre> -<pre><code class="python language-python hljs"><span class="hljs-meta">>>> </span>counter = Counter() -<span class="hljs-meta">>>> </span>next(counter), next(counter), next(counter) -(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>) -</code></pre> -<h3 id="callable">Callable</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> - <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span><span class="hljs-params">(self)</span>:</span> - self.i = <span class="hljs-number">0</span> - <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__call__</span><span class="hljs-params">(self)</span>:</span> - self.i += <span class="hljs-number">1</span> - <span class="hljs-keyword">return</span> self.i -</code></pre> -<pre><code class="python language-python hljs"><span class="hljs-meta">>>> </span>counter = Counter() -<span class="hljs-meta">>>> </span>counter(), counter(), counter() -(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>) -</code></pre> -<h3 id="contextmanager">Context Manager</h3> -<pre><code class="python language-python hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyOpen</span><span class="hljs-params">()</span>:</span> - <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span><span class="hljs-params">(self, filename)</span>:</span> - self.filename = filename - <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__enter__</span><span class="hljs-params">(self)</span>:</span> - self.file = open(self.filename) - <span class="hljs-keyword">return</span> self.file - <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__exit__</span><span class="hljs-params">(self, *args)</span>:</span> - self.file.close() -</code></pre> -<pre><code class="python language-python hljs"><span class="hljs-meta">>>> </span><span class="hljs-keyword">with</span> open(<span class="hljs-string">'test.txt'</span>, <span class="hljs-string">'w'</span>) <span class="hljs-keyword">as</span> file: -<span class="hljs-meta">... </span> file.write(<span class="hljs-string">'Hello World!'</span>) -<span class="hljs-meta">>>> </span><span class="hljs-keyword">with</span> MyOpen(<span class="hljs-string">'test.txt'</span>) <span class="hljs-keyword">as</span> file: -<span class="hljs-meta">... </span> print(file.read()) -Hello World! -</code></pre> -<h4 id="contextmanagers">Context managers:</h4> -<pre><code class="python language-python hljs"><span class="hljs-keyword">with</span> open(<span class="hljs-string">'<path>'</span>, ...) <span class="hljs-keyword">as</span> file: ... -<span class="hljs-keyword">with</span> wave.open(<span class="hljs-string">'<path>'</span>, ...) <span class="hljs-keyword">as</span> wave_file: ... -<span class="hljs-keyword">with</span> memoryview(<bytes/bytearray/array>) <span class="hljs-keyword">as</span> view: ... -</code></pre> -<h4 id="reusablecontextmanagers">Reusable context managers:</h4> -<pre><code class="python language-python hljs">lock = threading.RLock(); <span class="hljs-keyword">with</span> lock: ... -con = sqlite3.connect(<span class="hljs-string">'<path>'</span>); <span class="hljs-keyword">with</span> con: con.execute(<span class="hljs-string">'<insert_query>'</span>) -</code></pre> <h2 id="enum"><a href="#enum" name="enum">#</a>Enum</h2> <pre><code class="python language-python hljs"><span class="hljs-keyword">from</span> enum <span class="hljs-keyword">import</span> Enum, auto diff --git a/parse.js b/parse.js index dcba0af..6498c55 100755 --- a/parse.js +++ b/parse.js @@ -184,7 +184,7 @@ const DIAGRAM_7_B = '┠────────────┼──────────┼────────────┼──────────┼──────────────┨\n' + '┃ iter() │ ✓ │ ✓ │ ✓ │ ✓ ┃\n' + '┃ len() │ │ ✓ │ ✓ │ ✓ ┃\n' + - '┃ getitem() │ │ │ ✓ │ ✓ ┃\n' + + '┃ getitem() │ │ + │ ✓ │ ✓ ┃\n' + '┃ contains() │ │ ✓ │ │ ✓ ┃\n' + '┗━━━━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━━━━━━━┛\n';