Browse Source

Rewrite of Profiling

pull/109/merge
Jure Šorn 1 year ago
parent
commit
ad00805ce2
5 changed files with 109 additions and 94 deletions
  1. 75
      README.md
  2. 83
      index.html
  3. 39
      parse.js
  4. 4
      pdf/index_for_pdf.html
  5. 2
      pdf/index_for_pdf_print.html

75
README.md

@ -1935,14 +1935,14 @@ with <conn>.begin(): ... # Exits the block with commit or
``` ```
```text ```text
+------------+--------------+-----------+----------------------------------+ +------------+--------------+----------+----------------------------------+
| Dialect | pip3 install | import | Dependencies | | Dialect | pip3 install | import | Dependencies |
+------------+--------------+-----------+----------------------------------+ +------------+--------------+----------+----------------------------------+
| mysql | mysqlclient | MySQLdb | www.pypi.org/project/mysqlclient | | mysql | mysqlclient | MySQLdb | www.pypi.org/project/mysqlclient |
| postgresql | psycopg2 | psycopg2 | www.pypi.org/project/psycopg2 | | postgresql | psycopg2 | psycopg2 | www.pypi.org/project/psycopg2 |
| mssql | pyodbc | pyodbc | www.pypi.org/project/pyodbc | | mssql | pyodbc | pyodbc | www.pypi.org/project/pyodbc |
| oracle | oracledb | oracledb | www.pypi.org/project/oracledb | | oracle | oracledb | oracledb | www.pypi.org/project/oracledb |
+------------+--------------+-----------+----------------------------------+ +------------+--------------+----------+----------------------------------+
``` ```
@ -2591,49 +2591,48 @@ duration_in_seconds = perf_counter() - start_time
### Timing a Snippet ### Timing a Snippet
```python ```python
>>> from timeit import timeit >>> from timeit import timeit
>>> timeit("''.join(str(i) for i in range(100))", >>> timeit('list(range(10000))', number=1000, globals=globals(), setup='pass')
... number=10000, globals=globals(), setup='pass') 0.19373
0.34986
``` ```
### Profiling by Line ### Profiling by Line
```python ```text
# $ pip3 install line_profiler memory_profiler $ pip3 install line_profiler
$ echo "
@profile @profile
def main(): def main():
a = [*range(10000)] a = list(range(10000))
b = {*range(10000)} b = set(range(10000))
main() main()" > test.py
```
```text
$ kernprof -lv test.py $ kernprof -lv test.py
Line # Hits Time Per Hit % Time Line Contents Line # Hits Time Per Hit % Time Line Contents
======================================================= =======================================================
1 @profile 1 @profile
2 def main(): 2 def main():
3 1 955.0 955.0 43.7 a = [*range(10000)] 3 1 219.0 219.0 31.1 a = list(range(10000))
4 1 1231.0 1231.0 56.3 b = {*range(10000)} 4 1 487.0 487.0 68.9 b = set(range(10000))
$ python3 -m memory_profiler test.py
Line # Mem usage Increment Line Contents
=======================================================
1 37.668 MiB 37.668 MiB @profile
2 def main():
3 38.012 MiB 0.344 MiB a = [*range(10000)]
4 38.477 MiB 0.465 MiB b = {*range(10000)}
``` ```
### Call Graph ### Call and Flame Graphs
#### Generates a PNG image of the call graph with highlighted bottlenecks: ```bash
```python $ pip3 install gprof2dot snakeviz
# $ pip3 install pycallgraph2; apt/brew install graphviz $ apt/brew install graphviz
import pycallgraph2 as cg, datetime $ python3 -m cProfile -o test.prof test.py
$ gprof2dot -f pstats test.prof | dot -Tpng -o test.png; xdg-open/open test.png
$ snakeviz test.prof
```
filename = f'profile-{datetime.datetime.now():%Y%m%d_%H%M%S}.png' ### Sampling and Memory Profilers
drawer = cg.output.GraphvizOutput(output_file=filename) ```text
with cg.PyCallGraph(drawer): +--------------+-------------------------------+------------+----------+------+
<code_to_be_profiled> | pip3 install | How to run | Target | Type | Live |
+--------------+-------------------------------+------------+----------+------+
| py-spy | py-spy top -- python3 test.py | CPU | Sampling | Yes |
| pyinstrument | pyinstrument test.py | CPU | Sampling | No |
| scalene | scalene test.py | CPU+Memory | Sampling | No |
| memray | memray run --live test.py | Memory | Tracing | Yes |
| filprofiler | fil-profile run test.py | Memory | Tracing | No |
+--------------+-------------------------------+------------+----------+------+
``` ```

83
index.html

@ -54,7 +54,7 @@
<body> <body>
<header> <header>
<aside>June 9, 2023</aside> <aside>June 30, 2023</aside>
<a href="https://gto76.github.io" rel="author">Jure Šorn</a> <a href="https://gto76.github.io" rel="author">Jure Šorn</a>
</header> </header>
@ -1609,14 +1609,14 @@ CompletedProcess(args=[<span class="hljs-string">'bc'</span>, <span class="hljs-
<span class="hljs-keyword">with</span> &lt;conn&gt;.begin(): ... <span class="hljs-comment"># Exits the block with commit or rollback.</span> <span class="hljs-keyword">with</span> &lt;conn&gt;.begin(): ... <span class="hljs-comment"># Exits the block with commit or rollback.</span>
</code></pre></div> </code></pre></div>
<pre><code class="text language-text">┏━━━━━━━━━━━━┯━━━━━━━━━━━━━━┯━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ <pre><code class="text language-text">┏━━━━━━━━━━━━┯━━━━━━━━━━━━━━┯━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Dialect │ pip3 install │ import │ Dependencies ┃ Dialect │ pip3 install │ import │ Dependencies
┠────────────┼──────────────┼──────────┼──────────────────────────────────┨ ┠────────────┼──────────────┼──────────┼──────────────────────────────────┨
┃ mysql │ mysqlclient │ MySQLdb │ www.pypi.org/project/mysqlclient ┃ ┃ mysql │ mysqlclient │ MySQLdb │ www.pypi.org/project/mysqlclient ┃
┃ postgresql │ psycopg2 │ psycopg2 │ www.pypi.org/project/psycopg2 ┃ ┃ postgresql │ psycopg2 │ psycopg2 │ www.pypi.org/project/psycopg2 ┃
┃ mssql │ pyodbc │ pyodbc │ www.pypi.org/project/pyodbc ┃ ┃ mssql │ pyodbc │ pyodbc │ www.pypi.org/project/pyodbc ┃
┃ oracle │ oracledb │ oracledb │ www.pypi.org/project/oracledb ┃ ┃ oracle │ oracledb │ oracledb │ www.pypi.org/project/oracledb ┃
┗━━━━━━━━━━━━┷━━━━━━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━━━┷━━━━━━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
</code></pre> </code></pre>
<div><h2 id="bytes"><a href="#bytes" name="bytes">#</a>Bytes</h2><p><strong>Bytes object is an immutable sequence of single bytes. Mutable version is called bytearray.</strong></p><pre><code class="python language-python hljs">&lt;bytes&gt; = <span class="hljs-string">b'&lt;str&gt;'</span> <span class="hljs-comment"># Only accepts ASCII characters and \x00-\xff.</span> <div><h2 id="bytes"><a href="#bytes" name="bytes">#</a>Bytes</h2><p><strong>Bytes object is an immutable sequence of single bytes. Mutable version is called bytearray.</strong></p><pre><code class="python language-python hljs">&lt;bytes&gt; = <span class="hljs-string">b'&lt;str&gt;'</span> <span class="hljs-comment"># Only accepts ASCII characters and \x00-\xff.</span>
&lt;int&gt; = &lt;bytes&gt;[&lt;index&gt;] <span class="hljs-comment"># Returns an int in range from 0 to 255.</span> &lt;int&gt; = &lt;bytes&gt;[&lt;index&gt;] <span class="hljs-comment"># Returns an int in range from 0 to 255.</span>
@ -2124,44 +2124,43 @@ duration_in_seconds = perf_counter() - start_time
</code></pre></div> </code></pre></div>
<div><h3 id="timingasnippet">Timing a Snippet</h3><pre><code class="python language-python hljs"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">from</span> timeit <span class="hljs-keyword">import</span> timeit <div><h3 id="timingasnippet">Timing a Snippet</h3><pre><code class="python language-python hljs"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">from</span> timeit <span class="hljs-keyword">import</span> timeit
<span class="hljs-meta">&gt;&gt;&gt; </span>timeit(<span class="hljs-string">"''.join(str(i) for i in range(100))"</span>, <span class="hljs-meta">&gt;&gt;&gt; </span>timeit(<span class="hljs-string">'list(range(10000))'</span>, number=<span class="hljs-number">1000</span>, globals=globals(), setup=<span class="hljs-string">'pass'</span>)
<span class="hljs-meta">... </span> number=<span class="hljs-number">10000</span>, globals=globals(), setup=<span class="hljs-string">'pass'</span>) <span class="hljs-number">0.19373</span>
<span class="hljs-number">0.34986</span> </code></pre></div>
</code></pre></div> <div><h3 id="profilingbyline">Profiling by Line</h3><pre><code class="text language-text">$ pip3 install line_profiler
$ echo "
<div><h3 id="profilingbyline">Profiling by Line</h3><pre><code class="python language-python hljs"><span class="hljs-comment"># $ pip3 install line_profiler memory_profiler</span> @profile
<span class="hljs-meta">@profile</span> def main():
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span><span class="hljs-params">()</span>:</span> a = list(range(10000))
a = [*range(<span class="hljs-number">10000</span>)] b = set(range(10000))
b = {*range(<span class="hljs-number">10000</span>)} main()" &gt; test.py
main() $ kernprof -lv test.py
</code></pre></div>
<pre><code class="text language-text">$ kernprof -lv test.py
Line # Hits Time Per Hit % Time Line Contents Line # Hits Time Per Hit % Time Line Contents
======================================================= =======================================================
1 @profile 1 @profile
2 def main(): 2 def main():
3 1 955.0 955.0 43.7 a = [*range(10000)] 3 1 219.0 219.0 31.1 a = list(range(10000))
4 1 1231.0 1231.0 56.3 b = {*range(10000)} 4 1 487.0 487.0 68.9 b = set(range(10000))
</code></pre></div>
$ python3 -m memory_profiler test.py
Line # Mem usage Increment Line Contents
=======================================================
1 37.668 MiB 37.668 MiB @profile
2 def main():
3 38.012 MiB 0.344 MiB a = [*range(10000)]
4 38.477 MiB 0.465 MiB b = {*range(10000)}
</code></pre>
<div><h3 id="callgraph">Call Graph</h3><div><h4 id="generatesapngimageofthecallgraphwithhighlightedbottlenecks">Generates a PNG image of the call graph with highlighted bottlenecks:</h4><pre><code class="python language-python hljs"><span class="hljs-comment"># $ pip3 install pycallgraph2; apt/brew install graphviz</span>
<span class="hljs-keyword">import</span> pycallgraph2 <span class="hljs-keyword">as</span> cg, datetime
filename = <span class="hljs-string">f'profile-<span class="hljs-subst">{datetime.datetime.now():%Y%m%d_%H%M%S}</span>.png'</span> <div><h3 id="callandflamegraphs">Call and Flame Graphs</h3><pre><code class="bash language-bash hljs">$ pip3 install gprof2dot snakeviz
drawer = cg.output.GraphvizOutput(output_file=filename) $ apt/brew install graphviz
<span class="hljs-keyword">with</span> cg.PyCallGraph(drawer): $ python3 -m cProfile -o test.prof test.py
&lt;code_to_be_profiled&gt; $ gprof2dot -f pstats test.prof | dot -Tpng -o test.png; xdg-open/open test.png
</code></pre></div></div> $ snakeviz test.prof
</code></pre></div>
<div><h3 id="samplingandmemoryprofilers">Sampling and Memory Profilers</h3><pre><code class="text language-text">┏━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━┯━━━━━━━━━━┯━━━━━━┓
┃ pip3 install │ How to run │ Target │ Type │ Live ┃
┠──────────────┼───────────────────────────────┼────────────┼──────────┼──────┨
┃ py-spy │ py-spy top -- python3 test.py │ CPU │ Sampling │ Yes ┃
┃ pyinstrument │ pyinstrument test.py │ CPU │ Sampling │ No ┃
┃ scalene │ scalene test.py │ CPU+Memory │ Sampling │ No ┃
┃ memray │ memray run --live test.py │ Memory │ Tracing │ Yes ┃
┃ filprofiler │ fil-profile run test.py │ Memory │ Tracing │ No ┃
┗━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━┷━━━━━━━━━━┷━━━━━━┛
</code></pre></div>
<div><h2 id="numpy"><a href="#numpy" name="numpy">#</a>NumPy</h2><p><strong>Array manipulation mini-language. It can run up to one hundred times faster than the equivalent Python code. An even faster alternative that runs on a GPU is called CuPy.</strong></p><pre><code class="python language-python hljs"><span class="hljs-comment"># $ pip3 install numpy</span> <div><h2 id="numpy"><a href="#numpy" name="numpy">#</a>NumPy</h2><p><strong>Array manipulation mini-language. It can run up to one hundred times faster than the equivalent Python code. An even faster alternative that runs on a GPU is called CuPy.</strong></p><pre><code class="python language-python hljs"><span class="hljs-comment"># $ pip3 install numpy</span>
<span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np <span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np
@ -2934,7 +2933,7 @@ $ pyinstaller script.py --add-data '&lt;path&gt;:.' <span class="hljs-comment">
<footer> <footer>
<aside>June 9, 2023</aside> <aside>June 30, 2023</aside>
<a href="https://gto76.github.io" rel="author">Jure Šorn</a> <a href="https://gto76.github.io" rel="author">Jure Šorn</a>
</footer> </footer>

39
parse.js

@ -460,19 +460,19 @@ const DIAGRAM_9_B =
"┗━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━┛\n"; "┗━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━┛\n";
const DIAGRAM_95_A = const DIAGRAM_95_A =
"+------------+--------------+-----------+----------------------------------+\n" + '+------------+--------------+----------+----------------------------------+\n' +
"| Dialect | pip3 install | import | Dependencies |\n" + '| Dialect | pip3 install | import | Dependencies |\n' +
"+------------+--------------+-----------+----------------------------------+\n"; '+------------+--------------+----------+----------------------------------+\n';
const DIAGRAM_95_B = const DIAGRAM_95_B =
"┏━━━━━━━━━━━━┯━━━━━━━━━━━━━━┯━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n" + '┏━━━━━━━━━━━━┯━━━━━━━━━━━━━━┯━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n' +
"┃ Dialect │ pip3 install │ import │ Dependencies ┃\n" + '┃ Dialect │ pip3 install │ import │ Dependencies ┃\n' +
"┠────────────┼──────────────┼──────────┼──────────────────────────────────┨\n" + '┠────────────┼──────────────┼──────────┼──────────────────────────────────┨\n' +
"┃ mysql │ mysqlclient │ MySQLdb │ www.pypi.org/project/mysqlclient ┃\n" + '┃ mysql │ mysqlclient │ MySQLdb │ www.pypi.org/project/mysqlclient ┃\n' +
"┃ postgresql │ psycopg2 │ psycopg2 │ www.pypi.org/project/psycopg2 ┃\n" + '┃ postgresql │ psycopg2 │ psycopg2 │ www.pypi.org/project/psycopg2 ┃\n' +
"┃ mssql │ pyodbc │ pyodbc │ www.pypi.org/project/pyodbc ┃\n" + '┃ mssql │ pyodbc │ pyodbc │ www.pypi.org/project/pyodbc ┃\n' +
"┃ oracle │ oracledb │ oracledb │ www.pypi.org/project/oracledb ┃\n" + '┃ oracle │ oracledb │ oracledb │ www.pypi.org/project/oracledb ┃\n' +
"┗━━━━━━━━━━━━┷━━━━━━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n"; '┗━━━━━━━━━━━━┷━━━━━━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n';
const DIAGRAM_10_A = const DIAGRAM_10_A =
'+-------------+-------------+\n' + '+-------------+-------------+\n' +
@ -508,6 +508,22 @@ const DIAGRAM_11_B =
'┃ str │ ┃\n' + '┃ str │ ┃\n' +
'┗━━━━━━━━━━━━━┷━━━━━━━━━━━━━┛\n'; '┗━━━━━━━━━━━━━┷━━━━━━━━━━━━━┛\n';
const DIAGRAM_115_A =
'+--------------+-------------------------------+------------+----------+------+\n' +
'| pip3 install | How to run | Target | Type | Live |\n' +
'+--------------+-------------------------------+------------+----------+------+\n';
const DIAGRAM_115_B =
'┏━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━┯━━━━━━━━━━┯━━━━━━┓\n' +
'┃ pip3 install │ How to run │ Target │ Type │ Live ┃\n' +
'┠──────────────┼───────────────────────────────┼────────────┼──────────┼──────┨\n' +
'┃ py-spy │ py-spy top -- python3 test.py │ CPU │ Sampling │ Yes ┃\n' +
'┃ pyinstrument │ pyinstrument test.py │ CPU │ Sampling │ No ┃\n' +
'┃ scalene │ scalene test.py │ CPU+Memory │ Sampling │ No ┃\n' +
'┃ memray │ memray run --live test.py │ Memory │ Tracing │ Yes ┃\n' +
'┃ filprofiler │ fil-profile run test.py │ Memory │ Tracing │ No ┃\n' +
'┗━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━┷━━━━━━━━━━┷━━━━━━┛\n';
const DIAGRAM_12_A = const DIAGRAM_12_A =
'+-----------+-----------+------+-----------+\n' + '+-----------+-----------+------+-----------+\n' +
'| sampwidth | min | zero | max |\n' + '| sampwidth | min | zero | max |\n' +
@ -740,6 +756,7 @@ function updateDiagrams() {
$(`code:contains(${DIAGRAM_95_A})`).html(DIAGRAM_95_B); $(`code:contains(${DIAGRAM_95_A})`).html(DIAGRAM_95_B);
$(`code:contains(${DIAGRAM_10_A})`).html(DIAGRAM_10_B); $(`code:contains(${DIAGRAM_10_A})`).html(DIAGRAM_10_B);
$(`code:contains(${DIAGRAM_11_A})`).html(DIAGRAM_11_B); $(`code:contains(${DIAGRAM_11_A})`).html(DIAGRAM_11_B);
$(`code:contains(${DIAGRAM_115_A})`).html(DIAGRAM_115_B);
$(`code:contains(${DIAGRAM_12_A})`).html(DIAGRAM_12_B).removeClass("text").removeClass("language-text").addClass("python"); $(`code:contains(${DIAGRAM_12_A})`).html(DIAGRAM_12_B).removeClass("text").removeClass("language-text").addClass("python");
$(`code:contains(${DIAGRAM_13_A})`).html(DIAGRAM_13_B).removeClass("text").removeClass("language-text").addClass("python"); $(`code:contains(${DIAGRAM_13_A})`).html(DIAGRAM_13_B).removeClass("text").removeClass("language-text").addClass("python");
$(`code:contains(${DIAGRAM_14_A})`).parent().remove(); $(`code:contains(${DIAGRAM_14_A})`).parent().remove();

4
pdf/index_for_pdf.html

@ -51,7 +51,7 @@
<strong>filter function, <a href="#mapfilterreduce">11</a></strong><br> <strong>filter function, <a href="#mapfilterreduce">11</a></strong><br>
<strong>flask library, <a href="#web">36</a></strong><br> <strong>flask library, <a href="#web">36</a></strong><br>
<strong>floats, <a href="#abstractbaseclasses">4</a>, <a href="#floats">6</a>, <a href="#types">7</a></strong><br> <strong>floats, <a href="#abstractbaseclasses">4</a>, <a href="#floats">6</a>, <a href="#types">7</a></strong><br>
<strong>format, <a href="#format">6</a>-<a href="#comparisonofpresentationtypes">7</a>, <a href="#callgraph">37</a></strong><br> <strong>format, <a href="#format">6</a>-<a href="#comparisonofpresentationtypes">7</a></strong><br>
<strong>functools module, <a href="#mapfilterreduce">11</a>, <a href="#partial">12</a>, <a href="#debuggerexample">13</a>, <a href="#sortable">16</a></strong><br> <strong>functools module, <a href="#mapfilterreduce">11</a>, <a href="#partial">12</a>, <a href="#debuggerexample">13</a>, <a href="#sortable">16</a></strong><br>
<strong>futures, <a href="#threadpoolexecutor">30</a></strong> </p> <strong>futures, <a href="#threadpoolexecutor">30</a></strong> </p>
<h3 id="g">G</h3> <h3 id="g">G</h3>
@ -103,7 +103,7 @@
<strong>pillow library, <a href="#image">39</a>-<a href="#animation">40</a></strong><br> <strong>pillow library, <a href="#image">39</a>-<a href="#animation">40</a></strong><br>
<strong>plotting, <a href="#plot">34</a>, <a href="#dataframeencodedecodeplot">46</a>, <a href="#plotly">47</a>-<a href="#displaysamultiaxislinechartoftotalcoronaviruscasesandchangesinpricesofbitcoindowjonesandgold">48</a></strong><br> <strong>plotting, <a href="#plot">34</a>, <a href="#dataframeencodedecodeplot">46</a>, <a href="#plotly">47</a>-<a href="#displaysamultiaxislinechartoftotalcoronaviruscasesandchangesinpricesofbitcoindowjonesandgold">48</a></strong><br>
<strong>print function, <a href="#print">22</a></strong><br> <strong>print function, <a href="#print">22</a></strong><br>
<strong>profiling, <a href="#profiling">36</a>-<a href="#timingasnippet">37</a></strong><br> <strong>profiling, <a href="#profiling">36</a>-<a href="#profilingbyline">37</a></strong><br>
<strong>progress bar, <a href="#progressbar">34</a></strong><br> <strong>progress bar, <a href="#progressbar">34</a></strong><br>
<strong>property decorator, <a href="#property">15</a></strong><br> <strong>property decorator, <a href="#property">15</a></strong><br>
<strong>pygame library, <a href="#pygame">42</a>-<a href="#basicmariobrothersexample">43</a></strong> </p> <strong>pygame library, <a href="#pygame">42</a>-<a href="#basicmariobrothersexample">43</a></strong> </p>

2
pdf/index_for_pdf_print.html

@ -51,7 +51,7 @@
<strong>filter function, 11</strong><br> <strong>filter function, 11</strong><br>
<strong>flask library, 36</strong><br> <strong>flask library, 36</strong><br>
<strong>floats, 4, 6, 7</strong><br> <strong>floats, 4, 6, 7</strong><br>
<strong>format, 6-7, 37</strong><br> <strong>format, 6-7</strong><br>
<strong>functools module, 11, 12, 13, 16</strong><br> <strong>functools module, 11, 12, 13, 16</strong><br>
<strong>futures, 30</strong> </p> <strong>futures, 30</strong> </p>
<h3 id="g">G</h3> <h3 id="g">G</h3>

|||||||
100:0
Loading…
Cancel
Save