Browse Source

Removed Metaprogramming and Eval, added Match statement, expanded PySimpleGUI and Scraping, updated String, Regex, Arguments, Corountines and Image

pull/170/head
Jure Šorn 1 year ago
parent
commit
d20cfa1083
4 changed files with 367 additions and 360 deletions
  1. 337
      README.md
  2. 315
      index.html
  3. 56
      parse.js
  4. 19
      web/script_2.js

337
README.md

@ -16,6 +16,9 @@ Contents
**   ** **6. Advanced:** **   ** **[`Threading`](#threading)**__,__ **[`Operator`](#operator)**__,__ **[`Introspection`](#introspection)**__,__ **[`Metaprograming`](#metaprogramming)**__,__ **[`Eval`](#eval)**__,__ **[`Coroutines`](#coroutines)**__.__ **   ** **6. Advanced:** **   ** **[`Threading`](#threading)**__,__ **[`Operator`](#operator)**__,__ **[`Introspection`](#introspection)**__,__ **[`Metaprograming`](#metaprogramming)**__,__ **[`Eval`](#eval)**__,__ **[`Coroutines`](#coroutines)**__.__
**   ** **7. Libraries:** **      ** **[`Progress_Bar`](#progress-bar)**__,__ **[`Plot`](#plot)**__,__ **[`Tables`](#table)**__,__ **[`Curses`](#curses)**__,__ **[`Logging`](#logging)**__,__ **[`Scraping`](#scraping)**__,__ **[`Web`](#web)**__,__ **[`Profile`](#profiling)**__.__ **   ** **7. Libraries:** **      ** **[`Progress_Bar`](#progress-bar)**__,__ **[`Plot`](#plot)**__,__ **[`Tables`](#table)**__,__ **[`Curses`](#curses)**__,__ **[`Logging`](#logging)**__,__ **[`Scraping`](#scraping)**__,__ **[`Web`](#web)**__,__ **[`Profile`](#profiling)**__.__
**   ** **8. Multimedia:** **  ** **[`NumPy`](#numpy)**__,__ **[`Image`](#image)**__,__ **[`Animation`](#animation)**__,__ **[`Audio`](#audio)**__,__ **[`Pygame`](#pygame)**__,__ **[`Pandas`](#pandas)**__,__ **[`Plotly`](#plotly)**__,__ **[`PySimpleGUI`](#pysimplegui)**__.__ **   ** **8. Multimedia:** **  ** **[`NumPy`](#numpy)**__,__ **[`Image`](#image)**__,__ **[`Animation`](#animation)**__,__ **[`Audio`](#audio)**__,__ **[`Pygame`](#pygame)**__,__ **[`Pandas`](#pandas)**__,__ **[`Plotly`](#plotly)**__,__ **[`PySimpleGUI`](#pysimplegui)**__.__
**   ** **6. Advanced:** **   ** **[`Threading`](#threading)**__,__ **[`Operator`](#operator)**__,__ **[`Match_Stmt`](#match-statement)**__,__ **[`Introspection`](#introspection)**__,__ **[`Logging`](#logging)**__,__ **[`Coroutines`](#coroutines)**__.__
**   ** **7. Libraries:** **      ** **[`Progress_Bar`](#progress-bar)**__,__ **[`Plots`](#plot)**__,__ **[`Tables`](#table)**__,__ **[`Curses`](#curses)**__,__ **[`GUIs`](#pysimplegui)**__,__ **[`Scraping`](#scraping)**__,__ **[`Web`](#web)**__,__ **[`Profiling`](#profiling)**__.__
**   ** **8. Multimedia:** **  ** **[`NumPy`](#numpy)**__,__ **[`Image`](#image)**__,__ **[`Animation`](#animation)**__,__ **[`Audio`](#audio)**__,__ **[`Synthesizer`](#synthesizer)**__,__ **[`Pygame`](#pygame)**__,__ **[`Pandas`](#pandas)**__,__ **[`Plotly`](#plotly)**__.__
Main Main
@ -317,7 +320,6 @@ String
```python ```python
<bool> = <sub_str> in <str> # Checks if string contains the substring. <bool> = <sub_str> in <str> # Checks if string contains the substring.
<bool> = <str>.startswith(<sub_str>) # Pass tuple of strings for multiple options. <bool> = <str>.startswith(<sub_str>) # Pass tuple of strings for multiple options.
<bool> = <str>.endswith(<sub_str>) # Pass tuple of strings for multiple options.
<int> = <str>.find(<sub_str>) # Returns start index of the first match or -1. <int> = <str>.find(<sub_str>) # Returns start index of the first match or -1.
<int> = <str>.index(<sub_str>) # Same, but raises ValueError if missing. <int> = <str>.index(<sub_str>) # Same, but raises ValueError if missing.
``` ```
@ -333,6 +335,7 @@ String
<int> = ord(<str>) # Converts Unicode character to int. <int> = ord(<str>) # Converts Unicode character to int.
``` ```
* **Use `'unicodedata.normalize("NFC", <str>)'` on strings that may contain characters like `'Ö'` before comparing them, because they can be stored as one or two characters.** * **Use `'unicodedata.normalize("NFC", <str>)'` on strings that may contain characters like `'Ö'` before comparing them, because they can be stored as one or two characters.**
* **`'NFC'` converts such characters to a single character, while `'NFD'` converts them to two.**
### Property Methods ### Property Methods
```python ```python
@ -351,9 +354,6 @@ Regex
```python ```python
import re import re
```
```python
<str> = re.sub(<regex>, new, text, count=0) # Substitutes all occurrences with 'new'. <str> = re.sub(<regex>, new, text, count=0) # Substitutes all occurrences with 'new'.
<list> = re.findall(<regex>, text) # Returns all occurrences as strings. <list> = re.findall(<regex>, text) # Returns all occurrences as strings.
<list> = re.split(<regex>, text, maxsplit=0) # Add brackets around regex to include matches. <list> = re.split(<regex>, text, maxsplit=0) # Add brackets around regex to include matches.
@ -368,6 +368,7 @@ import re
* **Argument `'flags=re.DOTALL'` makes `'.'` also accept the `'\n'`.** * **Argument `'flags=re.DOTALL'` makes `'.'` also accept the `'\n'`.**
* **Use `r'\1'` or `'\\1'` for backreference (`'\1'` returns a character with octal code 1).** * **Use `r'\1'` or `'\\1'` for backreference (`'\1'` returns a character with octal code 1).**
* **Add `'?'` after `'*'` and `'+'` to make them non-greedy.** * **Add `'?'` after `'*'` and `'+'` to make them non-greedy.**
* **`'re.compile(<regex>)'` returns a Pattern object with listed methods.**
### Match Object ### Match Object
```python ```python
@ -589,7 +590,7 @@ Datetime
**Provides 'date', 'time', 'datetime' and 'timedelta' classes. All are immutable and hashable.** **Provides 'date', 'time', 'datetime' and 'timedelta' classes. All are immutable and hashable.**
```python ```python
# pip3 install python-dateutil
# $ pip3 install python-dateutil
from datetime import date, time, datetime, timedelta, timezone from datetime import date, time, datetime, timedelta, timezone
from dateutil.tz import tzlocal, gettz from dateutil.tz import tzlocal, gettz
``` ```
@ -740,7 +741,7 @@ def f(x, y, *, z): ... # f(x=1, y=2, z=3) | f(1, y=2, z=3) | f(1, 2, z=
<list> = [*<coll.> [, ...]] # Or: list(<collection>) [+ ...] <list> = [*<coll.> [, ...]] # Or: list(<collection>) [+ ...]
<tuple> = (*<coll.>, [...]) # Or: tuple(<collection>) [+ ...] <tuple> = (*<coll.>, [...]) # Or: tuple(<collection>) [+ ...]
<set> = {*<coll.> [, ...]} # Or: set(<collection>) [| ...] <set> = {*<coll.> [, ...]} # Or: set(<collection>) [| ...]
<dict> = {**<dict> [, ...]} # Or: dict(**<dict> [, ...])
<dict> = {**<dict> [, ...]} # Or: dict(<dict>) [| ...] (since 3.9)
``` ```
```python ```python
@ -2183,6 +2184,48 @@ first_element = op.methodcaller('pop', 0)(<list>)
* **Also: `'<bool> = <bool> &|^ <bool>'` and `'<int> = <bool> &|^ <int>'`.** * **Also: `'<bool> = <bool> &|^ <bool>'` and `'<int> = <bool> &|^ <int>'`.**
Match Statement
---------------
**Executes the first block with matching pattern. Added in Python 3.10.**
```python
match <object/expression>:
case <pattern> [if <condition>]:
<code>
...
```
### Patterns
```python
<value_pattern> = 1/'abc'/True/None/math.pi # Matches the literal or a dotted name.
<class_pattern> = <type>() # Matches any object of that type.
<capture_patt> = <name> # Matches any object and binds it to name.
<or_pattern> = <pattern> | <pattern> [| ...] # Matches any of the patterns.
<as_pattern> = <pattern> as <name> # Binds the match to the name.
<sequence_patt> = [<pattern>, ...] # Matches sequence with matching items.
<mapping_patt> = {<value_patt>: <pattern>, ...} # Matches dictionary with matching items.
<class_pattern> = <type>(<attr_name>=<patt>, ...) # Matches object with matching attributes.
```
* **Sequence pattern can also be written as a tuple.**
* **Use `'*<name>'` and `'**<name>'` in sequence/mapping patterns to bind remaining items.**
* **Patterns can be surrounded with brackets to override precedence (`'|'` > `'as'` > `','`).**
* **Built-in types allow a single positional pattern that is matched against the entire object.**
* **All names that are bound in the matching case, as well as variables initialized in its block, are visible after the match statement.**
### Example
```python
>>> from pathlib import Path
>>> match Path('/home/gto/python-cheatsheet/README.md'):
... case Path(
... parts=['/', 'home', user, *_],
... stem=stem,
... suffix=('.md' | '.txt') as suffix
... ) if stem.lower() == 'readme':
... print(f'{stem}{suffix} is a readme file that belongs to user {user}.')
'README.md is a readme file that belongs to user gto.'
```
Introspection Introspection
------------- -------------
```python ```python
@ -2191,7 +2234,6 @@ Introspection
<dict> = globals() # Dict of global vars, etc. (incl. '__builtins__'). <dict> = globals() # Dict of global vars, etc. (incl. '__builtins__').
``` ```
### Attributes
```python ```python
<list> = dir(<object>) # Names of object's attributes (including methods). <list> = dir(<object>) # Names of object's attributes (including methods).
<dict> = vars(<object>) # Dict of writable attributes. Also <obj>.__dict__. <dict> = vars(<object>) # Dict of writable attributes. Also <obj>.__dict__.
@ -2201,7 +2243,6 @@ setattr(<object>, '<attr_name>', value) # Only works on objects with '__dict_
delattr(<object>, '<attr_name>') # Same. Also `del <object>.<attr_name>`. delattr(<object>, '<attr_name>') # Same. Also `del <object>.<attr_name>`.
``` ```
### Parameters
```python ```python
<Sig> = inspect.signature(<function>) # Function's Signature object. <Sig> = inspect.signature(<function>) # Function's Signature object.
<dict> = <Sig>.parameters # Dict of Parameter objects. <dict> = <Sig>.parameters # Dict of Parameter objects.
@ -2211,101 +2252,56 @@ delattr(<object>, '<attr_name>') # Same. Also `del <object>.<attr_name
``` ```
Metaprogramming
---------------
**Code that generates code.**
### Type
**Type is the root class. If only passed an object it returns its type (class). Otherwise it creates a new class.**
```python
<class> = type('<class_name>', <tuple_of_parents>, <dict_of_class_attributes>)
```
```python
>>> Z = type('Z', (), {'a': 'abcde', 'b': 12345})
>>> z = Z()
```
### Meta Class
**A class that creates classes.**
```python
def my_meta_class(name, parents, attrs):
attrs['a'] = 'abcde'
return type(name, parents, attrs)
```
#### Or:
```python
class MyMetaClass(type):
def __new__(cls, name, parents, attrs):
attrs['a'] = 'abcde'
return type.__new__(cls, name, parents, attrs)
```
* **New() is a class method that gets called before init(). If it returns an instance of its class, then that instance gets passed to init() as a 'self' argument.**
* **It receives the same arguments as init(), except for the first one that specifies the desired type of the returned instance (MyMetaClass in our case).**
* **Like in our case, new() can also be called directly, usually from a new() method of a child class (**`def __new__(cls): return super().__new__(cls)`**).**
* **The only difference between the examples above is that my\_meta\_class() returns a class of type type, while MyMetaClass() returns a class of type MyMetaClass.**
### Metaclass Attribute
**Right before a class is created it checks if it has the 'metaclass' attribute defined. If not, it recursively checks if any of its parents has it defined and eventually comes to type().**
Logging
-------
```python ```python
class MyClass(metaclass=MyMetaClass):
b = 12345
import logging
``` ```
```python ```python
>>> MyClass.a, MyClass.b
('abcde', 12345)
logging.basicConfig(filename=<path>, level='DEBUG') # Configures the root logger (see Setup).
logging.debug/info/warning/error/critical(<str>) # Logs to the root logger.
<Logger> = logging.getLogger(__name__) # Logger named after the module.
<Logger>.<level>(<str>) # Logs to the logger.
<Logger>.exception(<str>) # Calls error() with caught exception.
``` ```
### Type Diagram
### Setup
```python ```python
type(MyClass) == MyMetaClass # MyClass is an instance of MyMetaClass.
type(MyMetaClass) == type # MyMetaClass is an instance of type.
```
```text
+-------------+-------------+
| Classes | Metaclasses |
+-------------+-------------|
| MyClass <-- MyMetaClass |
| | ^ |
| object <----- type <+ |
| | | +--+ |
| str <---------+ |
+-------------+-------------+
logging.basicConfig(
filename=None, # Logs to console (stderr) by default.
format='%(levelname)s:%(name)s:%(message)s', # Add '%(asctime)s' for local datetime.
level=logging.WARNING, # Drops messages with lower priority.
handlers=[logging.StreamHandler(sys.stderr)] # Uses FileHandler if filename is set.
)
``` ```
### Inheritance Diagram
```python ```python
MyClass.__base__ == object # MyClass is a subclass of object.
MyMetaClass.__base__ == type # MyMetaClass is a subclass of type.
```
```text
+-------------+-------------+
| Classes | Metaclasses |
+-------------+-------------|
| MyClass | MyMetaClass |
| ^ | ^ |
| object -----> type |
| v | |
| str | |
+-------------+-------------+
<Formatter> = logging.Formatter('<format>') # Creates a Formatter.
<Handler> = logging.FileHandler(<path>, mode='a') # Creates a Handler. Also `encoding=None`.
<Handler>.setFormatter(<Formatter>) # Adds Formatter to the Handler.
<Handler>.setLevel(<int/str>) # Processes all messages by default.
<Logger>.addHandler(<Handler>) # Adds Handler to the Logger.
<Logger>.setLevel(<int/str>) # What is sent to its/ancestor's handlers.
``` ```
* **Parent logger can be specified by naming the child logger `'<parent>.<name>'`.**
* **If logger doesn't have a set level it inherits it from the first ancestor that does.**
* **Formatter also accepts: pathname, filename, funcName, lineno, thread and process.**
* **A `'handlers.RotatingFileHandler'` creates and deletes log files based on 'maxBytes' and 'backupCount' arguments.**
Eval
----
#### Creates a logger that writes all messages to file and sends them to the root's handler that prints warnings or higher:
```python ```python
>>> from ast import literal_eval
>>> literal_eval('[1, 2, 3]')
[1, 2, 3]
>>> literal_eval('1 + 2')
ValueError: malformed node or string
>>> logger = logging.getLogger('my_module')
>>> handler = logging.FileHandler('test.log', encoding='utf-8')
>>> formatter = logging.Formatter('%(asctime)s %(levelname)s:%(name)s:%(message)s')
>>> handler.setFormatter(formatter)
>>> logger.addHandler(handler)
>>> logging.basicConfig(level='DEBUG')
>>> logging.root.handlers[0].setLevel('WARNING')
>>> logger.critical('Running out of disk space.')
CRITICAL:my_module:Running out of disk space.
>>> print(open('test.log').read())
2023-02-07 23:21:01,430 CRITICAL:my_module:Running out of disk space.
``` ```
@ -2320,7 +2316,7 @@ Coroutines
#### Runs a terminal game where you control an asterisk that must avoid numbers: #### Runs a terminal game where you control an asterisk that must avoid numbers:
```python ```python
import asyncio, collections, curses, curses.textpad, enum, random
import asyncio, collections, curses, curses.textpad, enum, random, time
P = collections.namedtuple('P', 'x y') # Position P = collections.namedtuple('P', 'x y') # Position
D = enum.Enum('D', 'n e s w') # Direction D = enum.Enum('D', 'n e s w') # Direction
@ -2348,7 +2344,8 @@ async def random_controller(id_, moves):
async def human_controller(screen, moves): async def human_controller(screen, moves):
while True: while True:
key_mappings = {258: D.s, 259: D.n, 260: D.w, 261: D.e} key_mappings = {258: D.s, 259: D.n, 260: D.w, 261: D.e}
if d := key_mappings.get(screen.getch()):
ch = screen.getch()
if d := key_mappings.get(ch):
moves.put_nowait(('*', d)) moves.put_nowait(('*', d))
await asyncio.sleep(0.005) await asyncio.sleep(0.005)
@ -2357,7 +2354,8 @@ async def model(moves, state):
id_, d = await moves.get() id_, d = await moves.get()
x, y = state[id_] x, y = state[id_]
deltas = {D.n: P(0, -1), D.e: P(1, 0), D.s: P(0, 1), D.w: P(-1, 0)} deltas = {D.n: P(0, -1), D.e: P(1, 0), D.s: P(0, 1), D.w: P(-1, 0)}
state[id_] = P((x + deltas[d].x) % W, (y + deltas[d].y) % H)
dx, dy = deltas[d]
state[id_] = P((x + dx) % W, (y + dy) % H)
async def view(state, screen): async def view(state, screen):
offset = P(curses.COLS//2 - W//2, curses.LINES//2 - H//2) offset = P(curses.COLS//2 - W//2, curses.LINES//2 - H//2)
@ -2365,13 +2363,18 @@ async def view(state, screen):
screen.erase() screen.erase()
curses.textpad.rectangle(screen, offset.y-1, offset.x-1, offset.y+H, offset.x+W) curses.textpad.rectangle(screen, offset.y-1, offset.x-1, offset.y+H, offset.x+W)
for id_, p in state.items(): for id_, p in state.items():
screen.addstr(offset.y + (p.y - state['*'].y + H//2) % H,
offset.x + (p.x - state['*'].x + W//2) % W, str(id_))
screen.addstr(
offset.y + (p.y - state['*'].y + H//2) % H,
offset.x + (p.x - state['*'].x + W//2) % W,
str(id_)
)
screen.refresh() screen.refresh()
await asyncio.sleep(0.005) await asyncio.sleep(0.005)
if __name__ == '__main__': if __name__ == '__main__':
start_time = time.perf_counter()
curses.wrapper(main) curses.wrapper(main)
print(f'You survived {time.perf_counter() - start_time:.2f} seconds.')
``` ```
<br> <br>
@ -2421,7 +2424,7 @@ Curses
------ ------
#### Runs a basic file explorer in the console: #### Runs a basic file explorer in the console:
```python ```python
# pip3 install windows-curses
# $ pip3 install windows-curses
import curses, os import curses, os
from curses import A_REVERSE, KEY_DOWN, KEY_UP, KEY_LEFT, KEY_RIGHT, KEY_ENTER from curses import A_REVERSE, KEY_DOWN, KEY_UP, KEY_LEFT, KEY_RIGHT, KEY_ENTER
@ -2448,56 +2451,33 @@ if __name__ == '__main__':
``` ```
Logging
-------
```python
import logging
```
PySimpleGUI
-----------
#### A weight converter GUI application:
```python ```python
logging.basicConfig(filename=<path>, level='DEBUG') # Configures the root logger (see Setup).
logging.debug/info/warning/error/critical(<str>) # Logs to the root logger.
<Logger> = logging.getLogger(__name__) # Logger named after the module.
<Logger>.<level>(<str>) # Logs to the logger.
<Logger>.exception(<str>) # Calls error() with caught exception.
```
# $ pip3 install PySimpleGUI
import PySimpleGUI as sg
### Setup
```python
logging.basicConfig(
filename=None, # Logs to console (stderr) by default.
format='%(levelname)s:%(name)s:%(message)s', # Add '%(asctime)s' for local datetime.
level=logging.WARNING, # Drops messages with lower priority.
handlers=[logging.StreamHandler(sys.stderr)] # Uses FileHandler if filename is set.
)
```
text_box = sg.Input(default_text='100', enable_events=True, key='-VALUE-')
dropdown = sg.InputCombo(['g', 'kg', 't'], 'kg', readonly=True, enable_events=True, k='-UNIT-')
label = sg.Text('100 kg is 220.462 lbs.', key='-OUTPUT-')
button = sg.Button('Close')
window = sg.Window('Weight Converter', [[text_box, dropdown], [label], [button]])
```python
<Formatter> = logging.Formatter('<format>') # Creates a Formatter.
<Handler> = logging.FileHandler(<path>, mode='a') # Creates a Handler. Also `encoding=None`.
<Handler>.setFormatter(<Formatter>) # Adds Formatter to the Handler.
<Handler>.setLevel(<int/str>) # Processes all messages by default.
<Logger>.addHandler(<Handler>) # Adds Handler to the Logger.
<Logger>.setLevel(<int/str>) # What is sent to its/ancestor's handlers.
```
* **Parent logger can be specified by naming the child logger `'<parent>.<name>'`.**
* **If logger doesn't have a set level it inherits it from the first ancestor that does.**
* **Formatter also accepts: pathname, filename, funcName, lineno, thread and process.**
* **A `'handlers.RotatingFileHandler'` creates and deletes log files based on 'maxBytes' and 'backupCount' arguments.**
#### Creates a logger that writes all messages to file and sends them to the root's handler that prints warnings or higher:
```python
>>> logger = logging.getLogger('my_module')
>>> handler = logging.FileHandler('test.log', encoding='utf-8')
>>> formatter = logging.Formatter('%(asctime)s %(levelname)s:%(name)s:%(message)s')
>>> handler.setFormatter(formatter)
>>> logger.addHandler(handler)
>>> logging.basicConfig(level='DEBUG')
>>> logging.root.handlers[0].setLevel('WARNING')
>>> logger.critical('Running out of disk space.')
CRITICAL:my_module:Running out of disk space.
>>> print(open('test.log').read())
2023-02-07 23:21:01,430 CRITICAL:my_module:Running out of disk space.
while True:
event, values = window.read()
if event in [sg.WIN_CLOSED, 'Close']:
break
try:
value = float(values['-VALUE-'])
except ValueError:
continue
unit = values['-UNIT-']
units = {'g': 0.001, 'kg': 1, 't': 1000}
lbs = value * units[unit] / 0.45359237
window['-OUTPUT-'].update(value=f'{value} {unit} is {lbs:g} lbs.')
window.close()
``` ```
@ -2506,21 +2486,43 @@ Scraping
#### Scrapes Python's URL and logo from its Wikipedia page: #### Scrapes Python's URL and logo from its Wikipedia page:
```python ```python
# $ pip3 install requests beautifulsoup4 # $ pip3 install requests beautifulsoup4
import requests, bs4, os, sys
import requests, bs4, os
try:
response = requests.get('https://en.wikipedia.org/wiki/Python_(programming_language)')
document = bs4.BeautifulSoup(response.text, 'html.parser')
table = document.find('table', class_='infobox vevent')
python_url = table.find('th', text='Website').next_sibling.a['href']
logo_url = table.find('img')['src']
logo = requests.get(f'https:{logo_url}').content
filename = os.path.basename(logo_url)
with open(filename, 'wb') as file:
file.write(logo)
print(f'{python_url}, file://{os.path.abspath(filename)}')
except requests.exceptions.ConnectionError:
print("You've got problems with connection.", file=sys.stderr)
response = requests.get('https://en.wikipedia.org/wiki/Python_(programming_language)')
document = bs4.BeautifulSoup(response.text, 'html.parser')
table = document.find('table', class_='infobox vevent')
python_url = table.find('th', text='Website').next_sibling.a['href']
logo_url = table.find('img')['src']
logo = requests.get(f'https:{logo_url}').content
filename = os.path.basename(logo_url)
with open(filename, 'wb') as file:
file.write(logo)
print(f'{python_url}, file://{os.path.abspath(filename)}')
```
### Selenium
**Library for scraping websites with dynamic content.**
```python
# $ pip3 install selenium
from selenium import webdriver
<Drv> = webdriver.Chrome/Firefox/Safari/Edge() # Opens a browser. Also <Drv>.quit().
<Drv>.get('<url>') # Also <Drv>.implicitly_wait(seconds).
<El> = <Drv/El>.find_element('css selector', '<css>') # '<tag>#<id>.<class>[<attr>="<val>"]'.
<list> = <Drv/El>.find_elements('xpath', '<xpath>') # '//<tag>[@<attr>="<val>"]'.
<str> = <El>.get_attribute/get_property(<str>) # Also <El>.text/tag_name.
<El>.click/clear() # Also <El>.send_keys(<str>).
```
#### XPath — also available in browser's console via `'$x(<xpath>)'`:
```python
<xpath> = //<element>[/ or // <element>] # Child: /, Descendant: //, Parent: /..
<xpath> = //<element>/following::<element> # Next sibling. Also preceding/parent/…
<element> = <tag><conditions><index> # `<tag> = */a/…`, `<index> = [1/2/…]`.
<condition> = [<sub_cond> [and/or <sub_cond>]] # `and` is same as chaining conditions.
<sub_cond> = @<attr>="<val>" # `.="<val>"` matches complete text.
<sub_cond> = contains(@<attr>, "<val>") # Is <val> a substring of attr's value?
<sub_cond> = [//]<element> # Has matching child? Descendant if //.
``` ```
@ -2763,9 +2765,9 @@ from PIL import Image, ImageFilter, ImageEnhance
``` ```
```python ```python
<int/tuple> = <Image>.getpixel((x, y)) # Returns pixel's color.
<Image>.putpixel((x, y), <int/tuple>) # Changes pixel's color.
<ImagingCore> = <Image>.getdata() # Returns a flattened view of all pixels.
<int/tuple> = <Image>.getpixel((x, y)) # Returns pixel's value (its color).
<Image>.putpixel((x, y), <int/tuple>) # Updates pixel's value.
<ImagingCore> = <Image>.getdata() # Returns a flattened view of pixel values.
<Image>.putdata(<list/ImagingCore>) # Updates pixels with a copy of the sequence. <Image>.putdata(<list/ImagingCore>) # Updates pixels with a copy of the sequence.
<Image>.paste(<Image>, (x, y)) # Draws passed image at specified location. <Image>.paste(<Image>, (x, y)) # Draws passed image at specified location.
``` ```
@ -2776,8 +2778,8 @@ from PIL import Image, ImageFilter, ImageEnhance
``` ```
```python ```python
<array> = np.array(<Image>) # Creates a NumPy array from the image.
<Image> = Image.fromarray(np.uint8(<array>)) # Use <array>.clip(0, 255) to clip values.
<array> = np.array(<Image>) # Creates a 2d/3d NumPy array from the image.
<Image> = Image.fromarray(np.uint8(<array>)) # Use `<array>.clip(0, 255)` to clip values.
``` ```
### Modes ### Modes
@ -3496,19 +3498,6 @@ if __name__ == '__main__':
``` ```
PySimpleGUI
-----------
```python
# $ pip3 install PySimpleGUI
import PySimpleGUI as sg
layout = [[sg.Text("What's your name?")], [sg.Input()], [sg.Button('Ok')]]
window = sg.Window('Window Title', layout)
event, values = window.read()
print(f'Hello {values[0]}!' if event == 'Ok' else '')
```
Appendix Appendix
-------- --------
### Cython ### Cython

315
index.html

@ -54,7 +54,7 @@
<body> <body>
<header> <header>
<aside>December 6, 2023</aside>
<aside>December 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>
@ -85,9 +85,9 @@
<strong><span class="hljs-string"><span class="hljs-string">'3. Syntax'</span></span></strong>: [<a href="#arguments">Args</a>, <a href="#inline">Inline</a>, <a href="#imports">Import</a>, <a href="#decorator">Decorator</a>, <a href="#class">Class</a>, <a href="#ducktypes">Duck_Types</a>, <a href="#enum">Enum</a>, <a href="#exceptions">Exception</a>], <strong><span class="hljs-string"><span class="hljs-string">'3. Syntax'</span></span></strong>: [<a href="#arguments">Args</a>, <a href="#inline">Inline</a>, <a href="#imports">Import</a>, <a href="#decorator">Decorator</a>, <a href="#class">Class</a>, <a href="#ducktypes">Duck_Types</a>, <a href="#enum">Enum</a>, <a href="#exceptions">Exception</a>],
<strong><span class="hljs-string"><span class="hljs-string">'4. System'</span></span></strong>: [<a href="#exit">Exit</a>, <a href="#print">Print</a>, <a href="#input">Input</a>, <a href="#commandlinearguments">Command_Line_Arguments</a>, <a href="#open">Open</a>, <a href="#paths">Path</a>, <a href="#oscommands">OS_Commands</a>], <strong><span class="hljs-string"><span class="hljs-string">'4. System'</span></span></strong>: [<a href="#exit">Exit</a>, <a href="#print">Print</a>, <a href="#input">Input</a>, <a href="#commandlinearguments">Command_Line_Arguments</a>, <a href="#open">Open</a>, <a href="#paths">Path</a>, <a href="#oscommands">OS_Commands</a>],
<strong><span class="hljs-string"><span class="hljs-string">'5. Data'</span></span></strong>: [<a href="#json">JSON</a>, <a href="#pickle">Pickle</a>, <a href="#csv">CSV</a>, <a href="#sqlite">SQLite</a>, <a href="#bytes">Bytes</a>, <a href="#struct">Struct</a>, <a href="#array">Array</a>, <a href="#memoryview">Memory_View</a>, <a href="#deque">Deque</a>], <strong><span class="hljs-string"><span class="hljs-string">'5. Data'</span></span></strong>: [<a href="#json">JSON</a>, <a href="#pickle">Pickle</a>, <a href="#csv">CSV</a>, <a href="#sqlite">SQLite</a>, <a href="#bytes">Bytes</a>, <a href="#struct">Struct</a>, <a href="#array">Array</a>, <a href="#memoryview">Memory_View</a>, <a href="#deque">Deque</a>],
<strong><span class="hljs-string"><span class="hljs-string">'6. Advanced'</span></span></strong>: [<a href="#threading">Threading</a>, <a href="#operator">Operator</a>, <a href="#introspection">Introspection</a>, <a href="#metaprogramming">Metaprograming</a>, <a href="#eval">Eval</a>, <a href="#coroutines">Coroutine</a>],
<strong><span class="hljs-string"><span class="hljs-string">'7. Libraries'</span></span></strong>: [<a href="#progressbar">Progress_Bar</a>, <a href="#plot">Plot</a>, <a href="#table">Tables</a>, <a href="#curses">Curses</a>, <a href="#logging">Logging</a>, <a href="#scraping">Scraping</a>, <a href="#web">Web</a>, <a href="#profiling">Profile</a>],
<strong><span class="hljs-string"><span class="hljs-string">'8. Multimedia'</span></span></strong>: [<a href="#numpy">NumPy</a>, <a href="#image">Image</a>, <a href="#animation">Animation</a>, <a href="#audio">Audio</a>, <a href="#pygame">Pygame</a>, <a href="#pandas">Pandas</a>, <a href="#plotly">Plotly</a>, <a href="#pysimplegui">PySimpleGUI</a>]
<strong><span class="hljs-string"><span class="hljs-string">'6. Advanced'</span></span></strong>: [<a href="#threading">Threading</a>, <a href="#operator">Operator</a>, <a href="#matchstatement">Match_Stmt</a>, <a href="#introspection">Introspection</a>, <a href="#logging">Logging</a>, <a href="#coroutines">Coroutines</a>],
<strong><span class="hljs-string"><span class="hljs-string">'7. Libraries'</span></span></strong>: [<a href="#progressbar">Progress_Bar</a>, <a href="#plot">Plots</a>, <a href="#table">Tables</a>, <a href="#curses">Curses</a>, <a href="#pysimplegui">GUIs</a>, <a href="#scraping">Scraping</a>, <a href="#web">Web</a>, <a href="#profiling">Profiling</a>],
<strong><span class="hljs-string"><span class="hljs-string">'8. Multimedia'</span></span></strong>: [<a href="#numpy">NumPy</a>, <a href="#image">Image</a>, <a href="#animation">Animation</a>, <a href="#audio">Audio</a>, <a href="#synthesizer">Synthesizer</a>, <a href="#pygame">Pygame</a>, <a href="#pandas">Pandas</a>, <a href="#plotly">Plotly</a>]
} }
</code></pre></div></div> </code></pre></div></div>
@ -302,7 +302,6 @@ Point(x=<span class="hljs-number">1</span>, y=<span class="hljs-number">2</span>
</code></pre> </code></pre>
<pre><code class="python language-python hljs">&lt;bool&gt; = &lt;sub_str&gt; <span class="hljs-keyword">in</span> &lt;str&gt; <span class="hljs-comment"># Checks if string contains the substring.</span> <pre><code class="python language-python hljs">&lt;bool&gt; = &lt;sub_str&gt; <span class="hljs-keyword">in</span> &lt;str&gt; <span class="hljs-comment"># Checks if string contains the substring.</span>
&lt;bool&gt; = &lt;str&gt;.startswith(&lt;sub_str&gt;) <span class="hljs-comment"># Pass tuple of strings for multiple options.</span> &lt;bool&gt; = &lt;str&gt;.startswith(&lt;sub_str&gt;) <span class="hljs-comment"># Pass tuple of strings for multiple options.</span>
&lt;bool&gt; = &lt;str&gt;.endswith(&lt;sub_str&gt;) <span class="hljs-comment"># Pass tuple of strings for multiple options.</span>
&lt;int&gt; = &lt;str&gt;.find(&lt;sub_str&gt;) <span class="hljs-comment"># Returns start index of the first match or -1.</span> &lt;int&gt; = &lt;str&gt;.find(&lt;sub_str&gt;) <span class="hljs-comment"># Returns start index of the first match or -1.</span>
&lt;int&gt; = &lt;str&gt;.index(&lt;sub_str&gt;) <span class="hljs-comment"># Same, but raises ValueError if missing.</span> &lt;int&gt; = &lt;str&gt;.index(&lt;sub_str&gt;) <span class="hljs-comment"># Same, but raises ValueError if missing.</span>
</code></pre> </code></pre>
@ -315,6 +314,7 @@ Point(x=<span class="hljs-number">1</span>, y=<span class="hljs-number">2</span>
</code></pre> </code></pre>
<ul> <ul>
<li><strong>Use <code class="python hljs"><span class="hljs-string">'unicodedata.normalize("NFC", &lt;str&gt;)'</span></code> on strings that may contain characters like <code class="python hljs"><span class="hljs-string">'Ö'</span></code> before comparing them, because they can be stored as one or two characters.</strong></li> <li><strong>Use <code class="python hljs"><span class="hljs-string">'unicodedata.normalize("NFC", &lt;str&gt;)'</span></code> on strings that may contain characters like <code class="python hljs"><span class="hljs-string">'Ö'</span></code> before comparing them, because they can be stored as one or two characters.</strong></li>
<li><strong><code class="python hljs"><span class="hljs-string">'NFC'</span></code> converts such characters to a single character, while <code class="python hljs"><span class="hljs-string">'NFD'</span></code> converts them to two.</strong></li>
</ul> </ul>
<div><h3 id="propertymethods">Property Methods</h3><pre><code class="python language-python hljs">&lt;bool&gt; = &lt;str&gt;.isdecimal() <span class="hljs-comment"># Checks for [0-9].</span> <div><h3 id="propertymethods">Property Methods</h3><pre><code class="python language-python hljs">&lt;bool&gt; = &lt;str&gt;.isdecimal() <span class="hljs-comment"># Checks for [0-9].</span>
&lt;bool&gt; = &lt;str&gt;.isdigit() <span class="hljs-comment"># Checks for [²³¹] and isdecimal().</span> &lt;bool&gt; = &lt;str&gt;.isdigit() <span class="hljs-comment"># Checks for [²³¹] and isdecimal().</span>
@ -325,16 +325,15 @@ Point(x=<span class="hljs-number">1</span>, y=<span class="hljs-number">2</span>
</code></pre></div> </code></pre></div>
<div><h2 id="regex"><a href="#regex" name="regex">#</a>Regex</h2><p><strong>Functions for regular expression matching.</strong></p><pre><code class="python language-python hljs"><span class="hljs-keyword">import</span> re <div><h2 id="regex"><a href="#regex" name="regex">#</a>Regex</h2><p><strong>Functions for regular expression matching.</strong></p><pre><code class="python language-python hljs"><span class="hljs-keyword">import</span> re
</code></pre></div>
<pre><code class="python language-python hljs">&lt;str&gt; = re.sub(&lt;regex&gt;, new, text, count=<span class="hljs-number">0</span>) <span class="hljs-comment"># Substitutes all occurrences with 'new'.</span>
&lt;str&gt; = re.sub(&lt;regex&gt;, new, text, count=<span class="hljs-number">0</span>) <span class="hljs-comment"># Substitutes all occurrences with 'new'.</span>
&lt;list&gt; = re.findall(&lt;regex&gt;, text) <span class="hljs-comment"># Returns all occurrences as strings.</span> &lt;list&gt; = re.findall(&lt;regex&gt;, text) <span class="hljs-comment"># Returns all occurrences as strings.</span>
&lt;list&gt; = re.split(&lt;regex&gt;, text, maxsplit=<span class="hljs-number">0</span>) <span class="hljs-comment"># Add brackets around regex to include matches.</span> &lt;list&gt; = re.split(&lt;regex&gt;, text, maxsplit=<span class="hljs-number">0</span>) <span class="hljs-comment"># Add brackets around regex to include matches.</span>
&lt;Match&gt; = re.search(&lt;regex&gt;, text) <span class="hljs-comment"># First occurrence of the pattern or None.</span> &lt;Match&gt; = re.search(&lt;regex&gt;, text) <span class="hljs-comment"># First occurrence of the pattern or None.</span>
&lt;Match&gt; = re.match(&lt;regex&gt;, text) <span class="hljs-comment"># Searches only at the beginning of the text.</span> &lt;Match&gt; = re.match(&lt;regex&gt;, text) <span class="hljs-comment"># Searches only at the beginning of the text.</span>
&lt;iter&gt; = re.finditer(&lt;regex&gt;, text) <span class="hljs-comment"># Returns all occurrences as Match objects.</span> &lt;iter&gt; = re.finditer(&lt;regex&gt;, text) <span class="hljs-comment"># Returns all occurrences as Match objects.</span>
</code></pre>
</code></pre></div>
<ul> <ul>
<li><strong>Argument 'new' can be a function that accepts a Match object and returns a string.</strong></li> <li><strong>Argument 'new' can be a function that accepts a Match object and returns a string.</strong></li>
<li><strong>Argument <code class="python hljs"><span class="hljs-string">'flags=re.IGNORECASE'</span></code> can be used with all functions.</strong></li> <li><strong>Argument <code class="python hljs"><span class="hljs-string">'flags=re.IGNORECASE'</span></code> can be used with all functions.</strong></li>
@ -342,6 +341,7 @@ Point(x=<span class="hljs-number">1</span>, y=<span class="hljs-number">2</span>
<li><strong>Argument <code class="python hljs"><span class="hljs-string">'flags=re.DOTALL'</span></code> makes <code class="python hljs"><span class="hljs-string">'.'</span></code> also accept the <code class="python hljs"><span class="hljs-string">'\n'</span></code>.</strong></li> <li><strong>Argument <code class="python hljs"><span class="hljs-string">'flags=re.DOTALL'</span></code> makes <code class="python hljs"><span class="hljs-string">'.'</span></code> also accept the <code class="python hljs"><span class="hljs-string">'\n'</span></code>.</strong></li>
<li><strong>Use <code class="python hljs"><span class="hljs-string">r'\1'</span></code> or <code class="python hljs"><span class="hljs-string">'\\1'</span></code> for backreference (<code class="python hljs"><span class="hljs-string">'\1'</span></code> returns a character with octal code 1).</strong></li> <li><strong>Use <code class="python hljs"><span class="hljs-string">r'\1'</span></code> or <code class="python hljs"><span class="hljs-string">'\\1'</span></code> for backreference (<code class="python hljs"><span class="hljs-string">'\1'</span></code> returns a character with octal code 1).</strong></li>
<li><strong>Add <code class="python hljs"><span class="hljs-string">'?'</span></code> after <code class="python hljs"><span class="hljs-string">'*'</span></code> and <code class="python hljs"><span class="hljs-string">'+'</span></code> to make them non-greedy.</strong></li> <li><strong>Add <code class="python hljs"><span class="hljs-string">'?'</span></code> after <code class="python hljs"><span class="hljs-string">'*'</span></code> and <code class="python hljs"><span class="hljs-string">'+'</span></code> to make them non-greedy.</strong></li>
<li><strong><code class="python hljs"><span class="hljs-string">'re.compile(&lt;regex&gt;)'</span></code> returns a Pattern object with listed methods.</strong></li>
</ul> </ul>
<div><h3 id="matchobject">Match Object</h3><pre><code class="python language-python hljs">&lt;str&gt; = &lt;Match&gt;.group() <span class="hljs-comment"># Returns the whole match. Also group(0).</span> <div><h3 id="matchobject">Match Object</h3><pre><code class="python language-python hljs">&lt;str&gt; = &lt;Match&gt;.group() <span class="hljs-comment"># Returns the whole match. Also group(0).</span>
&lt;str&gt; = &lt;Match&gt;.group(<span class="hljs-number">1</span>) <span class="hljs-comment"># Returns the part inside first brackets.</span> &lt;str&gt; = &lt;Match&gt;.group(<span class="hljs-number">1</span>) <span class="hljs-comment"># Returns the part inside first brackets.</span>
@ -511,7 +511,7 @@ Point(x=<span class="hljs-number">1</span>, y=<span class="hljs-number">2</span>
(<span class="hljs-string">'b'</span>, <span class="hljs-string">'a'</span>), (<span class="hljs-string">'b'</span>, <span class="hljs-string">'c'</span>), <span class="hljs-comment"># b x . x</span> (<span class="hljs-string">'b'</span>, <span class="hljs-string">'a'</span>), (<span class="hljs-string">'b'</span>, <span class="hljs-string">'c'</span>), <span class="hljs-comment"># b x . x</span>
(<span class="hljs-string">'c'</span>, <span class="hljs-string">'a'</span>), (<span class="hljs-string">'c'</span>, <span class="hljs-string">'b'</span>)] <span class="hljs-comment"># c x x .</span> (<span class="hljs-string">'c'</span>, <span class="hljs-string">'a'</span>), (<span class="hljs-string">'c'</span>, <span class="hljs-string">'b'</span>)] <span class="hljs-comment"># c x x .</span>
</code></pre> </code></pre>
<div><h2 id="datetime"><a href="#datetime" name="datetime">#</a>Datetime</h2><p><strong>Provides 'date', 'time', 'datetime' and 'timedelta' classes. All are immutable and hashable.</strong></p><pre><code class="python language-python hljs"><span class="hljs-comment"># pip3 install python-dateutil</span>
<div><h2 id="datetime"><a href="#datetime" name="datetime">#</a>Datetime</h2><p><strong>Provides 'date', 'time', 'datetime' and 'timedelta' classes. All are immutable and hashable.</strong></p><pre><code class="python language-python hljs"><span class="hljs-comment"># $ pip3 install python-dateutil</span>
<span class="hljs-keyword">from</span> datetime <span class="hljs-keyword">import</span> date, time, datetime, timedelta, timezone <span class="hljs-keyword">from</span> datetime <span class="hljs-keyword">import</span> date, time, datetime, timedelta, timezone
<span class="hljs-keyword">from</span> dateutil.tz <span class="hljs-keyword">import</span> tzlocal, gettz <span class="hljs-keyword">from</span> dateutil.tz <span class="hljs-keyword">import</span> tzlocal, gettz
</code></pre></div> </code></pre></div>
@ -635,7 +635,7 @@ func(*args, **kwargs)
<div><h3 id="otheruses">Other Uses</h3><pre><code class="python language-python hljs">&lt;list&gt; = [*&lt;coll.&gt; [, ...]] <span class="hljs-comment"># Or: list(&lt;collection&gt;) [+ ...]</span> <div><h3 id="otheruses">Other Uses</h3><pre><code class="python language-python hljs">&lt;list&gt; = [*&lt;coll.&gt; [, ...]] <span class="hljs-comment"># Or: list(&lt;collection&gt;) [+ ...]</span>
&lt;tuple&gt; = (*&lt;coll.&gt;, [...]) <span class="hljs-comment"># Or: tuple(&lt;collection&gt;) [+ ...]</span> &lt;tuple&gt; = (*&lt;coll.&gt;, [...]) <span class="hljs-comment"># Or: tuple(&lt;collection&gt;) [+ ...]</span>
&lt;set&gt; = {*&lt;coll.&gt; [, ...]} <span class="hljs-comment"># Or: set(&lt;collection&gt;) [| ...]</span> &lt;set&gt; = {*&lt;coll.&gt; [, ...]} <span class="hljs-comment"># Or: set(&lt;collection&gt;) [| ...]</span>
&lt;dict&gt; = {**&lt;dict&gt; [, ...]} <span class="hljs-comment"># Or: dict(**&lt;dict&gt; [, ...])</span>
&lt;dict&gt; = {**&lt;dict&gt; [, ...]} <span class="hljs-comment"># Or: dict(&lt;dict&gt;) [| ...] (since 3.9)</span>
</code></pre></div> </code></pre></div>
<pre><code class="python language-python hljs">head, *body, tail = &lt;coll.&gt; <span class="hljs-comment"># Head or tail can be omitted.</span> <pre><code class="python language-python hljs">head, *body, tail = &lt;coll.&gt; <span class="hljs-comment"># Head or tail can be omitted.</span>
@ -1799,93 +1799,100 @@ first_element = op.methodcaller(<span class="hljs-string">'pop'</span>, <span
<li><strong>Bitwise operators require objects to have or(), xor(), and(), lshift(), rshift() and invert() special methods, unlike logical operators that work on all types of objects.</strong></li> <li><strong>Bitwise operators require objects to have or(), xor(), and(), lshift(), rshift() and invert() special methods, unlike logical operators that work on all types of objects.</strong></li>
<li><strong>Also: <code class="python hljs"><span class="hljs-string">'&lt;bool&gt; = &lt;bool&gt; &amp;|^ &lt;bool&gt;'</span></code> and <code class="python hljs"><span class="hljs-string">'&lt;int&gt; = &lt;bool&gt; &amp;|^ &lt;int&gt;'</span></code>.</strong></li> <li><strong>Also: <code class="python hljs"><span class="hljs-string">'&lt;bool&gt; = &lt;bool&gt; &amp;|^ &lt;bool&gt;'</span></code> and <code class="python hljs"><span class="hljs-string">'&lt;int&gt; = &lt;bool&gt; &amp;|^ &lt;int&gt;'</span></code>.</strong></li>
</ul> </ul>
<div><h2 id="matchstatement"><a href="#matchstatement" name="matchstatement">#</a>Match Statement</h2><p><strong>Executes the first block with matching pattern. Added in Python 3.10.</strong></p><pre><code class="python language-python hljs"><span class="hljs-keyword">match</span> &lt;object/expression&gt;:
<span class="hljs-keyword">case</span> &lt;pattern&gt; [<span class="hljs-keyword">if</span> &lt;condition&gt;]:
&lt;code&gt;
...
</code></pre></div>
<div><h3 id="patterns">Patterns</h3><pre><code class="python language-python hljs">&lt;value_pattern&gt; = <span class="hljs-number">1</span>/<span class="hljs-string">'abc'</span>/<span class="hljs-keyword">True</span>/<span class="hljs-keyword">None</span>/math.pi <span class="hljs-comment"># Matches the literal or a dotted name.</span>
&lt;class_pattern&gt; = &lt;type&gt;() <span class="hljs-comment"># Matches any object of that type.</span>
&lt;capture_patt&gt; = &lt;name&gt; <span class="hljs-comment"># Matches any object and binds it to name.</span>
&lt;or_pattern&gt; = &lt;pattern&gt; | &lt;pattern&gt; [| ...] <span class="hljs-comment"># Matches any of the patterns.</span>
&lt;as_pattern&gt; = &lt;pattern&gt; <span class="hljs-keyword">as</span> &lt;name&gt; <span class="hljs-comment"># Binds the match to the name.</span>
&lt;sequence_patt&gt; = [&lt;pattern&gt;, ...] <span class="hljs-comment"># Matches sequence with matching items.</span>
&lt;mapping_patt&gt; = {&lt;value_patt&gt;: &lt;pattern&gt;, ...} <span class="hljs-comment"># Matches dictionary with matching items.</span>
&lt;class_pattern&gt; = &lt;type&gt;(&lt;attr_name&gt;=&lt;patt&gt;, ...) <span class="hljs-comment"># Matches object with matching attributes.</span>
</code></pre></div>
<ul>
<li><strong>Sequence pattern can also be written as a tuple.</strong></li>
<li><strong>Use <code class="python hljs"><span class="hljs-string">'*&lt;name&gt;'</span></code> and <code class="python hljs"><span class="hljs-string">'**&lt;name&gt;'</span></code> in sequence/mapping patterns to bind remaining items.</strong></li>
<li><strong>Patterns can be surrounded with brackets to override precedence (<code class="python hljs"><span class="hljs-string">'|'</span></code> &gt; <code class="python hljs"><span class="hljs-string">'as'</span></code> &gt; <code class="python hljs"><span class="hljs-string">','</span></code>).</strong></li>
<li><strong>Built-in types allow a single positional pattern that is matched against the entire object.</strong></li>
<li><strong>All names that are bound in the matching case, as well as variables initialized in its block, are visible after the match statement.</strong></li>
</ul>
<div><h3 id="example-2">Example</h3><pre><code class="python language-python hljs"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">from</span> pathlib <span class="hljs-keyword">import</span> Path
<span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">match</span> Path(<span class="hljs-string">'/home/gto/python-cheatsheet/README.md'</span>):
<span class="hljs-meta">... </span> <span class="hljs-keyword">case</span> Path(
<span class="hljs-meta">... </span> parts=[<span class="hljs-string">'/'</span>, <span class="hljs-string">'home'</span>, user, *_],
<span class="hljs-meta">... </span> stem=stem,
<span class="hljs-meta">... </span> suffix=(<span class="hljs-string">'.md'</span> | <span class="hljs-string">'.txt'</span>) <span class="hljs-keyword">as</span> suffix
<span class="hljs-meta">... </span> ) <span class="hljs-keyword">if</span> stem.lower() == <span class="hljs-string">'readme'</span>:
<span class="hljs-meta">... </span> print(<span class="hljs-string">f'<span class="hljs-subst">{stem}</span><span class="hljs-subst">{suffix}</span> is a readme file that belongs to user <span class="hljs-subst">{user}</span>.'</span>)
<span class="hljs-string">'README.md is a readme file that belongs to user gto.'</span>
</code></pre></div>
<div><h2 id="introspection"><a href="#introspection" name="introspection">#</a>Introspection</h2><pre><code class="python language-python hljs">&lt;list&gt; = dir() <span class="hljs-comment"># Names of local variables, functions, classes, etc.</span> <div><h2 id="introspection"><a href="#introspection" name="introspection">#</a>Introspection</h2><pre><code class="python language-python hljs">&lt;list&gt; = dir() <span class="hljs-comment"># Names of local variables, functions, classes, etc.</span>
&lt;dict&gt; = vars() <span class="hljs-comment"># Dict of local variables, etc. Also locals().</span> &lt;dict&gt; = vars() <span class="hljs-comment"># Dict of local variables, etc. Also locals().</span>
&lt;dict&gt; = globals() <span class="hljs-comment"># Dict of global vars, etc. (incl. '__builtins__').</span> &lt;dict&gt; = globals() <span class="hljs-comment"># Dict of global vars, etc. (incl. '__builtins__').</span>
</code></pre></div> </code></pre></div>
<div><h3 id="attributes">Attributes</h3><pre><code class="python language-python hljs">&lt;list&gt; = dir(&lt;object&gt;) <span class="hljs-comment"># Names of object's attributes (including methods).</span>
<pre><code class="python language-python hljs">&lt;list&gt; = dir(&lt;object&gt;) <span class="hljs-comment"># Names of object's attributes (including methods).</span>
&lt;dict&gt; = vars(&lt;object&gt;) <span class="hljs-comment"># Dict of writable attributes. Also &lt;obj&gt;.__dict__.</span> &lt;dict&gt; = vars(&lt;object&gt;) <span class="hljs-comment"># Dict of writable attributes. Also &lt;obj&gt;.__dict__.</span>
&lt;bool&gt; = hasattr(&lt;object&gt;, <span class="hljs-string">'&lt;attr_name&gt;'</span>) <span class="hljs-comment"># Checks if getattr() raises an AttributeError.</span> &lt;bool&gt; = hasattr(&lt;object&gt;, <span class="hljs-string">'&lt;attr_name&gt;'</span>) <span class="hljs-comment"># Checks if getattr() raises an AttributeError.</span>
value = getattr(&lt;object&gt;, <span class="hljs-string">'&lt;attr_name&gt;'</span>) <span class="hljs-comment"># Raises AttributeError if attribute is missing.</span> value = getattr(&lt;object&gt;, <span class="hljs-string">'&lt;attr_name&gt;'</span>) <span class="hljs-comment"># Raises AttributeError if attribute is missing.</span>
setattr(&lt;object&gt;, <span class="hljs-string">'&lt;attr_name&gt;'</span>, value) <span class="hljs-comment"># Only works on objects with '__dict__' attribute.</span> setattr(&lt;object&gt;, <span class="hljs-string">'&lt;attr_name&gt;'</span>, value) <span class="hljs-comment"># Only works on objects with '__dict__' attribute.</span>
delattr(&lt;object&gt;, <span class="hljs-string">'&lt;attr_name&gt;'</span>) <span class="hljs-comment"># Same. Also `del &lt;object&gt;.&lt;attr_name&gt;`.</span> delattr(&lt;object&gt;, <span class="hljs-string">'&lt;attr_name&gt;'</span>) <span class="hljs-comment"># Same. Also `del &lt;object&gt;.&lt;attr_name&gt;`.</span>
</code></pre></div>
<div><h3 id="parameters-1">Parameters</h3><pre><code class="python language-python hljs">&lt;Sig&gt; = inspect.signature(&lt;function&gt;) <span class="hljs-comment"># Function's Signature object.</span>
</code></pre>
<pre><code class="python language-python hljs">&lt;Sig&gt; = inspect.signature(&lt;function&gt;) <span class="hljs-comment"># Function's Signature object.</span>
&lt;dict&gt; = &lt;Sig&gt;.parameters <span class="hljs-comment"># Dict of Parameter objects.</span> &lt;dict&gt; = &lt;Sig&gt;.parameters <span class="hljs-comment"># Dict of Parameter objects.</span>
&lt;memb&gt; = &lt;Param&gt;.kind <span class="hljs-comment"># Member of ParameterKind enum.</span> &lt;memb&gt; = &lt;Param&gt;.kind <span class="hljs-comment"># Member of ParameterKind enum.</span>
&lt;obj&gt; = &lt;Param&gt;.default <span class="hljs-comment"># Default value or Parameter.empty.</span> &lt;obj&gt; = &lt;Param&gt;.default <span class="hljs-comment"># Default value or Parameter.empty.</span>
&lt;type&gt; = &lt;Param&gt;.annotation <span class="hljs-comment"># Type or Parameter.empty.</span> &lt;type&gt; = &lt;Param&gt;.annotation <span class="hljs-comment"># Type or Parameter.empty.</span>
</code></pre></div>
<div><h2 id="metaprogramming"><a href="#metaprogramming" name="metaprogramming">#</a>Metaprogramming</h2><p><strong>Code that generates code.</strong></p><div><h3 id="type-1">Type</h3><p><strong>Type is the root class. If only passed an object it returns its type (class). Otherwise it creates a new class.</strong></p><pre><code class="python language-python hljs">&lt;class&gt; = type(<span class="hljs-string">'&lt;class_name&gt;'</span>, &lt;tuple_of_parents&gt;, &lt;dict_of_class_attributes&gt;)</code></pre></div></div>
<pre><code class="python language-python hljs"><span class="hljs-meta">&gt;&gt;&gt; </span>Z = type(<span class="hljs-string">'Z'</span>, (), {<span class="hljs-string">'a'</span>: <span class="hljs-string">'abcde'</span>, <span class="hljs-string">'b'</span>: <span class="hljs-number">12345</span>})
<span class="hljs-meta">&gt;&gt;&gt; </span>z = Z()
</code></pre>
<div><h3 id="metaclass">Meta Class</h3><p><strong>A class that creates classes.</strong></p><pre><code class="python language-python hljs"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">my_meta_class</span><span class="hljs-params">(name, parents, attrs)</span>:</span>
attrs[<span class="hljs-string">'a'</span>] = <span class="hljs-string">'abcde'</span>
<span class="hljs-keyword">return</span> type(name, parents, attrs)
</code></pre></div>
<div><h4 id="or-2">Or:</h4><pre><code class="python language-python hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyMetaClass</span><span class="hljs-params">(type)</span>:</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__new__</span><span class="hljs-params">(cls, name, parents, attrs)</span>:</span>
attrs[<span class="hljs-string">'a'</span>] = <span class="hljs-string">'abcde'</span>
<span class="hljs-keyword">return</span> type.__new__(cls, name, parents, attrs)
</code></pre></div>
<ul>
<li><strong>New() is a class method that gets called before init(). If it returns an instance of its class, then that instance gets passed to init() as a 'self' argument.</strong></li>
<li><strong>It receives the same arguments as init(), except for the first one that specifies the desired type of the returned instance (MyMetaClass in our case).</strong></li>
<li><strong>Like in our case, new() can also be called directly, usually from a new() method of a child class (</strong><code class="python hljs"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__new__</span><span class="hljs-params">(cls)</span>:</span> <span class="hljs-keyword">return</span> super().__new__(cls)</code><strong>).</strong></li>
<li><strong>The only difference between the examples above is that my_meta_class() returns a class of type type, while MyMetaClass() returns a class of type MyMetaClass.</strong></li>
</ul>
<div><h3 id="metaclassattribute">Metaclass Attribute</h3><p><strong>Right before a class is created it checks if it has the 'metaclass' attribute defined. If not, it recursively checks if any of its parents has it defined and eventually comes to type().</strong></p><pre><code class="python language-python hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyClass</span><span class="hljs-params">(metaclass=MyMetaClass)</span>:</span>
b = <span class="hljs-number">12345</span>
</code></pre></div>
<pre><code class="python language-python hljs"><span class="hljs-meta">&gt;&gt;&gt; </span>MyClass.a, MyClass.b
(<span class="hljs-string">'abcde'</span>, <span class="hljs-number">12345</span>)
</code></pre> </code></pre>
<div><h3 id="typediagram">Type Diagram</h3><pre><code class="python language-python hljs">type(MyClass) == MyMetaClass <span class="hljs-comment"># MyClass is an instance of MyMetaClass.</span>
type(MyMetaClass) == type <span class="hljs-comment"># MyMetaClass is an instance of type.</span>
<div><h2 id="logging"><a href="#logging" name="logging">#</a>Logging</h2><pre><code class="python language-python hljs"><span class="hljs-keyword">import</span> logging
</code></pre></div> </code></pre></div>
<pre><code class="text language-text">┏━━━━━━━━━━━━━┯━━━━━━━━━━━━━┓
┃ Classes │ Metaclasses ┃
┠─────────────┼─────────────┨
┃ MyClass ←──╴MyMetaClass ┃
┃ │ ↑ ┃
┃ object ←─────╴type ←╮ ┃
┃ │ │ ╰──╯ ┃
┃ str ←─────────╯ ┃
┗━━━━━━━━━━━━━┷━━━━━━━━━━━━━┛
<pre><code class="python language-python hljs">logging.basicConfig(filename=&lt;path&gt;, level=<span class="hljs-string">'DEBUG'</span>) <span class="hljs-comment"># Configures the root logger (see Setup).</span>
logging.debug/info/warning/error/critical(&lt;str&gt;) <span class="hljs-comment"># Logs to the root logger.</span>
&lt;Logger&gt; = logging.getLogger(__name__) <span class="hljs-comment"># Logger named after the module.</span>
&lt;Logger&gt;.&lt;level&gt;(&lt;str&gt;) <span class="hljs-comment"># Logs to the logger.</span>
&lt;Logger&gt;.exception(&lt;str&gt;) <span class="hljs-comment"># Calls error() with caught exception.</span>
</code></pre> </code></pre>
<div><h3 id="inheritancediagram">Inheritance Diagram</h3><pre><code class="python language-python hljs">MyClass.__base__ == object <span class="hljs-comment"># MyClass is a subclass of object.</span>
MyMetaClass.__base__ == type <span class="hljs-comment"># MyMetaClass is a subclass of type.</span>
<div><h3 id="setup">Setup</h3><pre><code class="python language-python hljs">logging.basicConfig(
filename=<span class="hljs-keyword">None</span>, <span class="hljs-comment"># Logs to console (stderr) by default.</span>
format=<span class="hljs-string">'%(levelname)s:%(name)s:%(message)s'</span>, <span class="hljs-comment"># Add '%(asctime)s' for local datetime.</span>
level=logging.WARNING, <span class="hljs-comment"># Drops messages with lower priority.</span>
handlers=[logging.StreamHandler(sys.stderr)] <span class="hljs-comment"># Uses FileHandler if filename is set.</span>
)
</code></pre></div> </code></pre></div>
<pre><code class="text language-text">┏━━━━━━━━━━━━━┯━━━━━━━━━━━━━┓
┃ Classes │ Metaclasses ┃
┠─────────────┼─────────────┨
┃ MyClass │ MyMetaClass ┃
┃ ↑ │ ↑ ┃
┃ object╶─────→ type ┃
┃ ↓ │ ┃
┃ str │ ┃
┗━━━━━━━━━━━━━┷━━━━━━━━━━━━━┛
<pre><code class="python language-python hljs">&lt;Formatter&gt; = logging.Formatter(<span class="hljs-string">'&lt;format&gt;'</span>) <span class="hljs-comment"># Creates a Formatter.</span>
&lt;Handler&gt; = logging.FileHandler(&lt;path&gt;, mode=<span class="hljs-string">'a'</span>) <span class="hljs-comment"># Creates a Handler. Also `encoding=None`.</span>
&lt;Handler&gt;.setFormatter(&lt;Formatter&gt;) <span class="hljs-comment"># Adds Formatter to the Handler.</span>
&lt;Handler&gt;.setLevel(&lt;int/str&gt;) <span class="hljs-comment"># Processes all messages by default.</span>
&lt;Logger&gt;.addHandler(&lt;Handler&gt;) <span class="hljs-comment"># Adds Handler to the Logger.</span>
&lt;Logger&gt;.setLevel(&lt;int/str&gt;) <span class="hljs-comment"># What is sent to its/ancestor's handlers.</span>
</code></pre> </code></pre>
<div><h2 id="eval"><a href="#eval" name="eval">#</a>Eval</h2><pre><code class="python language-python hljs"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">from</span> ast <span class="hljs-keyword">import</span> literal_eval
<span class="hljs-meta">&gt;&gt;&gt; </span>literal_eval(<span class="hljs-string">'[1, 2, 3]'</span>)
[<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>literal_eval(<span class="hljs-string">'1 + 2'</span>)
ValueError: malformed node or string
<ul>
<li><strong>Parent logger can be specified by naming the child logger <code class="python hljs"><span class="hljs-string">'&lt;parent&gt;.&lt;name&gt;'</span></code>.</strong></li>
<li><strong>If logger doesn't have a set level it inherits it from the first ancestor that does.</strong></li>
<li><strong>Formatter also accepts: pathname, filename, funcName, lineno, thread and process.</strong></li>
<li><strong>A <code class="python hljs"><span class="hljs-string">'handlers.RotatingFileHandler'</span></code> creates and deletes log files based on 'maxBytes' and 'backupCount' arguments.</strong></li>
</ul>
<div><h4 id="createsaloggerthatwritesallmessagestofileandsendsthemtotherootshandlerthatprintswarningsorhigher">Creates a logger that writes all messages to file and sends them to the root's handler that prints warnings or higher:</h4><pre><code class="python language-python hljs"><span class="hljs-meta">&gt;&gt;&gt; </span>logger = logging.getLogger(<span class="hljs-string">'my_module'</span>)
<span class="hljs-meta">&gt;&gt;&gt; </span>handler = logging.FileHandler(<span class="hljs-string">'test.log'</span>, encoding=<span class="hljs-string">'utf-8'</span>)
<span class="hljs-meta">&gt;&gt;&gt; </span>formatter = logging.Formatter(<span class="hljs-string">'%(asctime)s %(levelname)s:%(name)s:%(message)s'</span>)
<span class="hljs-meta">&gt;&gt;&gt; </span>handler.setFormatter(formatter)
<span class="hljs-meta">&gt;&gt;&gt; </span>logger.addHandler(handler)
<span class="hljs-meta">&gt;&gt;&gt; </span>logging.basicConfig(level=<span class="hljs-string">'DEBUG'</span>)
<span class="hljs-meta">&gt;&gt;&gt; </span>logging.root.handlers[<span class="hljs-number">0</span>].setLevel(<span class="hljs-string">'WARNING'</span>)
<span class="hljs-meta">&gt;&gt;&gt; </span>logger.critical(<span class="hljs-string">'Running out of disk space.'</span>)
CRITICAL:my_module:Running out of disk space.
<span class="hljs-meta">&gt;&gt;&gt; </span>print(open(<span class="hljs-string">'test.log'</span>).read())
2023-02-07 23:21:01,430 CRITICAL:my_module:Running out of disk space.
</code></pre></div> </code></pre></div>
<div><h2 id="coroutines"><a href="#coroutines" name="coroutines">#</a>Coroutines</h2><ul> <div><h2 id="coroutines"><a href="#coroutines" name="coroutines">#</a>Coroutines</h2><ul>
@ -1894,7 +1901,7 @@ ValueError: malformed node or string
<li><strong><code class="python hljs"><span class="hljs-string">'asyncio.run(&lt;coroutine&gt;)'</span></code> is the main entry point for asynchronous programs.</strong></li> <li><strong><code class="python hljs"><span class="hljs-string">'asyncio.run(&lt;coroutine&gt;)'</span></code> is the main entry point for asynchronous programs.</strong></li>
<li><strong>Functions wait(), gather() and as_completed() start multiple coroutines at the same time.</strong></li> <li><strong>Functions wait(), gather() and as_completed() start multiple coroutines at the same time.</strong></li>
<li><strong>Asyncio module also provides its own <a href="#queue">Queue</a>, <a href="#semaphoreeventbarrier">Event</a>, <a href="#lock">Lock</a> and <a href="#semaphoreeventbarrier">Semaphore</a> classes.</strong></li> <li><strong>Asyncio module also provides its own <a href="#queue">Queue</a>, <a href="#semaphoreeventbarrier">Event</a>, <a href="#lock">Lock</a> and <a href="#semaphoreeventbarrier">Semaphore</a> classes.</strong></li>
</ul><div><h4 id="runsaterminalgamewhereyoucontrolanasteriskthatmustavoidnumbers">Runs a terminal game where you control an asterisk that must avoid numbers:</h4><pre><code class="python language-python hljs"><span class="hljs-keyword">import</span> asyncio, collections, curses, curses.textpad, enum, random
</ul><div><h4 id="runsaterminalgamewhereyoucontrolanasteriskthatmustavoidnumbers">Runs a terminal game where you control an asterisk that must avoid numbers:</h4><pre><code class="python language-python hljs"><span class="hljs-keyword">import</span> asyncio, collections, curses, curses.textpad, enum, random, time
P = collections.namedtuple(<span class="hljs-string">'P'</span>, <span class="hljs-string">'x y'</span>) <span class="hljs-comment"># Position</span> P = collections.namedtuple(<span class="hljs-string">'P'</span>, <span class="hljs-string">'x y'</span>) <span class="hljs-comment"># Position</span>
D = enum.Enum(<span class="hljs-string">'D'</span>, <span class="hljs-string">'n e s w'</span>) <span class="hljs-comment"># Direction</span> D = enum.Enum(<span class="hljs-string">'D'</span>, <span class="hljs-string">'n e s w'</span>) <span class="hljs-comment"># Direction</span>
@ -1922,7 +1929,8 @@ W, H = <span class="hljs-number">15</span>, <span class="hljs-number">7</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">human_controller</span><span class="hljs-params">(screen, moves)</span>:</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">human_controller</span><span class="hljs-params">(screen, moves)</span>:</span>
<span class="hljs-keyword">while</span> <span class="hljs-keyword">True</span>: <span class="hljs-keyword">while</span> <span class="hljs-keyword">True</span>:
key_mappings = {<span class="hljs-number">258</span>: D.s, <span class="hljs-number">259</span>: D.n, <span class="hljs-number">260</span>: D.w, <span class="hljs-number">261</span>: D.e} key_mappings = {<span class="hljs-number">258</span>: D.s, <span class="hljs-number">259</span>: D.n, <span class="hljs-number">260</span>: D.w, <span class="hljs-number">261</span>: D.e}
<span class="hljs-keyword">if</span> d := key_mappings.get(screen.getch()):
ch = screen.getch()
<span class="hljs-keyword">if</span> d := key_mappings.get(ch):
moves.put_nowait((<span class="hljs-string">'*'</span>, d)) moves.put_nowait((<span class="hljs-string">'*'</span>, d))
<span class="hljs-keyword">await</span> asyncio.sleep(<span class="hljs-number">0.005</span>) <span class="hljs-keyword">await</span> asyncio.sleep(<span class="hljs-number">0.005</span>)
@ -1931,7 +1939,8 @@ W, H = <span class="hljs-number">15</span>, <span class="hljs-number">7</span>
id_, d = <span class="hljs-keyword">await</span> moves.get() id_, d = <span class="hljs-keyword">await</span> moves.get()
x, y = state[id_] x, y = state[id_]
deltas = {D.n: P(<span class="hljs-number">0</span>, <span class="hljs-number">-1</span>), D.e: P(<span class="hljs-number">1</span>, <span class="hljs-number">0</span>), D.s: P(<span class="hljs-number">0</span>, <span class="hljs-number">1</span>), D.w: P(<span class="hljs-number">-1</span>, <span class="hljs-number">0</span>)} deltas = {D.n: P(<span class="hljs-number">0</span>, <span class="hljs-number">-1</span>), D.e: P(<span class="hljs-number">1</span>, <span class="hljs-number">0</span>), D.s: P(<span class="hljs-number">0</span>, <span class="hljs-number">1</span>), D.w: P(<span class="hljs-number">-1</span>, <span class="hljs-number">0</span>)}
state[id_] = P((x + deltas[d].x) % W, (y + deltas[d].y) % H)
dx, dy = deltas[d]
state[id_] = P((x + dx) % W, (y + dy) % H)
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">view</span><span class="hljs-params">(state, screen)</span>:</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">view</span><span class="hljs-params">(state, screen)</span>:</span>
offset = P(curses.COLS//<span class="hljs-number">2</span> - W//<span class="hljs-number">2</span>, curses.LINES//<span class="hljs-number">2</span> - H//<span class="hljs-number">2</span>) offset = P(curses.COLS//<span class="hljs-number">2</span> - W//<span class="hljs-number">2</span>, curses.LINES//<span class="hljs-number">2</span> - H//<span class="hljs-number">2</span>)
@ -1939,13 +1948,18 @@ W, H = <span class="hljs-number">15</span>, <span class="hljs-number">7</span>
screen.erase() screen.erase()
curses.textpad.rectangle(screen, offset.y-<span class="hljs-number">1</span>, offset.x-<span class="hljs-number">1</span>, offset.y+H, offset.x+W) curses.textpad.rectangle(screen, offset.y-<span class="hljs-number">1</span>, offset.x-<span class="hljs-number">1</span>, offset.y+H, offset.x+W)
<span class="hljs-keyword">for</span> id_, p <span class="hljs-keyword">in</span> state.items(): <span class="hljs-keyword">for</span> id_, p <span class="hljs-keyword">in</span> state.items():
screen.addstr(offset.y + (p.y - state[<span class="hljs-string">'*'</span>].y + H//<span class="hljs-number">2</span>) % H,
offset.x + (p.x - state[<span class="hljs-string">'*'</span>].x + W//<span class="hljs-number">2</span>) % W, str(id_))
screen.addstr(
offset.y + (p.y - state[<span class="hljs-string">'*'</span>].y + H//<span class="hljs-number">2</span>) % H,
offset.x + (p.x - state[<span class="hljs-string">'*'</span>].x + W//<span class="hljs-number">2</span>) % W,
str(id_)
)
screen.refresh() screen.refresh()
<span class="hljs-keyword">await</span> asyncio.sleep(<span class="hljs-number">0.005</span>) <span class="hljs-keyword">await</span> asyncio.sleep(<span class="hljs-number">0.005</span>)
<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>: <span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
start_time = time.perf_counter()
curses.wrapper(main) curses.wrapper(main)
print(<span class="hljs-string">f'You survived <span class="hljs-subst">{time.perf_counter() - start_time:<span class="hljs-number">.2</span>f}</span> seconds.'</span>)
</code></pre></div></div> </code></pre></div></div>
@ -1978,7 +1992,7 @@ print(table)
</code></pre></div></div> </code></pre></div></div>
<div><h2 id="curses"><a href="#curses" name="curses">#</a>Curses</h2><div><h4 id="runsabasicfileexplorerintheconsole">Runs a basic file explorer in the console:</h4><pre><code class="python language-python hljs"><span class="hljs-comment"># pip3 install windows-curses</span>
<div><h2 id="curses"><a href="#curses" name="curses">#</a>Curses</h2><div><h4 id="runsabasicfileexplorerintheconsole">Runs a basic file explorer in the console:</h4><pre><code class="python language-python hljs"><span class="hljs-comment"># $ pip3 install windows-curses</span>
<span class="hljs-keyword">import</span> curses, os <span class="hljs-keyword">import</span> curses, os
<span class="hljs-keyword">from</span> curses <span class="hljs-keyword">import</span> A_REVERSE, KEY_DOWN, KEY_UP, KEY_LEFT, KEY_RIGHT, KEY_ENTER <span class="hljs-keyword">from</span> curses <span class="hljs-keyword">import</span> A_REVERSE, KEY_DOWN, KEY_UP, KEY_LEFT, KEY_RIGHT, KEY_ENTER
@ -2005,68 +2019,68 @@ print(table)
</code></pre></div></div> </code></pre></div></div>
<div><h2 id="logging"><a href="#logging" name="logging">#</a>Logging</h2><pre><code class="python language-python hljs"><span class="hljs-keyword">import</span> logging
</code></pre></div>
<div><h2 id="pysimplegui"><a href="#pysimplegui" name="pysimplegui">#</a>PySimpleGUI</h2><div><h4 id="aweightconverterguiapplication">A weight converter GUI application:</h4><pre><code class="python language-python hljs"><span class="hljs-comment"># $ pip3 install PySimpleGUI</span>
<span class="hljs-keyword">import</span> PySimpleGUI <span class="hljs-keyword">as</span> sg
<pre><code class="python language-python hljs">logging.basicConfig(filename=&lt;path&gt;, level=<span class="hljs-string">'DEBUG'</span>) <span class="hljs-comment"># Configures the root logger (see Setup).</span>
logging.debug/info/warning/error/critical(&lt;str&gt;) <span class="hljs-comment"># Logs to the root logger.</span>
&lt;Logger&gt; = logging.getLogger(__name__) <span class="hljs-comment"># Logger named after the module.</span>
&lt;Logger&gt;.&lt;level&gt;(&lt;str&gt;) <span class="hljs-comment"># Logs to the logger.</span>
&lt;Logger&gt;.exception(&lt;str&gt;) <span class="hljs-comment"># Calls error() with caught exception.</span>
</code></pre>
<div><h3 id="setup">Setup</h3><pre><code class="python language-python hljs">logging.basicConfig(
filename=<span class="hljs-keyword">None</span>, <span class="hljs-comment"># Logs to console (stderr) by default.</span>
format=<span class="hljs-string">'%(levelname)s:%(name)s:%(message)s'</span>, <span class="hljs-comment"># Add '%(asctime)s' for local datetime.</span>
level=logging.WARNING, <span class="hljs-comment"># Drops messages with lower priority.</span>
handlers=[logging.StreamHandler(sys.stderr)] <span class="hljs-comment"># Uses FileHandler if filename is set.</span>
)
</code></pre></div>
text_box = sg.Input(default_text=<span class="hljs-string">'100'</span>, enable_events=<span class="hljs-keyword">True</span>, key=<span class="hljs-string">'-VALUE-'</span>)
dropdown = sg.InputCombo([<span class="hljs-string">'g'</span>, <span class="hljs-string">'kg'</span>, <span class="hljs-string">'t'</span>], <span class="hljs-string">'kg'</span>, readonly=<span class="hljs-keyword">True</span>, enable_events=<span class="hljs-keyword">True</span>, k=<span class="hljs-string">'-UNIT-'</span>)
label = sg.Text(<span class="hljs-string">'100 kg is 220.462 lbs.'</span>, key=<span class="hljs-string">'-OUTPUT-'</span>)
button = sg.Button(<span class="hljs-string">'Close'</span>)
window = sg.Window(<span class="hljs-string">'Weight Converter'</span>, [[text_box, dropdown], [label], [button]])
<span class="hljs-keyword">while</span> <span class="hljs-keyword">True</span>:
event, values = window.read()
<span class="hljs-keyword">if</span> event <span class="hljs-keyword">in</span> [sg.WIN_CLOSED, <span class="hljs-string">'Close'</span>]:
<span class="hljs-keyword">break</span>
<span class="hljs-keyword">try</span>:
value = float(values[<span class="hljs-string">'-VALUE-'</span>])
<span class="hljs-keyword">except</span> ValueError:
<span class="hljs-keyword">continue</span>
unit = values[<span class="hljs-string">'-UNIT-'</span>]
units = {<span class="hljs-string">'g'</span>: <span class="hljs-number">0.001</span>, <span class="hljs-string">'kg'</span>: <span class="hljs-number">1</span>, <span class="hljs-string">'t'</span>: <span class="hljs-number">1000</span>}
lbs = value * units[unit] / <span class="hljs-number">0.45359237</span>
window[<span class="hljs-string">'-OUTPUT-'</span>].update(value=<span class="hljs-string">f'<span class="hljs-subst">{value}</span> <span class="hljs-subst">{unit}</span> is <span class="hljs-subst">{lbs:g}</span> lbs.'</span>)
window.close()
</code></pre></div></div>
<pre><code class="python language-python hljs">&lt;Formatter&gt; = logging.Formatter(<span class="hljs-string">'&lt;format&gt;'</span>) <span class="hljs-comment"># Creates a Formatter.</span>
&lt;Handler&gt; = logging.FileHandler(&lt;path&gt;, mode=<span class="hljs-string">'a'</span>) <span class="hljs-comment"># Creates a Handler. Also `encoding=None`.</span>
&lt;Handler&gt;.setFormatter(&lt;Formatter&gt;) <span class="hljs-comment"># Adds Formatter to the Handler.</span>
&lt;Handler&gt;.setLevel(&lt;int/str&gt;) <span class="hljs-comment"># Processes all messages by default.</span>
&lt;Logger&gt;.addHandler(&lt;Handler&gt;) <span class="hljs-comment"># Adds Handler to the Logger.</span>
&lt;Logger&gt;.setLevel(&lt;int/str&gt;) <span class="hljs-comment"># What is sent to its/ancestor's handlers.</span>
</code></pre>
<ul>
<li><strong>Parent logger can be specified by naming the child logger <code class="python hljs"><span class="hljs-string">'&lt;parent&gt;.&lt;name&gt;'</span></code>.</strong></li>
<li><strong>If logger doesn't have a set level it inherits it from the first ancestor that does.</strong></li>
<li><strong>Formatter also accepts: pathname, filename, funcName, lineno, thread and process.</strong></li>
<li><strong>A <code class="python hljs"><span class="hljs-string">'handlers.RotatingFileHandler'</span></code> creates and deletes log files based on 'maxBytes' and 'backupCount' arguments.</strong></li>
</ul>
<div><h4 id="createsaloggerthatwritesallmessagestofileandsendsthemtotherootshandlerthatprintswarningsorhigher">Creates a logger that writes all messages to file and sends them to the root's handler that prints warnings or higher:</h4><pre><code class="python language-python hljs"><span class="hljs-meta">&gt;&gt;&gt; </span>logger = logging.getLogger(<span class="hljs-string">'my_module'</span>)
<span class="hljs-meta">&gt;&gt;&gt; </span>handler = logging.FileHandler(<span class="hljs-string">'test.log'</span>, encoding=<span class="hljs-string">'utf-8'</span>)
<span class="hljs-meta">&gt;&gt;&gt; </span>formatter = logging.Formatter(<span class="hljs-string">'%(asctime)s %(levelname)s:%(name)s:%(message)s'</span>)
<span class="hljs-meta">&gt;&gt;&gt; </span>handler.setFormatter(formatter)
<span class="hljs-meta">&gt;&gt;&gt; </span>logger.addHandler(handler)
<span class="hljs-meta">&gt;&gt;&gt; </span>logging.basicConfig(level=<span class="hljs-string">'DEBUG'</span>)
<span class="hljs-meta">&gt;&gt;&gt; </span>logging.root.handlers[<span class="hljs-number">0</span>].setLevel(<span class="hljs-string">'WARNING'</span>)
<span class="hljs-meta">&gt;&gt;&gt; </span>logger.critical(<span class="hljs-string">'Running out of disk space.'</span>)
CRITICAL:my_module:Running out of disk space.
<span class="hljs-meta">&gt;&gt;&gt; </span>print(open(<span class="hljs-string">'test.log'</span>).read())
2023-02-07 23:21:01,430 CRITICAL:my_module:Running out of disk space.
</code></pre></div>
<div><h2 id="scraping"><a href="#scraping" name="scraping">#</a>Scraping</h2><div><h4 id="scrapespythonsurlandlogofromitswikipediapage">Scrapes Python's URL and logo from its Wikipedia page:</h4><pre><code class="python language-python hljs"><span class="hljs-comment"># $ pip3 install requests beautifulsoup4</span> <div><h2 id="scraping"><a href="#scraping" name="scraping">#</a>Scraping</h2><div><h4 id="scrapespythonsurlandlogofromitswikipediapage">Scrapes Python's URL and logo from its Wikipedia page:</h4><pre><code class="python language-python hljs"><span class="hljs-comment"># $ pip3 install requests beautifulsoup4</span>
<span class="hljs-keyword">import</span> requests, bs4, os, sys
<span class="hljs-keyword">try</span>:
response = requests.get(<span class="hljs-string">'https://en.wikipedia.org/wiki/Python_(programming_language)'</span>)
document = bs4.BeautifulSoup(response.text, <span class="hljs-string">'html.parser'</span>)
table = document.find(<span class="hljs-string">'table'</span>, class_=<span class="hljs-string">'infobox vevent'</span>)
python_url = table.find(<span class="hljs-string">'th'</span>, text=<span class="hljs-string">'Website'</span>).next_sibling.a[<span class="hljs-string">'href'</span>]
logo_url = table.find(<span class="hljs-string">'img'</span>)[<span class="hljs-string">'src'</span>]
logo = requests.get(<span class="hljs-string">f'https:<span class="hljs-subst">{logo_url}</span>'</span>).content
filename = os.path.basename(logo_url)
<span class="hljs-keyword">with</span> open(filename, <span class="hljs-string">'wb'</span>) <span class="hljs-keyword">as</span> file:
file.write(logo)
print(<span class="hljs-string">f'<span class="hljs-subst">{python_url}</span>, file://<span class="hljs-subst">{os.path.abspath(filename)}</span>'</span>)
<span class="hljs-keyword">except</span> requests.exceptions.ConnectionError:
print(<span class="hljs-string">"You've got problems with connection."</span>, file=sys.stderr)
<span class="hljs-keyword">import</span> requests, bs4, os
response = requests.get(<span class="hljs-string">'https://en.wikipedia.org/wiki/Python_(programming_language)'</span>)
document = bs4.BeautifulSoup(response.text, <span class="hljs-string">'html.parser'</span>)
table = document.find(<span class="hljs-string">'table'</span>, class_=<span class="hljs-string">'infobox vevent'</span>)
python_url = table.find(<span class="hljs-string">'th'</span>, text=<span class="hljs-string">'Website'</span>).next_sibling.a[<span class="hljs-string">'href'</span>]
logo_url = table.find(<span class="hljs-string">'img'</span>)[<span class="hljs-string">'src'</span>]
logo = requests.get(<span class="hljs-string">f'https:<span class="hljs-subst">{logo_url}</span>'</span>).content
filename = os.path.basename(logo_url)
<span class="hljs-keyword">with</span> open(filename, <span class="hljs-string">'wb'</span>) <span class="hljs-keyword">as</span> file:
file.write(logo)
print(<span class="hljs-string">f'<span class="hljs-subst">{python_url}</span>, file://<span class="hljs-subst">{os.path.abspath(filename)}</span>'</span>)
</code></pre></div></div> </code></pre></div></div>
<div><h3 id="selenium">Selenium</h3><p><strong>Library for scraping websites with dynamic content.</strong></p><pre><code class="python language-python hljs"><span class="hljs-comment"># $ pip3 install selenium</span>
<span class="hljs-keyword">from</span> selenium <span class="hljs-keyword">import</span> webdriver
&lt;Drv&gt; = webdriver.Chrome/Firefox/Safari/Edge() <span class="hljs-comment"># Opens a browser. Also &lt;Drv&gt;.quit().</span>
&lt;Drv&gt;.get(<span class="hljs-string">'&lt;url&gt;'</span>) <span class="hljs-comment"># Also &lt;Drv&gt;.implicitly_wait(seconds).</span>
&lt;El&gt; = &lt;Drv/El&gt;.find_element(<span class="hljs-string">'css selector'</span>, <span class="hljs-string">'&lt;css&gt;'</span>) <span class="hljs-comment"># '&lt;tag&gt;#&lt;id&gt;.&lt;class&gt;[&lt;attr&gt;="&lt;val&gt;"]'.</span>
&lt;list&gt; = &lt;Drv/El&gt;.find_elements(<span class="hljs-string">'xpath'</span>, <span class="hljs-string">'&lt;xpath&gt;'</span>) <span class="hljs-comment"># '//&lt;tag&gt;[@&lt;attr&gt;="&lt;val&gt;"]'.</span>
&lt;str&gt; = &lt;El&gt;.get_attribute/get_property(&lt;str&gt;) <span class="hljs-comment"># Also &lt;El&gt;.text/tag_name.</span>
&lt;El&gt;.click/clear() <span class="hljs-comment"># Also &lt;El&gt;.send_keys(&lt;str&gt;).</span>
</code></pre></div>
<div><h4 id="xpathalsoavailableinbrowsersconsoleviadxxpath">XPath — also available in browser's console via <code class="python hljs"><span class="hljs-string">'$x(&lt;xpath&gt;)'</span></code>:</h4><pre><code class="python language-python hljs">&lt;xpath&gt; = //&lt;element&gt;[/ <span class="hljs-keyword">or</span> // &lt;element&gt;] <span class="hljs-comment"># Child: /, Descendant: //, Parent: /..</span>
&lt;xpath&gt; = //&lt;element&gt;/following::&lt;element&gt; <span class="hljs-comment"># Next sibling. Also preceding/parent/…</span>
&lt;element&gt; = &lt;tag&gt;&lt;conditions&gt;&lt;index&gt; <span class="hljs-comment"># `&lt;tag&gt; = */a/…`, `&lt;index&gt; = [1/2/…]`.</span>
&lt;condition&gt; = [&lt;sub_cond&gt; [<span class="hljs-keyword">and</span>/<span class="hljs-keyword">or</span> &lt;sub_cond&gt;]] <span class="hljs-comment"># `and` is same as chaining conditions.</span>
&lt;sub_cond&gt; = @&lt;attr&gt;=<span class="hljs-string">"&lt;val&gt;"</span> <span class="hljs-comment"># `.="&lt;val&gt;"` matches complete text.</span>
&lt;sub_cond&gt; = contains(@&lt;attr&gt;, <span class="hljs-string">"&lt;val&gt;"</span>) <span class="hljs-comment"># Is &lt;val&gt; a substring of attr's value?</span>
&lt;sub_cond&gt; = [//]&lt;element&gt; <span class="hljs-comment"># Has matching child? Descendant if //.</span>
</code></pre></div>
<div><h2 id="web"><a href="#web" name="web">#</a>Web</h2><p><strong>Flask is a micro web framework/server. If you just want to open a html file in a web browser use <code class="python hljs"><span class="hljs-string">'webbrowser.open(&lt;path&gt;)'</span></code> instead.</strong></p><pre><code class="python language-python hljs"><span class="hljs-comment"># $ pip3 install flask</span> <div><h2 id="web"><a href="#web" name="web">#</a>Web</h2><p><strong>Flask is a micro web framework/server. If you just want to open a html file in a web browser use <code class="python hljs"><span class="hljs-string">'webbrowser.open(&lt;path&gt;)'</span></code> instead.</strong></p><pre><code class="python language-python hljs"><span class="hljs-comment"># $ pip3 install flask</span>
<span class="hljs-keyword">import</span> flask <span class="hljs-keyword">import</span> flask
</code></pre></div> </code></pre></div>
@ -2219,7 +2233,7 @@ right = [[<span class="hljs-number">0.1</span>, <span class="hljs-number">0.6</
[<span class="hljs-number">0.1</span>, <span class="hljs-number">0.6</span>, <span class="hljs-number">0.8</span>]] [<span class="hljs-number">0.1</span>, <span class="hljs-number">0.6</span>, <span class="hljs-number">0.8</span>]]
</code></pre></div> </code></pre></div>
<div><h3 id="example-2">Example</h3><div><h4 id="foreachpointreturnsindexofitsnearestpoint010608121">For each point returns index of its nearest point (<code class="python hljs">[<span class="hljs-number">0.1</span>, <span class="hljs-number">0.6</span>, <span class="hljs-number">0.8</span>] =&gt; [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>]</code>):</h4><pre><code class="python language-python hljs"><span class="hljs-meta">&gt;&gt;&gt; </span>points = np.array([<span class="hljs-number">0.1</span>, <span class="hljs-number">0.6</span>, <span class="hljs-number">0.8</span>])
<div><h3 id="example-3">Example</h3><div><h4 id="foreachpointreturnsindexofitsnearestpoint010608121">For each point returns index of its nearest point (<code class="python hljs">[<span class="hljs-number">0.1</span>, <span class="hljs-number">0.6</span>, <span class="hljs-number">0.8</span>] =&gt; [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>]</code>):</h4><pre><code class="python language-python hljs"><span class="hljs-meta">&gt;&gt;&gt; </span>points = np.array([<span class="hljs-number">0.1</span>, <span class="hljs-number">0.6</span>, <span class="hljs-number">0.8</span>])
[ <span class="hljs-number">0.1</span>, <span class="hljs-number">0.6</span>, <span class="hljs-number">0.8</span>] [ <span class="hljs-number">0.1</span>, <span class="hljs-number">0.6</span>, <span class="hljs-number">0.8</span>]
<span class="hljs-meta">&gt;&gt;&gt; </span>wrapped_points = points.reshape(<span class="hljs-number">3</span>, <span class="hljs-number">1</span>) <span class="hljs-meta">&gt;&gt;&gt; </span>wrapped_points = points.reshape(<span class="hljs-number">3</span>, <span class="hljs-number">1</span>)
[[ <span class="hljs-number">0.1</span>], [[ <span class="hljs-number">0.1</span>],
@ -2252,17 +2266,17 @@ right = [[<span class="hljs-number">0.1</span>, <span class="hljs-number">0.6</
&lt;Image&gt;.save(&lt;path&gt;) <span class="hljs-comment"># Selects format based on the path extension.</span> &lt;Image&gt;.save(&lt;path&gt;) <span class="hljs-comment"># Selects format based on the path extension.</span>
&lt;Image&gt;.show() <span class="hljs-comment"># Opens image in the default preview app.</span> &lt;Image&gt;.show() <span class="hljs-comment"># Opens image in the default preview app.</span>
</code></pre> </code></pre>
<pre><code class="python language-python hljs">&lt;int/tuple&gt; = &lt;Image&gt;.getpixel((x, y)) <span class="hljs-comment"># Returns pixel's color.</span>
&lt;Image&gt;.putpixel((x, y), &lt;int/tuple&gt;) <span class="hljs-comment"># Changes pixel's color.</span>
&lt;ImagingCore&gt; = &lt;Image&gt;.getdata() <span class="hljs-comment"># Returns a flattened view of all pixels.</span>
<pre><code class="python language-python hljs">&lt;int/tuple&gt; = &lt;Image&gt;.getpixel((x, y)) <span class="hljs-comment"># Returns pixel's value (its color).</span>
&lt;Image&gt;.putpixel((x, y), &lt;int/tuple&gt;) <span class="hljs-comment"># Updates pixel's value.</span>
&lt;ImagingCore&gt; = &lt;Image&gt;.getdata() <span class="hljs-comment"># Returns a flattened view of pixel values.</span>
&lt;Image&gt;.putdata(&lt;list/ImagingCore&gt;) <span class="hljs-comment"># Updates pixels with a copy of the sequence.</span> &lt;Image&gt;.putdata(&lt;list/ImagingCore&gt;) <span class="hljs-comment"># Updates pixels with a copy of the sequence.</span>
&lt;Image&gt;.paste(&lt;Image&gt;, (x, y)) <span class="hljs-comment"># Draws passed image at specified location.</span> &lt;Image&gt;.paste(&lt;Image&gt;, (x, y)) <span class="hljs-comment"># Draws passed image at specified location.</span>
</code></pre> </code></pre>
<pre><code class="python language-python hljs">&lt;Image&gt; = &lt;Image&gt;.filter(&lt;Filter&gt;) <span class="hljs-comment"># `&lt;Filter&gt; = ImageFilter.&lt;name&gt;([&lt;args&gt;])`</span> <pre><code class="python language-python hljs">&lt;Image&gt; = &lt;Image&gt;.filter(&lt;Filter&gt;) <span class="hljs-comment"># `&lt;Filter&gt; = ImageFilter.&lt;name&gt;([&lt;args&gt;])`</span>
&lt;Image&gt; = &lt;Enhance&gt;.enhance(&lt;float&gt;) <span class="hljs-comment"># `&lt;Enhance&gt; = ImageEnhance.&lt;name&gt;(&lt;Image&gt;)`</span> &lt;Image&gt; = &lt;Enhance&gt;.enhance(&lt;float&gt;) <span class="hljs-comment"># `&lt;Enhance&gt; = ImageEnhance.&lt;name&gt;(&lt;Image&gt;)`</span>
</code></pre> </code></pre>
<pre><code class="python language-python hljs">&lt;array&gt; = np.array(&lt;Image&gt;) <span class="hljs-comment"># Creates a NumPy array from the image.</span>
&lt;Image&gt; = Image.fromarray(np.uint8(&lt;array&gt;)) <span class="hljs-comment"># Use &lt;array&gt;.clip(0, 255) to clip values.</span>
<pre><code class="python language-python hljs">&lt;array&gt; = np.array(&lt;Image&gt;) <span class="hljs-comment"># Creates a 2d/3d NumPy array from the image.</span>
&lt;Image&gt; = Image.fromarray(np.uint8(&lt;array&gt;)) <span class="hljs-comment"># Use `&lt;array&gt;.clip(0, 255)` to clip values.</span>
</code></pre> </code></pre>
<div><h3 id="modes-1">Modes</h3><ul> <div><h3 id="modes-1">Modes</h3><ul>
<li><strong><code class="python hljs"><span class="hljs-string">'L'</span></code> - 8-bit pixels, greyscale.</strong></li> <li><strong><code class="python hljs"><span class="hljs-string">'L'</span></code> - 8-bit pixels, greyscale.</strong></li>
@ -2849,15 +2863,6 @@ ex.line(df, x=<span class="hljs-string">'Date'</span>, y=<span class="hljs-strin
<div><h2 id="pysimplegui"><a href="#pysimplegui" name="pysimplegui">#</a>PySimpleGUI</h2><pre><code class="python language-python hljs"><span class="hljs-comment"># $ pip3 install PySimpleGUI</span>
<span class="hljs-keyword">import</span> PySimpleGUI <span class="hljs-keyword">as</span> sg
layout = [[sg.Text(<span class="hljs-string">"What's your name?"</span>)], [sg.Input()], [sg.Button(<span class="hljs-string">'Ok'</span>)]]
window = sg.Window(<span class="hljs-string">'Window Title'</span>, layout)
event, values = window.read()
print(<span class="hljs-string">f'Hello <span class="hljs-subst">{values[<span class="hljs-number">0</span>]}</span>!'</span> <span class="hljs-keyword">if</span> event == <span class="hljs-string">'Ok'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">''</span>)
</code></pre></div>
<div><h2 id="appendix"><a href="#appendix" name="appendix">#</a>Appendix</h2><div><h3 id="cython">Cython</h3><p><strong>Library that compiles Python code into C.</strong></p><pre><code class="python language-python hljs"><span class="hljs-comment"># $ pip3 install cython</span> <div><h2 id="appendix"><a href="#appendix" name="appendix">#</a>Appendix</h2><div><h3 id="cython">Cython</h3><p><strong>Library that compiles Python code into C.</strong></p><pre><code class="python language-python hljs"><span class="hljs-comment"># $ pip3 install cython</span>
<span class="hljs-keyword">import</span> pyximport; pyximport.install() <span class="hljs-keyword">import</span> pyximport; pyximport.install()
<span class="hljs-keyword">import</span> &lt;cython_script&gt; <span class="hljs-keyword">import</span> &lt;cython_script&gt;
@ -2926,7 +2931,7 @@ $ deactivate <span class="hljs-comment"># Deactivates the activ
<footer> <footer>
<aside>December 6, 2023</aside>
<aside>December 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>

56
parse.js

@ -38,9 +38,9 @@ const TOC =
' <strong><span class="hljs-string">\'3. Syntax\'</span></strong>: [<a href="#arguments">Args</a>, <a href="#inline">Inline</a>, <a href="#imports">Import</a>, <a href="#decorator">Decorator</a>, <a href="#class">Class</a>, <a href="#ducktypes">Duck_Types</a>, <a href="#enum">Enum</a>, <a href="#exceptions">Exception</a>],\n' + ' <strong><span class="hljs-string">\'3. Syntax\'</span></strong>: [<a href="#arguments">Args</a>, <a href="#inline">Inline</a>, <a href="#imports">Import</a>, <a href="#decorator">Decorator</a>, <a href="#class">Class</a>, <a href="#ducktypes">Duck_Types</a>, <a href="#enum">Enum</a>, <a href="#exceptions">Exception</a>],\n' +
' <strong><span class="hljs-string">\'4. System\'</span></strong>: [<a href="#exit">Exit</a>, <a href="#print">Print</a>, <a href="#input">Input</a>, <a href="#commandlinearguments">Command_Line_Arguments</a>, <a href="#open">Open</a>, <a href="#paths">Path</a>, <a href="#oscommands">OS_Commands</a>],\n' + ' <strong><span class="hljs-string">\'4. System\'</span></strong>: [<a href="#exit">Exit</a>, <a href="#print">Print</a>, <a href="#input">Input</a>, <a href="#commandlinearguments">Command_Line_Arguments</a>, <a href="#open">Open</a>, <a href="#paths">Path</a>, <a href="#oscommands">OS_Commands</a>],\n' +
' <strong><span class="hljs-string">\'5. Data\'</span></strong>: [<a href="#json">JSON</a>, <a href="#pickle">Pickle</a>, <a href="#csv">CSV</a>, <a href="#sqlite">SQLite</a>, <a href="#bytes">Bytes</a>, <a href="#struct">Struct</a>, <a href="#array">Array</a>, <a href="#memoryview">Memory_View</a>, <a href="#deque">Deque</a>],\n' + ' <strong><span class="hljs-string">\'5. Data\'</span></strong>: [<a href="#json">JSON</a>, <a href="#pickle">Pickle</a>, <a href="#csv">CSV</a>, <a href="#sqlite">SQLite</a>, <a href="#bytes">Bytes</a>, <a href="#struct">Struct</a>, <a href="#array">Array</a>, <a href="#memoryview">Memory_View</a>, <a href="#deque">Deque</a>],\n' +
' <strong><span class="hljs-string">\'6. Advanced\'</span></strong>: [<a href="#threading">Threading</a>, <a href="#operator">Operator</a>, <a href="#introspection">Introspection</a>, <a href="#metaprogramming">Metaprograming</a>, <a href="#eval">Eval</a>, <a href="#coroutines">Coroutine</a>],\n' +
' <strong><span class="hljs-string">\'7. Libraries\'</span></strong>: [<a href="#progressbar">Progress_Bar</a>, <a href="#plot">Plot</a>, <a href="#table">Tables</a>, <a href="#curses">Curses</a>, <a href="#logging">Logging</a>, <a href="#scraping">Scraping</a>, <a href="#web">Web</a>, <a href="#profiling">Profile</a>],\n' +
' <strong><span class="hljs-string">\'8. Multimedia\'</span></strong>: [<a href="#numpy">NumPy</a>, <a href="#image">Image</a>, <a href="#animation">Animation</a>, <a href="#audio">Audio</a>, <a href="#pygame">Pygame</a>, <a href="#pandas">Pandas</a>, <a href="#plotly">Plotly</a>, <a href="#pysimplegui">PySimpleGUI</a>]\n' +
' <strong><span class="hljs-string">\'6. Advanced\'</span></strong>: [<a href="#threading">Threading</a>, <a href="#operator">Operator</a>, <a href="#matchstatement">Match_Stmt</a>, <a href="#introspection">Introspection</a>, <a href="#logging">Logging</a>, <a href="#coroutines">Coroutines</a>],\n' +
' <strong><span class="hljs-string">\'7. Libraries\'</span></strong>: [<a href="#progressbar">Progress_Bar</a>, <a href="#plot">Plots</a>, <a href="#table">Tables</a>, <a href="#curses">Curses</a>, <a href="#pysimplegui">GUIs</a>, <a href="#scraping">Scraping</a>, <a href="#web">Web</a>, <a href="#profiling">Profiling</a>],\n' +
' <strong><span class="hljs-string">\'8. Multimedia\'</span></strong>: [<a href="#numpy">NumPy</a>, <a href="#image">Image</a>, <a href="#animation">Animation</a>, <a href="#audio">Audio</a>, <a href="#synthesizer">Synthesizer</a>, <a href="#pygame">Pygame</a>, <a href="#pandas">Pandas</a>, <a href="#plotly">Plotly</a>]\n' +
'}\n' + '}\n' +
'</code></pre>\n'; '</code></pre>\n';
@ -105,18 +105,25 @@ const OS_RENAME =
const STRUCT_FORMAT = const STRUCT_FORMAT =
'<span class="hljs-section">\'&lt;n&gt;s\'</span><span class="hljs-attribute"></span>'; '<span class="hljs-section">\'&lt;n&gt;s\'</span><span class="hljs-attribute"></span>';
const TYPE =
'&lt;class&gt; = type(<span class="hljs-string">\'&lt;class_name&gt;\'</span>, &lt;tuple_of_parents&gt;, &lt;dict_of_class_attributes&gt;)';
const EVAL =
'<span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">from</span> ast <span class="hljs-keyword">import</span> literal_eval\n' +
'<span class="hljs-meta">&gt;&gt;&gt; </span>literal_eval(<span class="hljs-string">\'[1, 2, 3]\'</span>)\n' +
'[<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]\n' +
'<span class="hljs-meta">&gt;&gt;&gt; </span>literal_eval(<span class="hljs-string">\'1 + 2\'</span>)\n' +
'ValueError: malformed node or string\n';
const MATCH =
'<span class="hljs-keyword">match</span> &lt;object/expression&gt;:\n' +
' <span class="hljs-keyword">case</span> &lt;pattern&gt; [<span class="hljs-keyword">if</span> &lt;condition&gt;]:\n' +
' &lt;code&gt;\n' +
' ...\n';
const MATCH_EXAMPLE =
'<span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">from</span> pathlib <span class="hljs-keyword">import</span> Path\n' +
'<span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">match</span> Path(<span class="hljs-string">\'/home/gto/python-cheatsheet/README.md\'</span>):\n' +
'<span class="hljs-meta">... </span> <span class="hljs-keyword">case</span> Path(\n' +
'<span class="hljs-meta">... </span> parts=[<span class="hljs-string">\'/\'</span>, <span class="hljs-string">\'home\'</span>, user, *_],\n' +
'<span class="hljs-meta">... </span> stem=stem,\n' +
'<span class="hljs-meta">... </span> suffix=(<span class="hljs-string">\'.md\'</span> | <span class="hljs-string">\'.txt\'</span>) <span class="hljs-keyword">as</span> suffix\n' +
'<span class="hljs-meta">... </span> ) <span class="hljs-keyword">if</span> stem.lower() == <span class="hljs-string">\'readme\'</span>:\n' +
'<span class="hljs-meta">... </span> print(<span class="hljs-string">f\'<span class="hljs-subst">{stem}</span><span class="hljs-subst">{suffix}</span> is a readme file that belongs to user <span class="hljs-subst">{user}</span>.\'</span>)\n' +
'<span class="hljs-string">\'README.md is a readme file that belongs to user gto.\'</span>\n';
const COROUTINES = const COROUTINES =
'<span class="hljs-keyword">import</span> asyncio, collections, curses, curses.textpad, enum, random\n' +
'<span class="hljs-keyword">import</span> asyncio, collections, curses, curses.textpad, enum, random, time\n' +
'\n' + '\n' +
'P = collections.namedtuple(<span class="hljs-string">\'P\'</span>, <span class="hljs-string">\'x y\'</span>) <span class="hljs-comment"># Position</span>\n' + 'P = collections.namedtuple(<span class="hljs-string">\'P\'</span>, <span class="hljs-string">\'x y\'</span>) <span class="hljs-comment"># Position</span>\n' +
'D = enum.Enum(<span class="hljs-string">\'D\'</span>, <span class="hljs-string">\'n e s w\'</span>) <span class="hljs-comment"># Direction</span>\n' + 'D = enum.Enum(<span class="hljs-string">\'D\'</span>, <span class="hljs-string">\'n e s w\'</span>) <span class="hljs-comment"># Direction</span>\n' +
@ -144,7 +151,8 @@ const COROUTINES =
'<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">human_controller</span><span class="hljs-params">(screen, moves)</span>:</span>\n' + '<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">human_controller</span><span class="hljs-params">(screen, moves)</span>:</span>\n' +
' <span class="hljs-keyword">while</span> <span class="hljs-keyword">True</span>:\n' + ' <span class="hljs-keyword">while</span> <span class="hljs-keyword">True</span>:\n' +
' key_mappings = {<span class="hljs-number">258</span>: D.s, <span class="hljs-number">259</span>: D.n, <span class="hljs-number">260</span>: D.w, <span class="hljs-number">261</span>: D.e}\n' + ' key_mappings = {<span class="hljs-number">258</span>: D.s, <span class="hljs-number">259</span>: D.n, <span class="hljs-number">260</span>: D.w, <span class="hljs-number">261</span>: D.e}\n' +
' <span class="hljs-keyword">if</span> d := key_mappings.get(screen.getch()):\n' +
' ch = screen.getch()\n' +
' <span class="hljs-keyword">if</span> d := key_mappings.get(ch):\n' +
' moves.put_nowait((<span class="hljs-string">\'*\'</span>, d))\n' + ' moves.put_nowait((<span class="hljs-string">\'*\'</span>, d))\n' +
' <span class="hljs-keyword">await</span> asyncio.sleep(<span class="hljs-number">0.005</span>)\n' + ' <span class="hljs-keyword">await</span> asyncio.sleep(<span class="hljs-number">0.005</span>)\n' +
'\n' + '\n' +
@ -153,7 +161,8 @@ const COROUTINES =
' id_, d = <span class="hljs-keyword">await</span> moves.get()\n' + ' id_, d = <span class="hljs-keyword">await</span> moves.get()\n' +
' x, y = state[id_]\n' + ' x, y = state[id_]\n' +
' deltas = {D.n: P(<span class="hljs-number">0</span>, <span class="hljs-number">-1</span>), D.e: P(<span class="hljs-number">1</span>, <span class="hljs-number">0</span>), D.s: P(<span class="hljs-number">0</span>, <span class="hljs-number">1</span>), D.w: P(<span class="hljs-number">-1</span>, <span class="hljs-number">0</span>)}\n' + ' deltas = {D.n: P(<span class="hljs-number">0</span>, <span class="hljs-number">-1</span>), D.e: P(<span class="hljs-number">1</span>, <span class="hljs-number">0</span>), D.s: P(<span class="hljs-number">0</span>, <span class="hljs-number">1</span>), D.w: P(<span class="hljs-number">-1</span>, <span class="hljs-number">0</span>)}\n' +
' state[id_] = P((x + deltas[d].x) % W, (y + deltas[d].y) % H)\n' +
' dx, dy = deltas[d]\n' +
' state[id_] = P((x + dx) % W, (y + dy) % H)\n' +
'\n' + '\n' +
'<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">view</span><span class="hljs-params">(state, screen)</span>:</span>\n' + '<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">view</span><span class="hljs-params">(state, screen)</span>:</span>\n' +
' offset = P(curses.COLS//<span class="hljs-number">2</span> - W//<span class="hljs-number">2</span>, curses.LINES//<span class="hljs-number">2</span> - H//<span class="hljs-number">2</span>)\n' + ' offset = P(curses.COLS//<span class="hljs-number">2</span> - W//<span class="hljs-number">2</span>, curses.LINES//<span class="hljs-number">2</span> - H//<span class="hljs-number">2</span>)\n' +
@ -161,16 +170,21 @@ const COROUTINES =
' screen.erase()\n' + ' screen.erase()\n' +
' curses.textpad.rectangle(screen, offset.y-<span class="hljs-number">1</span>, offset.x-<span class="hljs-number">1</span>, offset.y+H, offset.x+W)\n' + ' curses.textpad.rectangle(screen, offset.y-<span class="hljs-number">1</span>, offset.x-<span class="hljs-number">1</span>, offset.y+H, offset.x+W)\n' +
' <span class="hljs-keyword">for</span> id_, p <span class="hljs-keyword">in</span> state.items():\n' + ' <span class="hljs-keyword">for</span> id_, p <span class="hljs-keyword">in</span> state.items():\n' +
' screen.addstr(offset.y + (p.y - state[<span class="hljs-string">\'*\'</span>].y + H//<span class="hljs-number">2</span>) % H,\n' +
' offset.x + (p.x - state[<span class="hljs-string">\'*\'</span>].x + W//<span class="hljs-number">2</span>) % W, str(id_))\n' +
' screen.addstr(\n' +
' offset.y + (p.y - state[<span class="hljs-string">\'*\'</span>].y + H//<span class="hljs-number">2</span>) % H,\n' +
' offset.x + (p.x - state[<span class="hljs-string">\'*\'</span>].x + W//<span class="hljs-number">2</span>) % W,\n' +
' str(id_)\n' +
' )\n' +
' screen.refresh()\n' + ' screen.refresh()\n' +
' <span class="hljs-keyword">await</span> asyncio.sleep(<span class="hljs-number">0.005</span>)\n' + ' <span class="hljs-keyword">await</span> asyncio.sleep(<span class="hljs-number">0.005</span>)\n' +
'\n' + '\n' +
'<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">\'__main__\'</span>:\n' + '<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">\'__main__\'</span>:\n' +
' curses.wrapper(main)\n';
' start_time = time.perf_counter()\n' +
' curses.wrapper(main)\n' +
' print(<span class="hljs-string">f\'You survived <span class="hljs-subst">{time.perf_counter() - start_time:<span class="hljs-number">.2</span>f}</span> seconds.\'</span>)\n';
const CURSES = const CURSES =
'<span class="hljs-comment"># pip3 install windows-curses</span>\n' +
'<span class="hljs-comment"># $ pip3 install windows-curses</span>\n' +
'<span class="hljs-keyword">import</span> curses, os\n' + '<span class="hljs-keyword">import</span> curses, os\n' +
'<span class="hljs-keyword">from</span> curses <span class="hljs-keyword">import</span> A_REVERSE, KEY_DOWN, KEY_UP, KEY_LEFT, KEY_RIGHT, KEY_ENTER\n' + '<span class="hljs-keyword">from</span> curses <span class="hljs-keyword">import</span> A_REVERSE, KEY_DOWN, KEY_UP, KEY_LEFT, KEY_RIGHT, KEY_ENTER\n' +
'\n' + '\n' +
@ -814,8 +828,8 @@ function fixHighlights() {
$(`code:contains(shutil.copy)`).html(SHUTIL_COPY); $(`code:contains(shutil.copy)`).html(SHUTIL_COPY);
$(`code:contains(os.rename)`).html(OS_RENAME); $(`code:contains(os.rename)`).html(OS_RENAME);
$(`code:contains(\'<n>s\')`).html(STRUCT_FORMAT); $(`code:contains(\'<n>s\')`).html(STRUCT_FORMAT);
$(`code:contains(\'<class_name>\', <tuple_of_parents>, <dict_of_class_attributes>)`).html(TYPE);
$(`code:contains(ValueError: malformed node)`).html(EVAL);
$(`code:contains(match <object/expression>:)`).html(MATCH);
$(`code:contains(>>> match Path)`).html(MATCH_EXAMPLE);
$(`code:contains(import asyncio, collections, curses, curses.textpad, enum, random)`).html(COROUTINES); $(`code:contains(import asyncio, collections, curses, curses.textpad, enum, random)`).html(COROUTINES);
$(`code:contains(import curses, os)`).html(CURSES); $(`code:contains(import curses, os)`).html(CURSES);
$(`code:contains(pip3 install tqdm)`).html(PROGRESS_BAR); $(`code:contains(pip3 install tqdm)`).html(PROGRESS_BAR);

19
web/script_2.js

@ -5,9 +5,9 @@ const TOC =
' <strong><span class="hljs-string">\'3. Syntax\'</span></strong>: [<a href="#arguments">Args</a>, <a href="#inline">Inline</a>, <a href="#imports">Import</a>, <a href="#decorator">Decorator</a>, <a href="#class">Class</a>, <a href="#ducktypes">Duck_Types</a>, <a href="#enum">Enum</a>, <a href="#exceptions">Exception</a>],\n' + ' <strong><span class="hljs-string">\'3. Syntax\'</span></strong>: [<a href="#arguments">Args</a>, <a href="#inline">Inline</a>, <a href="#imports">Import</a>, <a href="#decorator">Decorator</a>, <a href="#class">Class</a>, <a href="#ducktypes">Duck_Types</a>, <a href="#enum">Enum</a>, <a href="#exceptions">Exception</a>],\n' +
' <strong><span class="hljs-string">\'4. System\'</span></strong>: [<a href="#exit">Exit</a>, <a href="#print">Print</a>, <a href="#input">Input</a>, <a href="#commandlinearguments">Command_Line_Arguments</a>, <a href="#open">Open</a>, <a href="#paths">Path</a>, <a href="#oscommands">OS_Commands</a>],\n' + ' <strong><span class="hljs-string">\'4. System\'</span></strong>: [<a href="#exit">Exit</a>, <a href="#print">Print</a>, <a href="#input">Input</a>, <a href="#commandlinearguments">Command_Line_Arguments</a>, <a href="#open">Open</a>, <a href="#paths">Path</a>, <a href="#oscommands">OS_Commands</a>],\n' +
' <strong><span class="hljs-string">\'5. Data\'</span></strong>: [<a href="#json">JSON</a>, <a href="#pickle">Pickle</a>, <a href="#csv">CSV</a>, <a href="#sqlite">SQLite</a>, <a href="#bytes">Bytes</a>, <a href="#struct">Struct</a>, <a href="#array">Array</a>, <a href="#memoryview">Memory_View</a>, <a href="#deque">Deque</a>],\n' + ' <strong><span class="hljs-string">\'5. Data\'</span></strong>: [<a href="#json">JSON</a>, <a href="#pickle">Pickle</a>, <a href="#csv">CSV</a>, <a href="#sqlite">SQLite</a>, <a href="#bytes">Bytes</a>, <a href="#struct">Struct</a>, <a href="#array">Array</a>, <a href="#memoryview">Memory_View</a>, <a href="#deque">Deque</a>],\n' +
' <strong><span class="hljs-string">\'6. Advanced\'</span></strong>: [<a href="#threading">Threading</a>, <a href="#operator">Operator</a>, <a href="#introspection">Introspection</a>, <a href="#metaprogramming">Metaprograming</a>, <a href="#eval">Eval</a>, <a href="#coroutines">Coroutine</a>],\n' +
' <strong><span class="hljs-string">\'7. Libraries\'</span></strong>: [<a href="#progressbar">Progress_Bar</a>, <a href="#plot">Plot</a>, <a href="#table">Tables</a>, <a href="#curses">Curses</a>, <a href="#logging">Logging</a>, <a href="#scraping">Scraping</a>, <a href="#web">Web</a>, <a href="#profiling">Profile</a>],\n' +
' <strong><span class="hljs-string">\'8. Multimedia\'</span></strong>: [<a href="#numpy">NumPy</a>, <a href="#image">Image</a>, <a href="#animation">Animation</a>, <a href="#audio">Audio</a>, <a href="#pygame">Pygame</a>, <a href="#pandas">Pandas</a>, <a href="#plotly">Plotly</a>, <a href="#pysimplegui">PySimpleGUI</a>]\n' +
' <strong><span class="hljs-string">\'6. Advanced\'</span></strong>: [<a href="#threading">Threading</a>, <a href="#operator">Operator</a>, <a href="#matchstatement">Match_Stmt</a>, <a href="#introspection">Introspection</a>, <a href="#logging">Logging</a>, <a href="#coroutines">Coroutines</a>],\n' +
' <strong><span class="hljs-string">\'7. Libraries\'</span></strong>: [<a href="#progressbar">Progress_Bar</a>, <a href="#plot">Plots</a>, <a href="#table">Tables</a>, <a href="#curses">Curses</a>, <a href="#pysimplegui">GUIs</a>, <a href="#scraping">Scraping</a>, <a href="#web">Web</a>, <a href="#profiling">Profiling</a>],\n' +
' <strong><span class="hljs-string">\'8. Multimedia\'</span></strong>: [<a href="#numpy">NumPy</a>, <a href="#image">Image</a>, <a href="#animation">Animation</a>, <a href="#audio">Audio</a>, <a href="#synthesizer">Synthesizer</a>, <a href="#pygame">Pygame</a>, <a href="#pandas">Pandas</a>, <a href="#plotly">Plotly</a>]\n' +
'}\n'; '}\n';
const TOC_MOBILE = const TOC_MOBILE =
@ -29,15 +29,14 @@ const TOC_MOBILE =
' <a href="#bytes">Bytes</a>, <a href="#struct">Struct</a>, <a href="#array">Array</a>,\n' + ' <a href="#bytes">Bytes</a>, <a href="#struct">Struct</a>, <a href="#array">Array</a>,\n' +
' <a href="#memoryview">Memory_View</a>, <a href="#deque">Deque</a>],\n' + ' <a href="#memoryview">Memory_View</a>, <a href="#deque">Deque</a>],\n' +
' <strong><span class="hljs-string">\'6. Advanced\'</span></strong>: [<a href="#threading">Threading</a>, <a href="#operator">Operator</a>,\n' + ' <strong><span class="hljs-string">\'6. Advanced\'</span></strong>: [<a href="#threading">Threading</a>, <a href="#operator">Operator</a>,\n' +
' <a href="#introspection">Introspection</a>,\n' +
' <a href="#metaprogramming">Metaprograming</a>, <a href="#eval">Eval</a>,\n' +
' <a href="#coroutines">Coroutine</a>],\n' +
' <a href="#matchstatement">Match_Stmt</a>, <a href="#introspection">Introspection</a>,\n' +
' <a href="#logging">Logging</a>, <a href="#coroutines">Coroutines</a>],\n' +
' <strong><span class="hljs-string">\'7. Libraries\'</span></strong>: [<a href="#progressbar">Progress_Bar</a>, <a href="#plot">Plot</a>, <a href="#table">Table</a>,\n' + ' <strong><span class="hljs-string">\'7. Libraries\'</span></strong>: [<a href="#progressbar">Progress_Bar</a>, <a href="#plot">Plot</a>, <a href="#table">Table</a>,\n' +
' <a href="#curses">Curses</a>, <a href="#logging">Logging</a>, <a href="#scraping">Scraping</a>,\n' +
' <a href="#web">Web</a>, <a href="#profiling">Profile</a>],\n' +
' <a href="#curses">Curses</a>, <a href="#pysimplegui">GUIs</a>, <a href="#scraping">Scraping</a>,\n' +
' <a href="#web">Web</a>, <a href="#profiling">Profiling</a>],\n' +
' <strong><span class="hljs-string">\'8. Multimedia\'</span></strong>: [<a href="#numpy">NumPy</a>, <a href="#image">Image</a>, <a href="#animation">Animation</a>,\n' + ' <strong><span class="hljs-string">\'8. Multimedia\'</span></strong>: [<a href="#numpy">NumPy</a>, <a href="#image">Image</a>, <a href="#animation">Animation</a>,\n' +
' <a href="#audio">Audio</a>, <a href="#pygame">Pygame</a>, <a href="#pandas">Pandas</a>,\n' +
' <a href="#plotly">Plotly</a>, <a href="#pysimplegui">PySimpleGUI</a>]\n' +
' <a href="#audio">Audio</a>, <a href="#synthesizer">Synthesizer</a>,\n' +
' <a href="#pygame">Pygame</a>, <a href="#pandas">Pandas</a>, <a href="#plotly">Plotly</a>]\n' +
'}\n'; '}\n';

Loading…
Cancel
Save