diff --git a/GiantKangaroo.html b/GiantKangaroo.html new file mode 100644 index 0000000..f705cd9 --- /dev/null +++ b/GiantKangaroo.html @@ -0,0 +1,501 @@ + + + + + + + +Giant Kangaroo + + + + + + + +
+ +

Giant Kangaroo

+ +
+ERROR! Your browser doesn't support the HTML5 canvas element! +
+ +
+This is javascript drawing on an HTML5 canvas in real time. +
+ +
+ + + diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..92df917 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,16 @@ +MIT No Attribution + +Copyright 2003-2024 PEW's Corner + +Permission is hereby granted, free of charge, to any person obtaining a copy of this +software and associated documentation files (the "Software"), to deal in the Software +without restriction, including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/LTE/active_RS.png b/LTE/active_RS.png new file mode 100644 index 0000000..f8513fa Binary files /dev/null and b/LTE/active_RS.png differ diff --git a/LTE/dci_decoder.html b/LTE/dci_decoder.html new file mode 100644 index 0000000..c24deee --- /dev/null +++ b/LTE/dci_decoder.html @@ -0,0 +1,1688 @@ + + + + + + + + +LTE DCI Decoder + + + + + + + +
+ +

LTE DCI Decoder

+

(Supports all Rel-8 DCI formats)

+ +

WARNING: If this text is still visible when the page is fully loaded, scripts are disabled in your browser and this page will not work properly!

+ +
+ +
+ + + + + + + + + + + +
Duplexing mode: + + +
TDD subframe type: + + +
Channel bandwidth: + + +
Number of Tx antenna ports: + + +
Transmission mode: + + +
RNTI type: + + +
DCI hex value: + + +
DCI length (bits): + + + +
All possible DCI lengths (bits):
+ (Bold ones are for given setup) +
+
+
+
+ +
+ +
+ + + diff --git a/LTE/inactive_RS.png b/LTE/inactive_RS.png new file mode 100644 index 0000000..b807903 Binary files /dev/null and b/LTE/inactive_RS.png differ diff --git a/LTE/index.html b/LTE/index.html new file mode 100644 index 0000000..5768410 --- /dev/null +++ b/LTE/index.html @@ -0,0 +1,27 @@ + + + + + + + +LTE Stuff + + + + + +
+ +

LTE Stuff

+ +
+LTE resource grid +PDSCH allocation calculator +DCI decoder +
+ +
+ + + diff --git a/LTE/lte_resource_grid.html b/LTE/lte_resource_grid.html new file mode 100644 index 0000000..8e21a4f --- /dev/null +++ b/LTE/lte_resource_grid.html @@ -0,0 +1,2004 @@ + + + + + + + + +LTE Resource Grid + + + + + + + +
+ +

LTE Resource Grid

+

(3GPP Rel-8 Downlink)

+ +

WARNING: If this text is still visible when the page is fully loaded, scripts are disabled in your browser and this page will not work properly!

+ +
+ +
+ + + + + + + + + + + + + + + + + +
Duplexing mode: + + +
TDD uplink/downlink configuration:
+ (from SIB1 in PDSCH) +

+   +

+   +
TDD special subframe configuration:
+ (from SIB1 in PDSCH) +

+   +

+  
+
MBSFN subframe:
+ (from SIB2 in PDSCH) +

+   +

+   +
Channel bandwidth:
+ (from MIB in PBCH) +

+   +

+   +
Cyclic prefix: + + +
Tx antenna port / number of ports: + / + + +
Physical layer cell ID (0-503):
+ (from PSCH and SSCH) +

+   +

+   +
Control format indicator (CFI):
+ (from PCFICH) +

+   +

+  
+
CFI for TDD subframes 1 and 6:
+ (from PCFICH) +

+   +

+  
+
CFI for MBSFN subframe:
+ (from PCFICH) +

+   +

+  
+
PHICH Ng factor:
+ (from MIB in PBCH) +

+   +

+  
+
PHICH duration:
+ (from MIB in PBCH) +

+   +

+   +
Set marker at: + + + + +
    in subframe: + + + +
+ PSCH (Primary Synchronization Channel)
+ SSCH (Secondary Synchronization Channel)
+ PBCH (Physical Broadcast Channel)
+ RS (cell-specific Reference Signal) for selected Tx antenna port
+ Reserved for TDD uplink
+ Unused by selected Tx antenna port, or undefined for all ports
+ MBSFN (Multicast/Broadcast over Single Frequency Network) region
+ - available for PMCH (Physical Multicast Channel)
+
+ PCFICH (Physical Control Format Indicator Channel)
+ PHICH (Physical Hybrid ARQ (Automatic Repeat reQuest) Indicator Channel)
+ PDCCH (Physical Downlink Control Channel)
+ Available for PDSCH (Physical Downlink Shared Channel)
+ TDD guard period in special subframe
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+ +
+ + + diff --git a/LTE/lte_style.css b/LTE/lte_style.css new file mode 100644 index 0000000..8fd4b2b --- /dev/null +++ b/LTE/lte_style.css @@ -0,0 +1,45 @@ +table.form { + margin-left: auto; + margin-right: auto; + border-collapse: separate; + border: 1px solid #D0D0D0; + border-spacing: 0px; + background-color: white; +} +table.form td { + border-color: #D0D0D0; + border-style: solid; + border-width: 1px 0px 1px 0px; + padding: 0.1em 0.3em; + text-align: left; +} +table.form td.no_bottom_border { + border-bottom-width: 0px; +} +table.form td.no_top_border { + border-top-width: 0px; +} +table.form td#result { + text-align: center; +} +table.result { + border-collapse: separate; + border: 2px solid #000000; + border-spacing: 0px; + margin: 0.3em auto; +} +table.result th, table.result td { + border-color: #D0D0D0; + border-style: solid; + border-width: 1px; + padding: 0.1em 0.3em; + text-align: left; +} +table.result th { + font-weight: bold; + background-color: #F0F0F0; +} +.note { + font-size: 70%; + color: #808080; +} diff --git a/LTE/marker.gif b/LTE/marker.gif new file mode 100644 index 0000000..442826e Binary files /dev/null and b/LTE/marker.gif differ diff --git a/LTE/pdsch_calc.html b/LTE/pdsch_calc.html new file mode 100644 index 0000000..03110ed --- /dev/null +++ b/LTE/pdsch_calc.html @@ -0,0 +1,618 @@ + + + + + + + + +LTE PDSCH Allocation Calculator + + + + + + + +
+ +

LTE PDSCH Allocation Calculator

+

(3GPP Rel-8)

+ +

WARNING: If this text is still visible when the page is fully loaded, scripts are disabled in your browser and this page will not work properly!

+ +
+ +
+ + + + + + + + + + + + + + + + + + +
Duplexing mode: + + +
TDD uplink/downlink configuration:
+   +

+   +

+   +
TDD special subframe configuration:
+   +

+   +

+  
+
Channel bandwidth: + + +
Cyclic prefix: + + +
Number of Tx antenna ports: + + +
Number of spatially multiplexed layers: + + +
Control format indicator (CFI): + + +
Subframe: + + +
Modulation: + + +
Slot 0 PRB allocation hex value: + + +
Bit string (PRB 0 first): + +
Slot 1 PRB allocation hex value: + + Same allocation as slot 0 +
Bit string (PRB 0 first): + +
Allocation value format: + + + +
Resulting allocated PDSCH resources (for given number of layers): +
+
+
+ +
+ +
+ + + diff --git a/LTE/resource_grid_6sym.png b/LTE/resource_grid_6sym.png new file mode 100644 index 0000000..5bf009d Binary files /dev/null and b/LTE/resource_grid_6sym.png differ diff --git a/LTE/resource_grid_7sym.png b/LTE/resource_grid_7sym.png new file mode 100644 index 0000000..f345eda Binary files /dev/null and b/LTE/resource_grid_7sym.png differ diff --git a/LTE/resource_grid_hdr.png b/LTE/resource_grid_hdr.png new file mode 100644 index 0000000..6822d74 Binary files /dev/null and b/LTE/resource_grid_hdr.png differ diff --git a/README.md b/README.md new file mode 100644 index 0000000..86eb079 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +Repository for [PEW's Corner](https://pewscorner.github.io). + +[License](LICENSE.txt). diff --git a/RollingStone.html b/RollingStone.html new file mode 100644 index 0000000..b939aeb --- /dev/null +++ b/RollingStone.html @@ -0,0 +1,539 @@ + + + + + + + +Rolling Stone + + + + + + + +
+ +

Rolling Stone

+ +
+ERROR! Your browser doesn't support the HTML5 canvas element! +
+ +
+This is javascript drawing on an HTML5 canvas in real time. +
+ +
+ + + diff --git a/anaclock.html b/anaclock.html new file mode 100644 index 0000000..2956f36 --- /dev/null +++ b/anaclock.html @@ -0,0 +1,165 @@ + + + + + + + +Analog Clock + + + + + + + +
+ +

Analog Clock

+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+This shows parts of a single static PNG image. +The parts shown depend on the current time. +
+ +
+ + + \ No newline at end of file diff --git a/anaclock.png b/anaclock.png new file mode 100644 index 0000000..3cf2fea Binary files /dev/null and b/anaclock.png differ diff --git a/barcodes/code128_barcode_generator.html b/barcodes/code128_barcode_generator.html new file mode 100644 index 0000000..d7cf317 --- /dev/null +++ b/barcodes/code128_barcode_generator.html @@ -0,0 +1,676 @@ + + + + + + + +Code 128 Barcode Generator + + + + + + +
+ +

Code 128 Barcode Generator

+ +
+

+Supported characters/codes: +

+ + +Code set selection: +
+Input text: + +
+ +
+ +
+
+ERROR! Your browser doesn't support the HTML5 canvas element! +Download PNG +Download SVG +
+
+
+ +
+Raw codes:
+ +
+ +
+ + + diff --git a/barcodes/ean_barcode_generator.html b/barcodes/ean_barcode_generator.html new file mode 100644 index 0000000..af7b1d1 --- /dev/null +++ b/barcodes/ean_barcode_generator.html @@ -0,0 +1,343 @@ + + + + + + + +EAN Barcode Generator + + + + + + +
+ +

EAN-13 Barcode Generator

+ +
+Input 12-digit number (excl. final check digit): + + +
+ +
+
+ERROR! Your browser doesn't support the HTML5 canvas element! +Download PNG +Download SVG +
+
+
+ +
+ + + diff --git a/barcodes/index.html b/barcodes/index.html new file mode 100644 index 0000000..d052870 --- /dev/null +++ b/barcodes/index.html @@ -0,0 +1,27 @@ + + + + + + + +Barcodes + + + + + +
+ +

Barcodes

+ +
+QR code generator +EAN-13 barcode generator +Code 128 barcode generator +
+ +
+ + + diff --git a/barcodes/qrcode_generator.html b/barcodes/qrcode_generator.html new file mode 100644 index 0000000..948b7ee --- /dev/null +++ b/barcodes/qrcode_generator.html @@ -0,0 +1,1423 @@ + + + + + + + +QR Code Generator + + + + + + +
+ +

QR Code Generator

+ +
+Input text: + +
+Version (size): + +
+Error correction level: + +
+ +
+
+ +
+
+ERROR! Your browser doesn't support the HTML5 canvas element! +Download PNG +Download SVG +
+
+
+ +
+ + + diff --git a/calendar.html b/calendar.html new file mode 100644 index 0000000..02cf0b1 --- /dev/null +++ b/calendar.html @@ -0,0 +1,709 @@ + + + + + + + +Kalender + + + + + + + +
+ +

Kalender

+ +
+
+ +
+ + + diff --git a/calendar2.html b/calendar2.html new file mode 100644 index 0000000..81401e7 --- /dev/null +++ b/calendar2.html @@ -0,0 +1,743 @@ + + + + + + + +Kalender + + + + + + + +
+ +

Kalender

+ +
+
+ +
+ + + diff --git a/chinese_year.html b/chinese_year.html new file mode 100644 index 0000000..bfe55f6 --- /dev/null +++ b/chinese_year.html @@ -0,0 +1,677 @@ + + + + + + + +Chinese Year + + + + + + + +
+ +

Chinese Year

+ +
+ +
+
+ + + + + + + + + + + + + + + + + + +
Rat
+
Ox
+
Tiger
+
Rabbit
+
Dragon
+
Snake
+
Horse
+
Goat/
Sheep
+
Monkey
+
Rooster
+
Dog
+
Pig
+
+
+ + + + + + + + + + + + + + + + + + +
Yang
Wood
+
Yin
Wood
+
Yang
Fire
+
Yin
Fire
+
Yang
Earth
+
Yin
Earth
+
Yang
Metal
+
Yin
Metal
+
Yang
Water
+
Yin
Water
+
+ + + + + + + +
+ + + + + +
+  
+  
+
+ +
+
+
+
+
+
+ +
+ + + + diff --git a/dancing_snowman.html b/dancing_snowman.html new file mode 100644 index 0000000..36b9531 --- /dev/null +++ b/dancing_snowman.html @@ -0,0 +1,41 @@ + + + + + + + +Dancing Snowman + + + + + + +
+ +

Dancing Snowman

+ +
+ +
+ +
+This is a GIF file containing an animation. +Each frame of the animation was drawn in Google Sketchup by a Ruby script. +
+ +
+ + + \ No newline at end of file diff --git a/dancing_snowman_anim.gif b/dancing_snowman_anim.gif new file mode 100644 index 0000000..e4440cb Binary files /dev/null and b/dancing_snowman_anim.gif differ diff --git a/date_converter.html b/date_converter.html new file mode 100644 index 0000000..66cef73 --- /dev/null +++ b/date_converter.html @@ -0,0 +1,167 @@ + + + + + + + +Date Converter + + + + + + + + +
+ +

Date Converter

+ +
+ +

Date (yyyy-mm-dd)

+
+
+
+ +

+ +

Week-year and week (yyyy-ww)

+
+
+
+ +

+ +

First day of week

+
+
+ +
+ +
+ + + diff --git a/devanagari_digits.gif b/devanagari_digits.gif new file mode 100644 index 0000000..ca320ad Binary files /dev/null and b/devanagari_digits.gif differ diff --git a/digiclock.html b/digiclock.html new file mode 100644 index 0000000..e43a7ef --- /dev/null +++ b/digiclock.html @@ -0,0 +1,275 @@ + + + + + + + +Digital Clock + + + + + + +
+ +

Digital Clock

+ +
+
+ +
+
+ +
+This is javascript changing the colors of HTML DIV borders. +
+ +
+ + + \ No newline at end of file diff --git a/doppler_calc.html b/doppler_calc.html new file mode 100644 index 0000000..625645c --- /dev/null +++ b/doppler_calc.html @@ -0,0 +1,535 @@ + + + + + + + +Doppler Shift Calculator + + + + + + + +
+ +

Doppler Shift Calculator

+ +
+ + + +

Transmitter velocity

+
+
Note: This velocity is relative to the medium and towards the receiver.
+ +

Receiver velocity

+
+
Note: This velocity is relative to the medium and towards the transmitter.
+ +

Wave velocity

+
+Use velocity of + (m/s). +
+
Note: This velocity is relative to the medium.
+
Note: Use the same units for all velocities.
+ +

Resulting Doppler shift

+
+
Note: This is the ratio of the observed frequency shift to the original frequency.
+ +
+ +
+ +

Example cases

+
+ERROR! Your browser doesn't support the HTML5 canvas element! +
+ +
+ +
+ + + diff --git a/doppler_theory/doc.html b/doppler_theory/doc.html new file mode 100644 index 0000000..edfd49d --- /dev/null +++ b/doppler_theory/doc.html @@ -0,0 +1,1041 @@ + + + + + + + +Doppler Shift Theory + + + + + + +
+ +

Doppler Shift Theory

+ +
+ +

Contents

+ +
+ +

Introduction

+ +

In this document formulas are derived for the Doppler shift in +various cases.

+ +
+ +

Stationary Transmitter, Moving Receiver

+ +

Assume we have a medium in which waves are transmitted with a +frequency of f0 and propagate with velocity vw relative +to the medium. If the wave transmitter is at rest relative to the medium, the +wavelength everywhere in the medium will be:

+ +

Equation 1:

+ + + + + + + + + + + + + + + + + + + + + + + + + +

If the receiver is moving with velocity vRx +relative to the medium and in the direction of the transmitter, then the receiver's +velocity relative to the waves will be:

+ +

Equation 2:

+ + + + + + + + + + + + + + + + + + + + + + + +

Thus, the received waves will have the apparent frequency:

+ +

Equation 3:

+ + + + + + + + + + + + + + + + + + + + +

By substituting Equation 1 and Equation 2 into Equation 3, we obtain the following expression for the apparent frequency:

+ +

Equation 4:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

This can be rewritten to express the relative Doppler shift:

+ +

Equation 5:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Keep in mind that the velocities vw and vRx +are relative to the medium.

+ +
+ +

Moving Transmitter, Stationary Receiver

+ +

Now let's assume that the transmitter is moving with +velocity vTx relative to the medium and towards the receiver, which +is at rest relative to the medium. The wavelength in front of the transmitter +will be reduced by the distance it travels during one wave period T0 +(=1/f0), so the wavelength becomes:

+ +

Equation 6:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

The received waves will therefore have the apparent +frequency:

+ +

Equation 7:

+ + + + + + + + + + + + + + + + + + + + + +

By substituting Equation 6 into Equation 7, we obtain the following expression for the apparent frequency:

+ +

Equation 8:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

And the relative Doppler shift becomes:

+ +

Equation 9:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

When vTx is small compared to vw, Equation +8 and Equation 9 become similar to the stationary transmitter case (Equation 4 and Equation 5) as shown below:

+ +

Equation 10:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Equation 11:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

Moving Transmitter, Moving Receiver

+ +

If both the transmitter and the receiver are moving relative +to the medium and towards each other with the velocities vTx and vRx, +respectively, relative to the medium, then the wavelength λ will be +described by Equation 6, and the receiver's velocity v relative to the waves will be described by Equation 2. For the receiver the waves will therefore have the apparent frequency:

+ +

Equation 12:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

and the relative Doppler shift:

+ +

Equation 13:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

When vRx and vTx are small compared to vw, +these equations can be simplified to:

+ +

Equation 14:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Equation 15:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Note that vTx and vRx should have the +same sign when they are pointed in opposite directions. vw should always +be positive.

+ +
+ +

Electromagnetic Waves

+ +

For electromagnetic waves it is not necessary to relate the +motion of the transmitter, receiver, and waves to a medium. Only the velocities +relative to the receiver are important. If the velocity vTx of the +transmitter relative to the receiver (and towards it) is much smaller than the velocity +vw of the waves (which is 299,792,458 m/s in a vacuum), we can reuse Equation 10 +and Equation 11, regardless of whether the receiver is moving or not:

+ +

Equation 16:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Equation 17:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Remember that in this case vTx is the transmitter's velocity relative to the +receiver - not relative to the medium. Equation 16 and Equation 17 could of course also +be obtained by setting vRx=0 in Equation 14 and Equation 15, respectively.

+ +

If the transmitter velocity vTx is not small compared to the electromagnetic +wave velocity vw, relativistic effects (according to +Einstein's Theory of Relativity) +will be non-negligible and need to be taken into account. In this case, +time dilation +will reduce the transmitted frequency f0 in Equation 8 by the Lorentz factor γ +when observed from the receiver's frame of reference (before accounting for the Doppler shift). +The Lorentz factor is determined by the transmitter's velocity vTx relative to the +receiver as follows:

+ +

Equation 18:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Replacing f0 in Equation 8 with the time dilated value f0/γ, +we get the combined result of time dilation and Doppler shift:

+ +

Equation 19:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Equation 20:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(vTx is the transmitter's velocity relative to the receiver and towards the receiver, +and vw is the electromagnetic wave velocity).

+ +
+ +
+ + + diff --git a/event_logger.html b/event_logger.html new file mode 100644 index 0000000..4153db6 --- /dev/null +++ b/event_logger.html @@ -0,0 +1,238 @@ + + + + + + + +Key/Mouse/Touch Event Logger + + + + + + + +
+ +

Key/Mouse/Touch Event Logger

+ +
+ + + Input:
+
+ +

Events logged:

+ +

+ + Results:
+ +
+ +
+ + + + diff --git a/eyes/index.html b/eyes/index.html new file mode 100644 index 0000000..b1abc85 --- /dev/null +++ b/eyes/index.html @@ -0,0 +1,250 @@ + + + + + + + +Eyes + + + + + + + +
+ +

Eyes

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + \ No newline at end of file diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000..524c6d5 Binary files /dev/null and b/favicon.ico differ diff --git a/feedback.html b/feedback.html new file mode 100644 index 0000000..3623ef0 --- /dev/null +++ b/feedback.html @@ -0,0 +1,57 @@ + + + + + + + +Feedback + + + + + + + +
+ +

Feedback

+ +
+
+ +
+ + + diff --git a/fullscreencolor.html b/fullscreencolor.html new file mode 100644 index 0000000..f90acc1 --- /dev/null +++ b/fullscreencolor.html @@ -0,0 +1,208 @@ + + + + + + + +Full-Screen Color + + + + + + + +
+ +

Full-Screen Color

+ +
+ + + + + + + +
+

Click here to enter/exit full-screen mode

+
+ +
+ +
+ + + diff --git a/googlec9d6ceb65c9afaf6.html b/googlec9d6ceb65c9afaf6.html new file mode 100644 index 0000000..370cf03 --- /dev/null +++ b/googlec9d6ceb65c9afaf6.html @@ -0,0 +1 @@ +google-site-verification: googlec9d6ceb65c9afaf6.html \ No newline at end of file diff --git a/holidays.html b/holidays.html new file mode 100644 index 0000000..41ecb2a --- /dev/null +++ b/holidays.html @@ -0,0 +1,328 @@ + + + + + + + +Danske Helligdage + + + + + + + +
+ +

+ +
+ + +
+ +
+
+ +
+
+ +
+ + + diff --git a/index.html b/index.html new file mode 100644 index 0000000..cef2eb1 --- /dev/null +++ b/index.html @@ -0,0 +1,88 @@ + + + + + + + +PEW's Corner + + + + + + +
+ +

PEW's Corner

+ +

Tools

+ +
+Danish calendar +Danish holidays +Date converter +Chinese year +Music synthesizer +Programmer's number converter +Multi-cultural number converter +Text input assistant and converter +Doppler shift calculator +I/Q signal mismatch calculator +Thai language +Japanese language +Random code generator +Necktie knots +LTE stuff +Key/mouse/touch event logger +Barcodes +Full-screen color +Screen size converter +Mouse button test +
+ +

Docs

+ +
+Programming languages +Doppler shift theory +I/Q signal mismatch theory +Relativity theory +
+ +

Misc

+ +
+Platonic solids +Waveforms +Dancing snowman +Rolling stone +Giant kangaroo +Puzzle +Analog clock +Digital clock +Eyes +
+ +
+ + + diff --git a/iq_mismatch_calc.html b/iq_mismatch_calc.html new file mode 100644 index 0000000..7646c39 --- /dev/null +++ b/iq_mismatch_calc.html @@ -0,0 +1,405 @@ + + + + + + + +I/Q Signal Mismatch Calculator + + + + + + + +
+ +

I/Q Signal Mismatch Calculator

+ +
+ +

Amplitude mismatch

+
dB
+
+
Note: This is Q amplitude / I amplitude, converted to dB.
+ +

Phase mismatch

+
°
+
+
Note: This is Q phase - (I phase - 90°).
+ +

Resulting unwanted signal

+
dB
+
+
Note: This is magnitude of unwanted spectral component (at frequency -f) relative to wanted component (at frequency f), in dB.
+ +
+ +
+ +
+
+
I
+
Q
+
+
+
+ +
+
+
f
+
mag(dB)
+
+
+
+
+ +
+ +
+ + + diff --git a/iq_mismatch_theory/doc.html b/iq_mismatch_theory/doc.html new file mode 100644 index 0000000..04ac12f --- /dev/null +++ b/iq_mismatch_theory/doc.html @@ -0,0 +1,183 @@ + + + + + + + +I/Q Signal Mismatch Theory + + + + + + +
+ +

I/Q Signal Mismatch Theory

+ +
+ +

Introduction

+ +

This document describes the impact of amplitude and phase +mismatch in an I/Q (in-phase/quadrature-phase) signal pair. The result of a mismatch is an +unwanted spectral component at the negative signal frequency.

+ +
+ +

Theory

+ +

An ideal sinusoidal I/Q signal pair with no amplitude or +phase mismatch can be represented by the following complex function:

+ +

Equation 1:

+ +

y(t)   =   A exp(i(ωt + φ))   =   +A cos(ωt + φ)   +   i A sin(ωt + φ)

+ +

The real part (the first term in the second expression) of +y(t) is the I signal, and the imaginary part (the second term except the "i") +is the Q signal. ω, A, and φ are the angular frequency, amplitude and +phase, respectively.

+ +

If an amplitude and phase mismatch is introduced, the +function becomes:

+ +

Equation 2:

+ +

y(t)   =   A cos(ωt + φ)   +   +i α A sin(ωt + φ + ε)

+ +

Here, A and φ are the amplitude and phase of the I +signal, α is the amplitude mismatch (the ratio of Q amplitude to I +amplitude), and ε is the phase mismatch (the Q phase plus 90 degrees minus the I +phase). For α=0 dB (α=1) and ε=0 degrees there is no mismatch.

+ +

By rewriting Equation 2 we can split the mismatched I/Q signal into its spectral components:

+ +

Equation 3:

+ +

y(t)   =   0.5 (1 + α exp(i ε)) A exp(i(ωt + φ)) +  +   0.5 (1 - α exp(-i ε)) A exp(-i(ωt + φ))

+ +

The first term is the wanted signal (including both I and Q +parts) - a pure complex sinusoid at the frequency ω. The second term is an +unwanted signal at the negative frequency -ω. The wanted signal is simply +the ideal I/Q signal from Equation 1 multiplied by a complex constant, which modifies the amplitude and phase (here, the I and Q parts are modified equally).

+ +

From Equation 3 the ratio of the unwanted signal magnitude to the wanted signal magnitude can be found:

+ +

Equation 4:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

Conclusion

+ +

It has been shown that the introduction of an amplitude +and/or phase mismatch between the I and Q signals causes an unwanted spectral +component to appear at the mirror frequency. Also, the amplitude and phase of +the wanted spectral component will change. Equation 3 quantifies these effects.

+ +
+ +
+ + + diff --git a/jap_digits.gif b/jap_digits.gif new file mode 100644 index 0000000..7b4eec3 Binary files /dev/null and b/jap_digits.gif differ diff --git a/japanese/hiragana.html b/japanese/hiragana.html new file mode 100644 index 0000000..400edbe --- /dev/null +++ b/japanese/hiragana.html @@ -0,0 +1,96 @@ + + + + + + + +Hiragana + + + + + + + +
+ +

Hiragana

+ +
+
+ +
+ + + diff --git a/japanese/index.html b/japanese/index.html new file mode 100644 index 0000000..a9910bb --- /dev/null +++ b/japanese/index.html @@ -0,0 +1,36 @@ + + + + + + + +Japanese Language + + + + + +
+ +

Japanese Language

+ +
+Text input assistant and converter +Pronunciation guide +Translation practice: nouns +Translation practice: verbs +Translation practice: adjectives +Translation practice: numbers +Translation practice: dates +Translation practice: time +Translation practice: relative time +Character reading practice: Hiragana +Character reading practice: Katakana +Relative positions +
+ +
+ + + diff --git a/japanese/katakana.html b/japanese/katakana.html new file mode 100644 index 0000000..5e06636 --- /dev/null +++ b/japanese/katakana.html @@ -0,0 +1,96 @@ + + + + + + + +Katakana + + + + + + + +
+ +

Katakana

+ +
+
+ +
+ + + diff --git a/japanese/pronunciation.html b/japanese/pronunciation.html new file mode 100644 index 0000000..54ff794 --- /dev/null +++ b/japanese/pronunciation.html @@ -0,0 +1,102 @@ + + + + + + + +Japanese Pronunciation Guide + + + + + + + +
+ +

Japanese Pronunciation Guide

+ +
+ + + + + + + + + + + + +
e + +Pronounced like the first part of the "ay"-sound in "say", i.e. without the final "y"-sound. +The "e" in "get" is also a fair approximation. +The German "ä" and the Danish "æ" are better approximations. + +
ei/ee + +Pronounced as a Japanese "e" (see above), but twice as long in duration. +Note that in hiragana text this long vowel often occurs when a syllable (e.g. "ke") is +followed by an "i". In such cases the "i" is misleading and should not be pronounced as an "i" - +it only serves to prolong the "e" sound. + +
i + +Pronounced like the "ee" in "feet", but short in duration. +It is NOT pronounced like the "i" in "him". +Often the "i" is not pronounced in the syllable "shi" when it is followed by another syllable. + +
o + +Pronounced like the first part of the "o"-sound in "old", i.e. without the final "u"-sound. +The Danish "å" is also a good approximation. + +
ou/oo + +Pronounced as a Japanese "o" (see above), but twice as long in duration. +Note that in hiragana text this long vowel often occurs when a syllable (e.g. "ko") is +followed by a "u". In such cases the "u" is misleading and should not be pronounced as a "u" - +it only serves to prolong the "o" sound. + +
g + +Pronounced like the "g" in "get" when it occurs at the beginning of words.
+Pronounced like the "ng" in "sing" in all other cases.
+Some people always pronounce it like the "g" in "get". + +
n + +Pronounced like "n" at the beginning of syllables, +or when followed by any of the consonants ch, d, j, n, r, t, z, and sometimes s(h) +(even when these consonants belong to the next word) - +note that these consonants are all produced with the tip of the tongue (except s(h)).
+Pronounced like "m" when followed by m, b, or p (these consonants are all produced with the lips).
+Pronounced like the "ng" in "sing" in all other cases. + +
r + +Pronounced almost like the "rd" in "weirdo" (with an American-style "r"). + +
z + +Pronounced like "dz" at the beginning of words.
+Pronounced like "z" in all other cases. + +
+ +
+ +
+ + + diff --git a/japanese/relative_positions.html b/japanese/relative_positions.html new file mode 100644 index 0000000..6893f1f --- /dev/null +++ b/japanese/relative_positions.html @@ -0,0 +1,86 @@ + + + + + + + +Relative Positions + + + + + + + +
+ +

Relative Positions

+ +
+ + + + + + + + + +
Front side + 前 + まえ + +
Rear side + 後ろ + うしろ + +
Left side + 左 + ひだり + +
Right side + 右 + みぎ + +
Top side + 上 + うえ + +
Bottom side + 下 + した + +
Inside + 中 + なか + +
+ +
+ +
+ + + diff --git a/japanese/test_adjs.html b/japanese/test_adjs.html new file mode 100644 index 0000000..0968634 --- /dev/null +++ b/japanese/test_adjs.html @@ -0,0 +1,147 @@ + + + + + + + +Japanese Translation Practice: Adjectives + + + + + + + +
+ +

Japanese Translation Practice:
Adjectives

+ +
+ +

Task

+
+ +

Your input

+ + + + +
+ +
+ + + diff --git a/japanese/test_dates.html b/japanese/test_dates.html new file mode 100644 index 0000000..87aa36f --- /dev/null +++ b/japanese/test_dates.html @@ -0,0 +1,106 @@ + + + + + + + +Japanese Translation Practice: Dates + + + + + + + +
+ +

Japanese Translation Practice:
Dates

+ +
+ +

Task

+
+ +

Your input

+ + + + +
+ +
+ + + diff --git a/japanese/test_hiragana.html b/japanese/test_hiragana.html new file mode 100644 index 0000000..8815303 --- /dev/null +++ b/japanese/test_hiragana.html @@ -0,0 +1,204 @@ + + + + + + + +Japanese Character Reading Practice: Hiragana + + + + + + + +
+ +

Japanese Character Reading Practice:
Hiragana

+ +
+ +

Task

+
+ +

Your input

+ + + + + +
+ +
+ + + diff --git a/japanese/test_katakana.html b/japanese/test_katakana.html new file mode 100644 index 0000000..c6f8102 --- /dev/null +++ b/japanese/test_katakana.html @@ -0,0 +1,197 @@ + + + + + + + +Japanese Character Reading Practice: Katakana + + + + + + + +
+ +

Japanese Character Reading Practice:
Katakana

+ +
+ +

Task

+
+ +

Your input

+ + + + + +
+ +
+ + + diff --git a/japanese/test_nouns.html b/japanese/test_nouns.html new file mode 100644 index 0000000..015de9e --- /dev/null +++ b/japanese/test_nouns.html @@ -0,0 +1,170 @@ + + + + + + + +Japanese Translation Practice: Nouns + + + + + + + +
+ +

Japanese Translation Practice:
Nouns

+ +
+ +

Task

+
+ +

Your input

+ + + + +
+ +
+ + + diff --git a/japanese/test_numbers.html b/japanese/test_numbers.html new file mode 100644 index 0000000..97b8dd6 --- /dev/null +++ b/japanese/test_numbers.html @@ -0,0 +1,125 @@ + + + + + + + +Japanese Translation Practice: Numbers + + + + + + + +
+ +

Japanese Translation Practice:
Numbers

+ +
+ +

Task

+
+ +

Your input

+ + +
+ +Set number of digits:  + +
+ +
+ + + diff --git a/japanese/test_rel_time.html b/japanese/test_rel_time.html new file mode 100644 index 0000000..88963b3 --- /dev/null +++ b/japanese/test_rel_time.html @@ -0,0 +1,140 @@ + + + + + + + +Japanese Translation Practice: Relative Time + + + + + + + +
+ +

Japanese Translation Practice:
Relative Time

+ +
+ +

Task

+
+ +

Your input

+ + + + +
+ +
+ + + diff --git a/japanese/test_time.html b/japanese/test_time.html new file mode 100644 index 0000000..6772cab --- /dev/null +++ b/japanese/test_time.html @@ -0,0 +1,101 @@ + + + + + + + +Japanese Translation Practice: Time + + + + + + + +
+ +

Japanese Translation Practice:
Time

+ +
+ +

Task

+
+ +

Your input

+ + + + +
+ +
+ + + diff --git a/japanese/test_verbs.html b/japanese/test_verbs.html new file mode 100644 index 0000000..1ddbd12 --- /dev/null +++ b/japanese/test_verbs.html @@ -0,0 +1,274 @@ + + + + + + + +Japanese Translation Practice: Verbs + + + + + + + +
+ +

Japanese Translation Practice:
Verbs

+ +
+ +

Task

+
+ +

Your input

+ + + + + +
+ +
+ + + diff --git a/julegaveplan.html b/julegaveplan.html new file mode 100644 index 0000000..799edfb --- /dev/null +++ b/julegaveplan.html @@ -0,0 +1,922 @@ + + + + + + +Julegaveplan + + + + + + +

Julegaveplan for

+ + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + +
+ + + + +
+ +

mulige løsninger

+ + + + + + diff --git a/mouse_button_test.html b/mouse_button_test.html new file mode 100644 index 0000000..51e6c5d --- /dev/null +++ b/mouse_button_test.html @@ -0,0 +1,99 @@ + + + + + + + +Mouse Button Test + + + + + + + +
+ +

Mouse Button Test

+ +
+ +

Click left/middle/right mouse button in this box

+ +

Number of button press/release events (left, middle, right):

+ +
+ +
+ + + diff --git a/music_synth.html b/music_synth.html new file mode 100644 index 0000000..04e75a1 --- /dev/null +++ b/music_synth.html @@ -0,0 +1,547 @@ + + + + + + + +Music Synthesizer + + + + + + + +
+ +

Music Synthesizer

+ +
+ +
+ + + +
+ +
+Syntax: + +
+ +
+ + + diff --git a/necktie.html b/necktie.html new file mode 100644 index 0000000..1f1b576 --- /dev/null +++ b/necktie.html @@ -0,0 +1,196 @@ + + + + + + + +Necktie Knots + + + + + + +
+ +

Necktie Knots

+ +
+
+ + + + + + + + + + + + + + + + Four-in-hand + + + + + + + + + + + + + + + + + (Full) Windsor + + + +
+
+ +
+ + + diff --git a/number_converter.html b/number_converter.html new file mode 100644 index 0000000..1efed6d --- /dev/null +++ b/number_converter.html @@ -0,0 +1,565 @@ + + + + + + + +Multi-Cultural Number Converter + + + + + + + + +
+ +

Multi-Cultural Number Converter

+ +
+ +

Western (arabic) number

+
+
+ +

+ +

Roman number

+
+
+ +

+ +

Thai number

+
+
+
+
+
+
Click to add character:
+
+
+ +

+ +

Japanese number

+
+
+
+
+
+
Click to add character:
+
+
+ +

+ +

Indian (Devanagari) number

+
+
+
+
+
+
Click to add character:
+
+
+ +
+ +
+ + + diff --git a/page.js b/page.js new file mode 100644 index 0000000..882cb90 --- /dev/null +++ b/page.js @@ -0,0 +1,550 @@ +"use strict"; + +var genericPageSetup = +{ + debug: false, + + script_version: '7', + style_version: undefined, + + // A web page can add extra menu buttons to this array before the page load event + extra_menu_buttons: [], + + // Page URL with and without the hash/query part + this_page_url: undefined, + this_page_noarg_url: undefined, + + // Page header related variables + header_elem: undefined, + header_height: undefined, + has_scrolled: false, + last_scroll_pos: 0, + header_is_hidden: false, + + // Page menu related variables + menu_group_elem: undefined, + menu_is_open: false, + pending_menu_action: undefined, + // Named history state values + menu_closed_history_state: null, + menu_open_history_state: 1, + // Menu button DOM elements and visibility states + update_pg_addr_menu_button_info: + { + id: 'update_pg_addr_button', + button_elem: undefined, + is_visible: false, + }, + reset_pg_addr_menu_button_info: + { + id: 'reset_pg_addr_button', + button_elem: undefined, + is_visible: false, + }, + + // Relative URL path from the current page to the web site root (the location of this script is used as the root); + // includes a trailing '/' unless empty (meaning that the current page is in the root) + rel_path_to_root: (function pg_rel_path_to_root() + { + var scripts = document.getElementsByTagName('script'); + var re = new RegExp('^(.*?[^/])(?:/(?!/)|$)(.*)'); + var matches = re.exec(scripts[scripts.length - 1].src); + var this_script_url_parts = [matches[1]].concat(matches[2].split('/')).slice(0, -1); + matches = re.exec(location.href); + var this_page_url_parts = [matches[1]].concat(matches[2].split('/')).slice(0, -1); + var smallest_nbr_parts = Math.min(this_script_url_parts.length, this_page_url_parts.length); + for (var nbr_common_parts = 0; + nbr_common_parts < smallest_nbr_parts && this_script_url_parts[nbr_common_parts] == this_page_url_parts[nbr_common_parts]; + nbr_common_parts++); + var nbr_backout_levels = (nbr_common_parts == 0 ? 0 : this_page_url_parts.length - nbr_common_parts); + var rel_path = + new Array(nbr_backout_levels + 1).join('../') + + this_script_url_parts.slice(nbr_common_parts).join('/'); + if (rel_path.length > 0 && rel_path.slice(-1) != '/') + rel_path += '/'; + return rel_path; + })(), + + // Handles the page load event for the purpose of creating a page header and setting up related event handlers + init: function pg_init() + { + this.style_version = getComputedStyle(document.documentElement).getPropertyValue('--style-version').trim() || '?'; + if (this.debug) console.log('Page loaded (script v' + this.script_version + ', style v' + this.style_version + ')'); + this.refresh_page_info(); + // Disable the browser's automatic restoring of the scroll position when navigating the history (sometimes it + // doesn't work, and sometimes it gets in the way) - we'll handle this ourselves + history.scrollRestoration = 'manual'; + this.make_header(); + var that = this; + window.addEventListener('scroll', function(){that.scroll_handler()}, false); + setInterval(function(){that.time_handler()}, 200); + var nav_event_handler = function(e){that.navigation_handler(e)}; + // Register a handler for the pageshow event (comes after the load event - or without the load event - when + // navigating from a different page) + window.addEventListener('pageshow', nav_event_handler, false); + // Register a handler for the popstate event (comes when navigating from a different history entry for the same + // page - and for some older browsers it also comes after the pageshow event when navigating from a different + // page) + window.addEventListener('popstate', nav_event_handler, false); + }, + + refresh_page_info: function pg_refresh_page_info() + { + this.this_page_url = location.href; + this.this_page_noarg_url = this.this_page_url.split('#')[0].split('?')[0]; + this.set_menu_button_visible(this.reset_pg_addr_menu_button_info, + this.this_page_url != this.this_page_noarg_url); + }, + + // Opens the page menu + open_menu: function pg_open_menu() + { + this.menu_is_open = true; + this.menu_group_elem.style.display = 'block'; + if (this.debug) console.log('Adding and going to menu-open state'); + // Create and go to the menu-open history state + history.pushState({state: this.menu_open_history_state, scroll: window.pageYOffset}, ''); + }, + + // Closes the page menu if it is open, and ensures that all state reflects that it is closed + close_menu: function pg_close_menu() + { + this.menu_is_open = false; + this.menu_group_elem.style.display = 'none'; + if (history.state.state == this.menu_open_history_state) + { + // We're in the menu-open history state, so go back to the menu-closed history state + if (this.debug) console.log('Going back'); + history.back(); + } + }, + + update_pg_addr_menu_button: [ + 'update_pg_addr_button', + 'Update page address with setup', + 'genericPageSetup.update_page_addr_with_settings()' + ], + + reset_pg_addr_menu_button: [ + 'reset_pg_addr_button', + 'Reset page address', + 'genericPageSetup.reset_page_addr()' + ], + + feedback_menu_button: [ + 'feedback_button', + 'Feedback', + 'genericPageSetup.open_feedback_form()', + ], + + // Performs the action for the 'Update page address with setup' menu button + update_page_addr_with_settings: function pg_update_page_addr_with_settings() + { + var url_with_settings = this.make_url_from_settings(); + if (this.debug) console.log('update_pg_addr_with_settings: ' + url_with_settings); + history.replaceState(history.state, '', url_with_settings); + this.refresh_page_info(); + }, + + // Performs the action for the 'Reset page address' menu button + reset_page_addr: function pg_reset_page_addr() + { + history.replaceState(history.state, '', this.this_page_noarg_url); + this.refresh_page_info(); + }, + + // Performs the action for the 'Feedback' menu button + open_feedback_form: function pg_open_feedback_form() + { + var info = this.this_page_url + ' (modified ' + document.lastModified + + ', script v' + this.script_version + + ', style v' + this.style_version + ')\n'; + window.open(this.rel_path_to_root + 'feedback.html#' + encodeURIComponent(info), '_blank'); + }, + + // Makes the specified menu button visible or invisible as specified, or applies the previously set visibility if + // 'visible' is not true or false + set_menu_button_visible: function pg_set_menu_button_visible(button_info, visible) + { + if (this.debug) console.log('Requested visibility of ' + button_info.id + ': ' + visible); + if (visible === true || visible === false) + { + button_info.is_visible = visible; + } + if (button_info.button_elem) + { + if (this.debug) console.log('Setting visibility of ' + button_info.id + ' to ' + button_info.is_visible); + button_info.button_elem.style.display = button_info.is_visible ? 'block' : 'none'; + } + }, + + // Handles click events on menu item buttons + menu_item_click_handler: function pg_menu_item_click_handler(event) + { + // Prepare the menu item action for execution; the sequence of events is: + // 1. The click event triggers this handler which prepares the action. + // 2. The same click event then triggers the click handler on the underlying menu_group_elem. + // 3. The menu_group_elem click handler closes the menu and goes back to the menu-closed history state. + // 4. This triggers the history popstate event which triggers the navigation_handler. + // 5. The navigation_handler executes the pending action prepared in step 1. + // This sequence ensures that the browser is back in the normal menu-closed state before the action is executed. + this.pending_menu_action = event.target.dataset.action; + }, + + // Handles key events when the menu is open, for the purpose of closing the menu when the Esc key is pressed + menu_key_down_handler: function pg_menu_key_down_handler(event) + { + // This handler is attached to the page body element and receives events in the capturing phase (not the usual + // bubbling phase which comes after the capturing phase), so it receives events before anything else on the page + if (this.menu_is_open && event.key == 'Escape') + { + if (this.debug) console.log('Esc pressed'); + this.close_menu(); + // Prevent the key event from reaching any other element on the page + event.stopPropagation(); + } + }, + + // Handles navigation events for the purpose of closing the menu, executing a pending menu action if any, and + // generally avoiding the menu-open history state (which should never be entered on user navigation) + navigation_handler: function pg_navigation_handler(event) + { + // This navigation handler is called on every navigation event (pageshow or popstate) triggered by the user or + // by this script, but not on history.pushState which does not trigger any events + this.refresh_page_info(); + if (history.state == null) + { + history.replaceState({state: this.menu_closed_history_state, scroll: window.pageYOffset}, ''); + } + else if (history.state.state == this.menu_closed_history_state) + { + var that = this; + var old_scroll = history.state.scroll; + setTimeout(function(){that.scroll_and_hide_header(old_scroll)}); + } + var pending_menu_action = this.pending_menu_action; + this.pending_menu_action = undefined; + if (this.debug) console.log('nav_hndlr from ' + event.type + ': (' + history.state.state + ', ' + history.state.scroll + ') ' + + pending_menu_action + ' ' + this.this_page_url); + // Ensure that the menu is closed in all cases where the navigation handler is called (the only case where we + // want the menu to stay open is when it is deliberately opened via history.pushState, and that will not trigger + // any call to the navigation handler) + this.close_menu(); + if (pending_menu_action) + { + // There's a pending action from a menu item selected by the user, so execute that action now + setTimeout(function(){eval(pending_menu_action)}, 0); + } + }, + + // Handles scroll events for the purpose of showing or hiding the header depending on the scroll direction (most of + // this functionality is implemented in the timer_handler to avoid degrading the browser's scroll performance) + scroll_handler: function pg_scroll_handler() + { + this.has_scrolled = true; + }, + + // Handles regular timer ticks for the purpose of showing/hiding the header if scroll events have occurred since the + // last tick, and for storing the scroll position in the current history entry for later restoration when navigating + // back to this history entry + time_handler: function pg_time_handler() + { + if (this.has_scrolled) + { + this.has_scrolled = false; + var new_scroll_pos = window.pageYOffset; + history.replaceState({state: history.state.state, scroll: new_scroll_pos}, ''); + if (!this.menu_is_open && !this.header_is_hidden && + new_scroll_pos > this.last_scroll_pos && new_scroll_pos > this.header_height) + { + // The header is visible, the menu is closed, and the page has scrolled down beyond the height of the + // header, so hide the header + this.header_elem.className = 'hidden'; + this.header_is_hidden = true; + } else if (this.header_is_hidden && new_scroll_pos <= this.last_scroll_pos) + { + // The header is hidden and the page has scrolled up (or "scrolled" to the same position, which will + // only happen when navigation to a page causes scroll_and_hide_header to "scroll" to the top and the + // scroll position is already at the top), so reveal the header + this.header_elem.className = ''; + this.header_is_hidden = false; + } + this.last_scroll_pos = new_scroll_pos; + } + }, + + // Creates the page header and menu + make_header: function pg_make_header() + { + var body_elem = document.getElementsByTagName('body')[0]; + + var footer_elem = body_elem.appendChild(document.createElement('div')); + footer_elem.classList.add('footer'); + footer_elem.innerHTML = 'Terms<\/a>'; + + this.header_elem = body_elem.appendChild(document.createElement('header')); + + var hs = '
'; + hs += 'PEW\'s Corner<\/a>'; + hs += ' + + + +
+ERROR! Your browser doesn't support the HTML5 canvas element! +
+ +
+
+ +
+ + + diff --git a/programmers_converter.html b/programmers_converter.html new file mode 100644 index 0000000..cfe4c5f --- /dev/null +++ b/programmers_converter.html @@ -0,0 +1,2154 @@ + + + + + + + +Programmer's Number Converter + + + + + + + + +
+ +

Programmer's Number Converter

+ +
+
    +
  • Conversion/reformatting of entire tables/matrices of numbers in one go. +
  • Arbitrarily large numbers. +
  • Arbitrary fractional precision, or infinite precision using repetends
    + ("≈" means repetend took too long to calculate). +
  • Negative numbers in sign-magnitude or two's complement format. +
  • Any base from 2 through 36 (e.g. binary, octal, decimal, hex). +
  • Compound conversions (multiple conversions applied sequentially). +
+ + + + + +
+ +
+ +
+ +
+ +
+
+ +
+ + + +
+ +
+ + + diff --git a/programming/index.html b/programming/index.html new file mode 100644 index 0000000..11fdfd1 --- /dev/null +++ b/programming/index.html @@ -0,0 +1,26 @@ + + + + + + + +Programming Languages + + + + + +
+ +

Programming Languages

+ +
+Python 3 quick reference +(Dead) Python 2 quick reference +
+ +
+ + + diff --git a/programming/python3_quick_ref.html b/programming/python3_quick_ref.html new file mode 100644 index 0000000..a7ea62f --- /dev/null +++ b/programming/python3_quick_ref.html @@ -0,0 +1,6143 @@ + + + + + + + +Python 3 Quick Reference + + + + + + + +
+ +

Python 3
Quick Reference

+ +
+ +This is a one-(long-)page overview of the Python 3 (3.13.0) programming +language in the form of commented lines of code. + +

See also the old Python 2 quick reference.

+ +

Contents

+ +

Python Script Execution

+ +

Shebang

+ +
+#!/usr/bin/env python3
+
+ +
+#!/usr/bin/env python3.13
+
+ +With one of the above shebangs as the first line of the script, most Unix/Linux systems will +automatically pass the script to the latest installed version 3.x.x or 3.13.x Python +interpreter when the script is run as a command. This also works on Windows if the script is passed +to (or the typical script extension .py is associated with) the Python launcher py.exe. + +

Syntax

+ +

Statement Boundaries

+ +
+a = 3                   # Statements are usually separated by newlines
+print(a)                # ...
+b = 'hi'; print(b)      # (Non-compound) statements may be separated by semicolon
+c = 4;                  # and optionally terminated by semicolon
+                        # but using semicolons is discouraged (PEP 8)
+d = 2 * a + \
+    c                   # Any statement can be split across multiple lines
+                        # using backslash + newline (nothing allowed between the two)
+s = 'hel\
+  lo'                   # s = 'hel  lo' (any indention is included in string)
+s = 'hel' \
+    'lo'                # s = 'hello' (adjacent string literals are concatenated)
+d = 2 * (a +            # No backslash needed inside parentheses/brackets/...
+    c)
+print('hel'             # Prints 'hello' (adjacent string literals are concatenated;
+    'lo')               # no backslash needed inside parentheses)
+
+ +

Comments and Docstrings

+ +
+# Comments start with the '#' and end at the end of the same line,
+# so a comment spanning multiple lines must have '#' at the start
+# of each line.
+a = 3                   # Here's a comment following some code
+b = a + \               # ILLEGAL comment after backslash
+    2 +                 # and backslash WON'T WORK after comment either -> \
+    3                   # Comment must be on last line when using backslashes
+
+"""Another way to make a multiline comment
+is to put it inside a multiline string which
+is not assigned to anything."""
+
+def f():
+    # Here's a docstring for this function (similar for classes, modules):
+    """When a string is the first statement of a function (or class
+    or module), it becomes that object's docstring, accessible via
+    the __doc__ attribute. All lines traditionally have the same
+    indentation, and those spaces become part of the string.
+    """
+    return 3.14
+
+print(f.__doc__)        # Prints f's docstring (or None if none): 'When a string ...'
+help(f)                 # Prints information about f - including f's docstring
+
+ +

Compound Statement Format

+ +
+if len(mylist) > 0:     # A compound statement contains a header
+    sum = 0             # and a suite of statements with same indentation
+    for x in mylist:    # and possibly nested compound statements
+        print(x)
+        sum += x
+    print(sum)
+else:                   # and possibly another header
+    print('Empty list') # and its associated suite
+
+def func(x):            # A compound statement cannot have an empty suite
+    pass                # but 'pass' can be used to do nothing
+
+if x < y: x = y; y = 0  # Single-line compound statement (discouraged)
+                        # (cannot contain nested compound statements)
+
+ +

Keywords

+ +
+import keyword
+keyword.kwlist      # Returns the following list of "hard" Python keywords which cannot be
+                    # used as names of user-defined objects:
+                    # [
+                    # 'False',      # Bool value
+                    # 'None',       # None value
+                    # 'True',       # Bool value
+                    # 'and',        # Logical operator
+                    # 'as',         # Used with 'except', 'import', 'with', 'case'
+                    # 'assert',     # Assertion
+                    # 'async',      # Asynchronous coroutine function definition
+                    # 'await',      # Asynchronous coroutine handling
+                    # 'break',      # Loop control
+                    # 'class',      # Class definition
+                    # 'continue',   # Loop control
+                    # 'def',        # Function definition
+                    # 'del',        # Deletion of names, attributes (see delattr), and
+                    #               # container items (see __delitem__)
+                    # 'elif',       # Used with 'if'
+                    # 'else',       # Used with 'if', 'for', 'try', 'while'
+                    # 'except',     # Used with 'try'
+                    # 'finally',    # Used with 'try'
+                    # 'for',        # Looping, also in comprehensions and
+                    #               # generator expressions
+                    # 'from',       # Used with 'import', 'raise', 'yield'
+                    # 'global',     # Name scope control
+                    # 'if',         # Conditional execution/expression or condition in
+                    #               # comprehension, generator expression, or 'case'
+                    # 'import',     # Module importing
+                    # 'in',         # Membership testing operator, or used with 'for'
+                    # 'is',         # Identity testing operator
+                    # 'lambda',     # Anonymous lambda function expression
+                    # 'nonlocal',   # Name scope control
+                    # 'not',        # Logical operator
+                    # 'or',         # Logical operator
+                    # 'pass',       # Empty statement
+                    # 'raise',      # Exception raising
+                    # 'return',     # Return from a function
+                    # 'try',        # Exception handling
+                    # 'while',      # Looping
+                    # 'with',       # Context management
+                    # 'yield',      # Generator function control
+                    # ]
+
+keyword.softkwlist  # Returns the following list of "soft" Python keywords which may be
+                    # used as names of user-defined objects outside contexts where a
+                    # keyword is expected:
+                    # [
+                    # '_',          # Used with 'case'
+                    # 'case',       # Used with 'match'
+                    # 'match',      # Pattern matching
+                    # 'type',       # Type alias definition for type hints
+                    # ]
+
+ +

Expression Lists

+ +
+# Expression list
+t = 4, a + 1, 'hi'      # Right-hand side expression list becomes tuple (4, 2, 'hi')
+                        # (assuming a = 1)
+a, (b, c) = 3, (4, 5)   # Multiple assignments a=3, b=4, c=5 using expression lists
+                        # (all right-hand expressions are evaluated before any assignments)
+a, (b, c) = [3, (4, 5)] # Some alternatives equivalent to above; [] could also be ()
+[a, (b, c)] = 3, (4, 5) # ...
+a, *b, c = 1, 2, 3, 4   # Starred target (iterable unpacking); assigns a=1, b=[2,3], c=4
+a, *b, c = range(5)     # Assigns a=0, b=[1,2,3], c=4
+10,                     # Trailing comma is illegal/mandatory/optional if 0/1/more items
+[4, a + 1, 'hi']        # List created from expression list
+{4, a + 1, 'hi'}        # Set created from expression list
+f(4, a + 1, 'hi')       # Function call using expression list as argument list
+f(*range(2), **{'a':5}) # Iterable unpacking; same as f(0, 1, a=5)
+
+ +

Type Hints

+ +

Python provides syntax for annotating names (variables and functions) with their intended types, but Python itself does +not enforce these types (and never will, according to PEP 484). IDEs and +other tools (e.g. mypy) may use the type hints to do checking and assist developers in various ways.

+ +

See Types for more information on available types.

+ +
+# Define f as a function that takes an integer and a string and returns a string
+def f(n: int, s: str) -> str:
+    r: str = n * s
+    return r
+
+MyList = list[tuple[str, float]]        # Defines MyList as an alias for a list of tuples
+                                        # of string and float
+
+a: MyList = [('A', 3), ('B', 4.1)]      # Defines 'a' to have type MyList and assigns a
+                                        # valid object matching that type
+b: tuple[int, ...] = (1, 2, 3)          # Defines 'b' to be a tuple of 0 or more integers
+                                        # and assigns a valid object matching that type
+d: dict[str, int | None] = {'A': 4, 'B': None}  # Defines 'd' to be a dict that maps from
+                                                # string to either integer or None
+
+ +
+# Import more type hinting support from 'typing' module
+from typing import Any
+# Import 'Sequence' type from abstract base class module
+from collections.abc import Sequence
+
+type MyType = tuple[str, Any]           # Defines MyType as an explicit alias for a tuple
+                                        # of string and any type
+
+# Define a generic function 'get' using a type variable T; the function takes an int and a
+# sequence of T (which is constrained to being either an int or a MyType) and returns a T
+def get[T: (int, MyType)](i: int, s: Sequence[T]) -> T:
+    return s[i]
+
+# Define a generic class 'G' using a type variable T (which is either an int or a MyType);
+# the class works with any of T's possible types
+class G[T: (int, MyType)]:
+    def __init__(self, s: Sequence[T]) -> None:
+        self.s: Sequence[T] = s
+    def get(self, i: int) -> T:
+        return self.s[i]
+
+x: list[MyType] = [('A', 4), ('B', 'oo')]   # Defines 'x' to be a list of MyType and
+                                            # assigns a valid object matching that type
+get(0, x)                                   # Calls function 'get' with arguments matching
+                                            # its parameter type hints; returns ('A', 4)
+G(x).get(0)                                 # Creates an instance of class G using x as the
+                                            # constructor argument (T is implicitly MyType)
+                                            # and calls method 'get'; returns ('A', 4)
+G[int]([4,5,6]).get(0)                      # Creates an instance of class G (with T
+                                            # explicitly set to int) using a list of ints
+                                            # as the constructor argument, calls method
+                                            # 'get', and returns 4
+
+ +

Types

+ +See also Type Hints. + +

Basic Types (Immutable)

+ +
Int
+ +
+i = -2                  # Assigns an int (infinite range and precision)
+type(i)                 # Returns class int
+isinstance(i, int)      # Returns True
+int('20')               # Returns 20 (an int)
+int('20', 16)           # Returns 32 (second arg is base, 16 means hex)
+i += 0xA + 0o12 + 0b10  # i is now 20 (-2 + 10 + 10 + 2); this is hex + octal + binary
+012                     # ILLEGAL! (non-zero decimal numbers may not start with a zero -
+                        # avoids confusion with obsolete octal format)
+i.bit_length()          # Returns 5 (minimum number of bits needed to represent 20)
+(5).bit_length()        # Returns 3 (5.bit_length() would fail because 5. means 5.0)
+1_000_000 + 0b_1111_1111# Returns 1000255 (underscores improve readability)
+
+ +
Float
+ +
+x = -3.4                # Assigns a float (range: sys.float_info.min to sys.float_info.max)
+type(x)                 # Returns class float
+isinstance(x, float)    # Returns True
+float(3)                # Returns 3.0
+float('2.5e6')          # Returns 2500000.0
+float('inf')            # Returns positive infinity (greater than sys.float_info.max)
+float('-inf')           # Returns negative infinity (less than sys.float_info.min)
+float('nan')            # Returns the "not a number" (NaN) error value
+0 * float('inf')        # Returns float('nan')
+import math                 # Imports math module
+float('inf') == math.inf    # Returns True
+float('-inf') == -math.inf  # Returns True
+math.isinf(float('-inf'))   # Returns True
+math.isnan(float('nan'))    # Returns True
+math.nan == math.nan        # Returns False; NaN is unequal to everything, incl. itself
+math.sin(math.pi/2)     # Returns 1.0
+math.sqrt(2)            # Returns 1.4142135623730951
+1. + .2 + 3.4e-2        # Returns 1.234 (1. means 1.0, .2 means 0.2)
+0.000_000_001           # Returns 1e-9 (underscores improve readability)
+0.1 + 0.2 == 0.3        # Returns False because these values cannot be represented exactly
+                        # in floating point binary; use the decimal.Decimal type if exact
+                        # representations of (base-10) decimal values are needed, e.g. if
+                        # D = decimal.Decimal then D('0.1') + D('0.2') == D('0.3') returns
+                        # True
+math.isclose(0.1 + 0.2, 0.3)    # Returns True because 0.1 + 0.2 is (very) close to 0.3
+
+ +
Complex
+ +
+c = 1+2j                # Assigns a complex (pair of floats)
+type(c)                 # Returns class complex
+isinstance(c, complex)  # Returns True
+c.real                  # 1.0
+c.imag                  # 2.0
+c.real = 3              # ILLEGAL! Raises AttributeError exception (complex is immutable)
+c.conjugate()           # Returns (1-2j)
+complex(1, 2)           # Returns (1+2j)
+complex('1+2j')         # Returns (1+2j)
+complex(1+2j, 10j)      # Returns (-9+2j) because 10j is multiplied by 1j and becomes -10
+complex('infj')         # Same as complex(0, float('inf'))
+complex('-infj')        # Same as complex(0, float('-inf'))
+complex('inf-infj')     # Same as complex(float('inf'), float('-inf'))
+complex('nanj')         # Same as complex(0, float('nan'))
+import cmath                        # Imports cmath module (complex math)
+complex('infj') == cmath.infj       # Returns True
+complex('-infj') == -cmath.infj     # Returns True
+cmath.isinf(complex('-infj'))       # Returns True
+cmath.isnan(complex('nanj'))        # Returns True
+abs(3+4j)               # Returns 5.0 (magnitude)
+cmath.phase(3+4j)       # Returns 0.9272952180016122 (approx. 53 degrees in radians)
+cmath.polar(3+4j)       # Returns (5.0, 0.9272952180016122)
+cmath.rect(2, cmath.pi/4)           # Returns (1.4142135623730951+1.4142135623730951j)
+cmath.sqrt(-1)                      # Returns 1j
+0.1j + 0.2j == 0.3j                 # Returns False (see float type above for details)
+cmath.isclose(0.1j + 0.2j, 0.3j)    # Returns True because 0.1j + 0.2j is close to 0.3j
+
+ +
Bool
+ +
+b = True                # Assigns a bool (True or False)
+type(b)                 # Returns class bool
+isinstance(b, bool)     # Returns True
+bool(0)                 # Returns False for 0 (else True)
+bool('')                # Returns False for empty sequence type (else True)
+bool(None)              # Returns False
+int(True)               # Returns 1
+int(False)              # Returns 0
+3 + True                # Returns 4
+False * 5               # Returns 0
+
+ +
None
+ +
+x = None                # Assigns null object (nothing, unassigned argument/return value)
+type(x)                 # Returns class with name 'NoneType'; None is the only instance of
+                        # this class
+isinstance(x, type(None)) # Returns True
+bool(x)                 # Returns False
+
+ +
Slice
+ +
+sl = slice(3)           # Assigns a slice object equivalent to the :3 in a[:3] (supports
+                        # same parameters as range(), except negative start/stop values are
+                        # counted from end); more under classes
+type(sl)                # Returns class slice
+isinstance(sl, slice)   # Returns True
+print(sl)               # Prints 'slice(None, 3, None)'
+'hello'[sl]             # Returns 'hel' (same as 'hello'[:3])
+sl.start, sl.stop, sl.step  # Returns (None, 3, None)
+sl.indices(len('hello'))    # Returns (0, 3, 1) (range()-style (start, stop, step) args)
+sl.indices(len('hi'))       # Returns (0, 2, 1) (range is reduced to fit given length)
+sl = slice(-2, None, -1)# Assigns a slice object equivalent to the -2::-1 in a[-2::-1]
+'hello'[sl]             # Returns 'lleh' (same as 'hello'[-2::-1])
+sl.indices(len('hello'))# Returns (3, -1, -1) (here, stop == None for slice() maps to
+                        # stop == -1 for range())
+
+ +
Ellipsis
+ +
+e = Ellipsis            # Assigns Ellipsis object (intended for extended slice syntax)
+type(e)                 # Returns class with name 'ellipsis'; Ellipsis is the only instance
+                        # of this class
+isinstance(e, type(Ellipsis)) # Returns True
+bool(e)                 # Returns True
+e2 = ...                # Assigns Ellipsis object using alternative name '...'
+e2 is e                 # Returns True (there is only one Ellipsis object)
+
+ +
NotImplemented
+ +
+n = NotImplemented      # Assigns NotImplemented object (returned by methods such as
+                        # __add__ when they can't handle the provided argument type; the
+                        # interpreter will then try something else such as calling __radd__
+                        # on the other operand)
+type(n)                 # Returns class with name 'NotImplementedType'; NotImplemented is
+                        # the only instance of this class
+isinstance(n, type(NotImplemented)) # Returns True
+bool(n)                 # Returns True
+
+ +
Object
+ +
+o = object()            # Assigns a featureless object; object is the base of all
+                        # classes/types (about classes/types and objects)
+type(o)                 # Returns class object
+isinstance(o, object)   # Returns True
+isinstance(10, object)  # Returns True (int is a subclass of object)
+
+ +
Type
+ +
+T = type('MyT', (), {}) # Assigns a type object; all classes/types are instances of type
+                        # (about classes/types and objects)
+type(T)                 # Returns class type
+isinstance(T, type)     # Returns True
+class T2: pass          # Assigns a type object using a class statement (normal approach)
+type(T2)                # Returns class type
+
+ +

Basic Object Attributes

+ +

The following is a list of attributes (properties and methods) provided by instances of the +basic types +int, float, complex, bool, slice. +(Some general object attributes and low-level attributes are omitted from this list).

+ +Show attributes below: + +
+o.__abs__()             # Special method implementing abs(o);
+                        # applies to int,float,complex,bool
+o.__add__(o2)           # Special method implementing o + o2;
+                        # applies to int,float,complex,bool
+o.__and__(o2)           # Special method implementing o & o2;
+                        # applies to int,bool
+o.__bool__()            # Special method implementing bool(o);
+                        # applies to int,float,complex,bool
+o.__ceil__()            # Special method implementing math.ceil(o);
+                        # applies to int,float,bool
+o.__complex__()         # Special method implementing complex(o);
+                        # applies to complex
+o.__divmod__(o2)        # Special method
+                        # applies to int,float,bool
+o.__eq__(o2)            # Special method
+                        # applies to int,float,complex,bool,slice
+o.__float__()           # Special method
+                        # applies to int,float,bool
+o.__floor__()           # Special method
+                        # applies to int,float,bool
+o.__floordiv__(o2)      # Special method
+                        # applies to int,float,bool
+o.__ge__(o2)            # Special method
+                        # applies to int,float,bool,slice
+o.__getformat__(t)      # TBD
+                        # applies to float
+o.__getnewargs__()      # TBD (pickle protocol)
+                        # applies to int,float,complex,bool
+o.__gt__(o2)            # Special method
+                        # applies to int,float,bool,slice
+o.__index__()           # Special method
+                        # applies to int,bool
+o.__int__()             # Special method
+                        # applies to int,float,bool
+o.__invert__()          # Special method
+                        # applies to int,bool
+o.__le__(o2)            # Special method
+                        # applies to int,float,bool,slice
+o.__lshift__(o2)        # Special method
+                        # applies to int,bool
+o.__lt__(o2)            # Special method
+                        # applies to int,float,bool,slice
+o.__mod__(o2)           # Special method
+                        # applies to int,float,bool
+o.__mul__(o2)           # Special method
+                        # applies to int,float,complex,bool
+o.__ne__(o2)            # Special method
+                        # applies to int,float,complex,bool,slice
+o.__neg__()             # Special method
+                        # applies to int,float,complex,bool
+o.__or__(o2)            # Special method
+                        # applies to int,bool
+o.__pos__()             # Special method
+                        # applies to int,float,complex,bool
+o.__pow__(o2)           # Special method
+                        # applies to int,float,complex,bool
+o.__radd__(o2)          # Special method
+                        # applies to int,float,complex,bool
+o.__rand__(o2)          # Special method
+                        # applies to int,bool
+o.__rdivmod__(o2)       # Special method
+                        # applies to int,float,bool
+o.__rfloordiv__(o2)     # Special method
+                        # applies to int,float,bool
+o.__rlshift__(o2)       # Special method
+                        # applies to int,bool
+o.__rmod__(o2)          # Special method
+                        # applies to int,float,bool
+o.__rmul__(o2)          # Special method
+                        # applies to int,float,complex,bool
+o.__ror__(o2)           # Special method
+                        # applies to int,bool
+o.__round__()           # Special method
+                        # applies to int,float,bool
+o.__rpow__(o2)          # Special method
+                        # applies to int,float,complex,bool
+o.__rrshift__(o2)       # Special method
+                        # applies to int,bool
+o.__rshift__(o2)        # Special method
+                        # applies to int,bool
+o.__rsub__(o2)          # Special method
+                        # applies to int,float,complex,bool
+o.__rtruediv__(o2)      # Special method
+                        # applies to int,float,complex,bool
+o.__rxor__(o2)          # Special method
+                        # applies to int,bool
+o.__sub__(o2)           # Special method
+                        # applies to int,float,complex,bool
+o.__truediv__(o2)       # Special method
+                        # applies to int,float,complex,bool
+o.__trunc__()           # Special method
+                        # applies to int,float,bool
+o.__xor__(o2)           # Special method
+                        # applies to int,bool
+
+ +
+o.as_integer_ratio()    # Returns 2-tuple of integers whose ratio is equal to o;
+                        # (-1.5).as_integer_ratio() returns (-3,2); 0.1.as_integer_ratio()
+                        # returns (3602879701896397, 36028797018963968)
+                        # (but decimal.Decimal('0.1').as_integer_ratio() returns (1, 10));
+                        # applies to int,float,bool
+o.bit_count()           # Returns number of 1-bits in o; (10).bit_count() returns 2;
+                        # applies to int,bool
+o.bit_length()          # Returns minimum number of bits (disregarding sign) needed to
+                        # represent o; (10).bit_length() returns 4;
+                        # applies to int,bool
+o.conjugate()           # Returns complex conjugate of o; (1+2j).conjugate() returns (1-2j);
+                        # applies to int,float,complex,bool
+o.denominator           # Is 1 (unless o is a fractions.Fraction);
+                        # applies to int,bool
+o.from_bytes(b,e,signed=s)  # Class method; returns object of same class as o converted
+                        # from bytes object b with byte order e ('big', 'little',
+                        # sys.byteorder) in two's complement if s is True (default False);
+                        # int.from_bytes(b'\xfe\xff','little',signed=True) returns -2;
+                        # applies to int,bool
+o.fromhex(s)            # Class method; returns float value converted from hex number in
+                        # string s; float.fromhex(' ff.8 ') returns 255.5;
+                        # float.fromhex('0x1p10') returns 1024.0;
+                        # applies to float
+o.hex()                 # Returns hex string representing float o (in '0x#p#' format);
+                        # 255.0.hex() returns '0x1.fe00000000000p+7';
+                        # applies to float
+o.imag                  # Imaginary part of o (which is 0 if o is not complex);
+                        # (3+4j).imag returns 4; (3).imag returns 0; 4j.imag returns 4;
+                        # applies to int,float,complex,bool
+o.indices(n)            # Returns tuple of integers (start, stop, step) which can be passed
+                        # to range() to get a sequence of indices corresponding to applying
+                        # slice o to a sequence of length n;
+                        # ii = slice(None,None,-1).indices(5) makes ii (4,-1,-1), and
+                        # list(range(*ii)) returns [4,3,2,1,0];
+                        # applies to slice
+o.is_integer()          # Returns True if o is integral; 3.0.is_integer() returns True;
+                        # applies to int,float,bool
+o.numerator             # Is int(o) (unless o is a fractions.Fraction);
+                        # applies to int,bool
+o.real                  # Real part of o (which is o or int(o) if o is not complex);
+                        # (3+4j).real returns 3; (3).real returns 3; 4j.real returns 0;
+                        # applies to int,float,complex,bool
+o.start                 # Read-only start value of slice o; slice(2,5).start returns 2;
+                        # applies to slice
+o.step                  # Read-only step value of slice o; slice(5,2,-1).step returns -1;
+                        # applies to slice
+o.stop                  # Read-only stop value of slice o; slice(5).stop returns 5;
+                        # applies to slice
+o.to_bytes(n,e,signed=s)# Returns n-byte bytes object representing o with byte order e
+                        # ('big', 'little', sys.byteorder) and in two's complement if s is
+                        # True (default False); raises OverflowError if o is out of range
+                        # (-2).to_bytes(2,'little',signed=True) returns b'\xfe\xff';
+                        # applies to int,bool
+
+ +

Container Types

+ +
+# Container type detection
+import collections.abc                  # Imports abstract base class module
+isinstance(o, collections.abc.Container)# Returns True if o is container object (e.g. 'hi')
+
+ +

Sequence Types

+ +
Sequence Type Detection
+ +
+import collections.abc                  # Imports abstract base class module
+isinstance(o, collections.abc.Sequence) # Returns True if o is sequence object (e.g. 'hi')
+
+ +
String
+ +
+s1 = 'Say "hi"\n\'ho\'' # Assigns a string (immutable): Say "hi"(newline)'ho'
+s2 = "Say 'hi'\n\"ho\"" # Same as above, but with swapped single- and double-quotes
+                        # (Single-quotes allow embedded unescaped double-quotes, and vice
+                        # versa, otherwise no difference in behavior)
+s3 = """Say "hi"
+'ho'"""                 # Same as s1 above; triple-quotes allow embedded unescaped newlines
+                        # (usually used for docstrings)
+s4 = '''Say 'hi'
+"ho"'''                 # Same as s2 above (but triple single-quotes are not often used)
+s5 = r'\n\''            # Raw string of length 4: backslash, 'n', backslash, single-quote;
+                        # backslashes are taken literally, but still escape quotes; often
+                        # used for regular expressions
+s6 = r"""\\
+"""                     # Raw triple-quoted string of length 3: 2 backslashes and a newline
+                        # (see s3 and s5 above)
+s7 = '\xC6\u0E01\U0001F60E' # Assigns a string containing 3 Unicode characters; len(s7) is 3
+s8 = r'\u0E01\n'        # \u escapes are not interpreted in raw strings; len(s8) is 8
+                        # characters)
+s9 = f'{2+5:03d}\n'     # Formatted string literal: '007'(newline)
+s10 = fr'{2+5}\n'       # Formatted raw string literal: '7', backslash, 'n' (see s5 and s9
+                        # above)
+s11 = rf'{2+5}\n'       # Same as s10 above
+u'hi'                   # Same as 'hi'; Python 3 ignores the u prefix (but ur'' and uf''
+                        # are illegal)
+'\a\b\f\n\r\t\v\'\"\\'  # Same as '\x07\x08\x0C\x0A\x0D\x09\x0B\x27\x22\x5C'
+'\N{bel}\N{backspace}\N{form feed}\N{line feed}\N{carriage return}\
+\N{horizontal tabulation}\N{vertical tabulation}\N{apostrophe}\N{quotation mark}\
+\N{reverse solidus}'    # Same string as above (note that '\N{bel}' == '\x07', but
+                        # '\N{bell}' == '\U0001F514')
+'\0\7\10\011\3770'      # Octal escapes (max 3 digits); same as '\x00\x07\x08\x09\xFF\x30'
+s = ('hel'              # Adjacent string literals are concatenated (s = 'hello');
+    "lo")               # useful for splitting string literals and commenting each part
+                        # (see statement boundaries for other ways of breaking strings)
+type(s)                 # Returns class str
+isinstance(s, str)      # Returns True
+len(s)                  # Returns 5
+'e' in s                # Returns True
+s[0]                    # Returns 'h'
+s[0] = 'a'              # ILLEGAL! Raises TypeError exception because string is immutable
+s[-1]                   # Returns 'o'
+s[1:3]                  # Returns 'el' (general slice syntax is [start:stop:step] with
+                        # default values (if omitted) start=0, stop=end, step=1)
+s[-2:]                  # Returns 'lo'
+s[:-1]                  # Returns 'hell'
+s[::-1]                 # Returns 'olleh'
+s + ' there'            # Returns 'hello there'
+s * 2                   # Returns 'hellohello'
+str(4.1)                # Returns '4.1'
+
+ +
List
+ +
+a1 = [3, 'hello']       # Assigns a list (mutable)
+type(a1)                # Returns class list
+isinstance(a1, list)    # Returns True
+len(a1)                 # Returns 2
+'hello' in a1           # Returns True
+a1[-1]                  # Returns 'hello'
+a1[0] = [4]             # Assigns list [4] to first item of list a1
+a1.append('bye')        # a1 is now [[4], 'hello', 'bye']
+a1.extend([10, 11])     # a1 is now [[4], 'hello', 'bye', 10, 11]
+a1[-2:] = [9]           # a1 is now [[4], 'hello', 'bye', 9]
+del a1[-2:]             # a1 is now [[4], 'hello']
+a2 = a1                 # a2 now points to same list as a1
+                        # (changes to a1 items affect a2 items)
+a2 = a1[:]              # a2 is now a shallow copy of a1
+                        # (changes to 1st level of a1 don't affect a2)
+                        # (use a2 = copy.deepcopy(a1) to make a complete copy)
+list('hello')           # Returns ['h', 'e', 'l', 'l', 'o']
+
+ +
Tuple
+ +
+t = (3, 'hello')        # Assigns a tuple (immutable)
+t = 3, 'hello'          # Same as above but using unenclosed expression list
+type(t)                 # Returns class tuple
+()                      # Returns () (empty tuple)
+(4,)                    # Returns (4,) (single-item tuple)
+(4)                     # Returns 4 (int, not tuple)
+isinstance(t, tuple)    # Returns True
+len(t)                  # Returns 2
+'hello' in t            # Returns True
+t[-1]                   # Returns 'hello'
+t[-1] = 'a'             # ILLEGAL! Raises TypeError exception because tuple is immutable
+tuple('hello')          # Returns ('h', 'e', 'l', 'l', 'o')
+t2 = (4, [])            # Although tuples are immutable, they may contain mutable items
+t2[-1].append(5)        # t2 is now (4, [5])
+
+ +
Namedtuple Types
+ +
+import collections
+NT = collections.namedtuple('Mynamedtuple', 'x,y,z')    # Assigns a new named tuple type;
+                        # namedtuple itself is not a type but a function that makes a type
+type(NT)                # Returns class type
+nt = NT(4, 5, z=6)      # Assigns a named tuple of type NT (immutable; like tuple, but
+                        # allows items to be accessed by name)
+type(nt)                # Returns class with name 'Mynamedtuple'
+isinstance(nt, NT)      # Returns True
+nt.x                    # Returns 4 (unlike tuple)
+nt[-1]                  # Returns 6 (like tuple)
+5 in nt                 # Returns True (like tuple)
+NT._make([6,7,8])       # Same as NT(6, 7, 8) or NT(*[6, 7, 8])
+NT2 = collections.namedtuple('NT2', ('a','b','c'), defaults=(8,9))  # Assigns a new named
+                        # tuple type with defaults for the last 2 items
+nt2 = NT2(7)            # Assigns a named tuple of type NT2; values must be provided for
+                        # all items that don't have defaults
+nt2._asdict()           # Returns {'a':7, 'b':8, 'c':9}
+
+ +
Bytes
+ +
+b1 = bytes(3)               # Assigns a bytes object b'\x00\x00\x00' (immutable)
+b2 = bytes([65, 66, 67])    # Assigns a bytes object b'ABC' from a list (each value must be
+                            # in the range 0-255)
+b3 = bytes('\u0E01\u0E2E', 'utf_8')   # Assigns a bytes object b'\xe0\xb8\x81\xe0\xb8\xae'
+                                      # from a string using the specified encoding
+b4 = b'hi\n' + br'\n'       # Assigns a bytes object b'hi\n\\n' ('hi' + newline + backslash
+                            # + 'n', see string type above) from ascii strings
+list(b1)                    # Returns [0, 0, 0]
+list(b2)                    # Returns [65, 66, 67]
+list(b3)                    # Returns [224, 184, 129, 224, 184, 174]
+list(b4)                    # Returns [104, 105, 10, 92, 110]
+print(b2)                   # Prints "b'ABC'"
+print(b2[0])                # Prints '65'
+type(b1)                    # Returns class bytes
+isinstance(b1, bytes)       # Returns True
+len(b1)                     # Returns 3
+len(b3)                     # Returns 6
+b1 += b2                    # b1 is now b'\x00\x00\x00ABC' (b1 is reassigned, not mutated)
+b2.decode()                 # Returns string 'ABC'
+'ABC'.encode()              # Returns b'ABC'
+
+ +
Bytearray
+ +
+b1 = bytearray(2)               # Assigns a bytearray (same as bytes, but mutable)
+                                # containing 2 null bytes
+b2 = bytearray([65, 66, 67])    # Assigns a bytearray from a list
+                                # (each value must be in the range 0-255)
+b3 = bytearray('\u0E01\u0E2E', 'utf_8')   # Assigns a bytearray from a string using the
+                                          # specified encoding
+b4 = bytearray(b'ABC')          # Assigns a bytearray from a bytes object (b4 == b2)
+list(b1)                        # Returns [0, 0]
+list(b2)                        # Returns [65, 66, 67]
+list(b3)                        # Returns [224, 184, 129, 224, 184, 174]
+print(b2)                       # Prints "bytearray(b'ABC')"
+print(b2[0])                    # Prints '65'
+type(b1)                        # Returns class bytearray
+isinstance(b1, bytearray)       # Returns True
+len(b1)                         # Returns 2
+b1[0] = 72                      # b1 now contains 72, 0
+b1[1:] = b'ey'                  # b1 now contains 72, 101, 121
+b1 += b2                        # b1 now contains 72, 101, 121, 65, 66, 67
+print(b1)                       # Prints "bytearray(b'HeyABC')"
+
+ +
Memoryview
+ +
+b = bytes([4,5,6,7,8,9,254,255])    # Assigns a bytes object from a list
+m = memoryview(b)       # Assigns a memoryview referencing object b
+type(m)                 # Returns class memoryview
+isinstance(m, memoryview)   # Returns True
+m.readonly              # Returns True (because the referenced object b is immutable)
+m.tolist()              # Returns [4, 5, 6, 7, 8, 9, 254, 255]
+m[-1]                   # Returns 255 (last element)
+m[1:4]                  # Returns a new memoryview referencing b[1:4]
+m2 = m.cast('b', [2,4]) # New 2D memoryview referencing b (1-byte signed elements)
+m2.tolist()             # Returns [[4, 5, 6, 7], [8, 9, -2, -1]]
+m2[1,2]                 # Returns -2
+m3 = m.cast('H')        # New memoryview referencing b (2-byte unsigned elements)
+m3.tolist()             # Returns [1284, 1798, 2312, 65534] if platform is little-endian,
+                        # corresponding to [0x0504, 0x0706, 0x0908, 0xfffe]
+m4 = m.cast('i')        # New memoryview referencing b (4-byte signed elements)
+m4.tolist()             # Returns [117835012, -128760] if platform is little-endian
+
+ba = bytearray(b'hello')# Assigns a bytearray from a bytes object
+m5 = memoryview(ba)     # Assigns a memoryview referencing object ba
+m5.readonly             # Returns False (because the referenced object ba is mutable)
+m5[1] = ord('u')        # ba is now bytearray(b'hullo')
+
+ +
Range
+ +
+r = range(4)            # Assigns a range object (immutable) representing 0, 1, 2, 3 (from
+                        # 0 to 4 (4 excluded)) without actually storing this sequence
+type(r)                 # Returns class range
+print(r)                # Prints 'range(0, 4)'; r is an unexpanded range object
+print(list(r))          # Prints '[0, 1, 2, 3]'; list(r) expands r to a list
+print(tuple(r))         # Prints '(0, 1, 2, 3)'; tuple(r) expands r to a tuple
+isinstance(r, range)    # Returns True
+len(r)                  # Returns 4
+r[-1]                   # Returns 3
+range(2, 5)             # Returns range object representing sequence 2, 3, 4 (from 2 to 5
+                        # (5 excluded) with step 1)
+range(1, -2, -1)        # Returns range object representing sequence 1, 0, -1 (from 1 to -2
+                        # (-2 excluded) with step -1)
+
+ +

Other Container Types

+ +
Set
+ +
+u = {3, 'hello'}        # Assigns a set (mutable; unordered unique items)
+type(u)                 # Returns class set
+set()                   # Returns empty set
+{}                      # Returns empty dict, not set!
+isinstance(u, set)      # Returns True
+len(u)                  # Returns 2
+'hello' in u            # Returns True
+u.add(10)               # u is now {'hello', 10, 3} (undefined order)
+u.remove(10)            # u is now {'hello', 3}
+u.remove(10)            # Raises KeyError exception (no such item)
+u.discard(3)            # u is now {'hello'}
+u.discard(3)            # u is unchanged (did not contain 3)
+set('hello')            # Returns {'l', 'o', 'h', 'e'} (only one 'l')
+
+ +
Frozenset
+ +
+w = frozenset((3, 'hi'))    # Assigns a frozenset (like a set, but immutable, so can be
+                            # used as a dictionary key or element of a set)
+type(w)                     # Returns class frozenset
+isinstance(w, frozenset)    # Returns True
+
+ +
Dict
+ +
+d = {'a':10, 'b':5}     # Assigns a dictionary (mutable ordered mapping (preserves
+                        # insertion order); unique keys; was unordered until Python 3.7)
+type(d)                 # Returns class dict
+{}                      # Returns {} (empty dict, not set)
+isinstance(d, dict)     # Returns True
+len(d)                  # Returns 2
+'a' in d                # Returns True
+d['a'] = 11             # d is now {'a': 11, 'b': 5}
+dk = d.keys()           # Assigns a live view of d's keys
+type(dk)                # Returns class with name 'dict_keys'
+list(dk)                # Returns ['a', 'b']
+dv = d.values()         # Assigns a live view of d's values
+type(dv)                # Returns class with name 'dict_values'
+list(dv)                # Returns [11, 5]
+di = d.items()          # Assigns a live view of d's items
+type(di)                # Returns class with name 'dict_items'
+list(di)                # Returns [('a', 11), ('b', 5)]
+del d['a']              # d is now {'b': 5}
+list(dk)                # Returns ['b']
+list(dv)                # Returns [5]
+list(di)                # Returns [('b', 5)]
+dict((('a',10),('b',5))) # Returns {'a': 10, 'b': 5}
+dict(a=10, b=5)         # Returns {'a': 10, 'b': 5}
+
+ +
Defaultdict
+ +
+import collections
+dd = collections.defaultdict(int, {'a': 3}) # Assigns a defaultdict (same as dict, but the
+                        # first arg is called with no args to provide the default value for
+                        # nonexistent keys; here, int() returns the default value 0)
+type(dd)                # Returns class collections.defaultdict
+isinstance(dd, collections.defaultdict) # Returns True
+dd['a']                 # Returns 3
+dd['b']                 # Returns 0 (because that's what int() returns);
+                        # dd is now defaultdict(int, {'a': 3, 'b': 0})
+dd['c'] += 1            # dd is now defaultdict(int, {'a': 3, 'b': 0, 'c': 1})
+
+ +
OrderedDict
+ +
+import collections
+od = collections.OrderedDict([('a',10), ('b',11), ('c',12)]) # Assigns an OrderedDict (like
+                            # dict but has more functionality and different performance)
+type(od)                    # Returns class collections.OrderedDict
+isinstance(od, collections.OrderedDict) # Returns True
+od.move_to_end('a')         # od is now OrderedDict([('b',11), ('c',12), ('a',10)])
+od.move_to_end('a',last=False)  # od is now OrderedDict([('a',10), ('b',11), ('c',12)])
+od.popitem()                # Returns ('c',12); od is now OrderedDict([('a',10), ('b',11)])
+od.popitem(last=False)      # Returns ('a',10); od is now OrderedDict([('b',11)])
+
+ +
Counter
+ +
+import collections
+c = collections.Counter('abaab')    # Assigns a Counter (like a dict, but the values are
+                        # counts for the keys, i.e. {'a': 3, 'b': 2})
+type(c)                 # Returns class collections.Counter
+isinstance(c, collections.Counter)  # Returns True
+c['a']                  # Returns 3
+c['x']                  # Returns 0
+c['c'] += 2             # c is now Counter({'a': 3, 'b': 2, 'c': 2})
+c['b'] -= 6             # c is now Counter({'a': 3, 'b': -4, 'c': 2})
+c.update(['a', 'c'])    # c is now Counter({'a': 4, 'b': -4, 'c': 3})
+c.update({'a': 5})      # c is now Counter({'a': 9, 'b': -4, 'c': 3})
+c.most_common(2)        # Returns [('a', 9), ('c', 3)] (2 most common items ordered with
+                        # most common first)
+c.most_common()         # Returns [('a', 9), ('c', 3), ('b', -4)] (all items ordered with
+                        # most common first)
+c + collections.Counter({'a':-1, 'b':4})    # Returns Counter({'a': 8, 'c': 3}); items with
+                        # non-positive counts are discarded after arithmetic/set operations
+                        # on Counter objects
+
+ +
Deque (double-ended queue)
+ +
+import collections
+q = collections.deque() # Assigns a deque (a bit like list but with faster adding/removing
+                        # of items at both ends and slower indexing in the middle)
+type(q)                 # Returns class collections.deque
+isinstance(q, collections.deque)    # Returns True
+q = collections.deque((3, 'hi'), maxlen=4)  # Assigns a new deque containing items 3 and
+                        # 'hi' and restricted to max 4 items
+q.append('right')       # q is now deque([3, 'hi', 'right'])
+q.appendleft('left')    # q is now deque(['left', 3, 'hi', 'right'])
+q.append('R')           # q is now deque([3, 'hi', 'right', 'R']); 'left' got pushed out
+                        # due to maxlen=4
+q.appendleft('left')    # q is now deque(['left', 3, 'hi', 'right']); 'R' got pushed out
+                        # due to maxlen=4
+if q:                   # If q is not empty...
+    q.pop()             # Returns 'right'; q is now deque(['left', 3, 'hi'])
+q.popleft()             # Returns 'left'; q is now deque([3, 'hi'])
+q.extend([4,5,6])       # q is now deque(['hi', 4, 5, 6]); 3 got pushed out due to maxlen=4
+q.extendleft([2,1])     # q is now deque([1, 2, 'hi', 4]); 5 and 6 got pushed out
+q.rotate(-1)            # q is now deque([2, 'hi', 4, 1]); items rotated 1 place left
+
+ +

Container Object Attributes

+ +

The following is a list of attributes (properties and methods) provided by instances of the +container types +str, list, tuple, (types produced by) collections.namedtuple, bytes, bytearray, memoryview, range, +set, frozenset, dict, collections.defaultdict, collections.OrderedDict, collections.Counter, +collections.deque. +(Some general object attributes and low-level attributes are omitted from this list).

+ +Show attributes below: + +
+o.__add__(o2)           # Special method implementing o + o2 (concatenation); 'hi' + 'ho'
+                        # returns 'hiho'; for Counter the counts of equal keys are added
+                        # (and then items with non-positive counts are removed);
+                        # applies to str,list,tuple,namedtuple,bytes,bytearray,Counter,
+                        # deque
+o.__alloc__()           # Returns number of bytes allocated to o;
+                        # bytearray(b'hi').__alloc__() returns 3;
+                        # applies to bytearray
+o.__and__(o2)           # Implements o & o2 (intersection); {1,'a',3} & {'a',3,4} returns
+                        # {'a',3}; for Counter the intersection applies to the keys and the
+                        # smallest count is chosen for equal keys (and then items with non-
+                        # positive counts are removed);
+                        # applies to set,frozenset,Counter
+o.__bool__()            # TBD
+                        # applies to range
+o.__buffer__(flags)     # See buffer protocol special methods;
+                        # applies to bytes,bytearray,memoryview
+o.__bytes__()           # TBD
+                        # applies to bytes
+o.__class_getitem__(x)  # TBD
+                        # applies to list,tuple,namedtuple,set,frozenset,dict,defaultdict,
+                        # OrderedDict,Counter,deque
+o.__contains__(x)       # Implements x in o (membership test); 'b' in 'abc' returns True;
+                        # applies to str,list,tuple,namedtuple,bytes,bytearray,range,set,
+                        # frozenset,dict,defaultdict,OrderedDict,Counter,deque
+o.__copy__()            # Implements copy.copy(o); returns a shallow copy of o;
+                        # applies to defaultdict,deque
+o.__delitem__(x)        # Implements del o[x] (item deletion); if o = [4,5] then del o[0]
+                        # makes o [5]; o.__delitem__(slice(x,y,z)) implements del o[x:y:z];
+                        # applies to list,bytearray,dict,defaultdict,OrderedDict,Counter,
+                        # deque
+o.__enter__()           # TBD
+                        # applies to memoryview
+o.__eq__(o2)            # Implements o == o2;
+                        # applies to str,list,tuple,namedtuple,bytes,bytearray,memoryview,
+                        # range,set,frozenset,dict,defaultdict,OrderedDict,Counter,deque
+o.__exit__()            # TBD
+                        # applies to memoryview
+o.__ge__(o2)            # Implements o >= o2;
+                        # applies to str,list,tuple,namedtuple,bytes,bytearray,set,
+                        # frozenset,Counter,deque
+o.__getitem__(x)        # Implements o[x];
+                        # o.__getitem__(slice(x,y,z)) implements o[x:y:z];
+                        # applies to str,list,tuple,namedtuple,bytes,bytearray,memoryview,
+                        # range,dict,defaultdict,OrderedDict,Counter,deque
+o.__getnewargs__()      # TBD (pickle protocol)
+                        # applies to str,tuple,namedtuple,bytes
+o.__gt__(o2)            # Implements o > o2;
+                        # applies to str,list,tuple,namedtuple,bytes,bytearray,set,
+                        # frozenset,Counter,deque
+o.__iadd__(o2)          # Implements o += o2 (in-place concatenation); if o = [1,2] then
+                        # o += [3,4] makes o [1,2,3,4];
+                        # applies to list,bytearray,Counter,deque
+o.__iand__(o2)          # Implements o &= o2 (in-place intersection);
+                        # applies to set,Counter
+o.__imul__(x)           # Implements o *= x (in-place repetition); if o = [1,2] then o *= 3
+                        # makes o [1,2,1,2,1,2];
+                        # applies to list,bytearray,deque
+o.__ior__(o2)           # Implements o |= o2 (in-place union);
+                        # applies to set,dict,defaultdict,OrderedDict,Counter
+o.__isub__(o2)          # Implements o -= o2 (in-place difference);
+                        # applies to set,Counter
+o.__iter__()            # Implements iter(o); returns an iterator for iterable o;
+                        # applies to str,list,tuple,namedtuple,bytes,bytearray,memoryview,
+                        # range,set,frozenset,dict,defaultdict,OrderedDict,Counter,deque
+o.__ixor__(o2)          # Implements o ^= o2 (in-place symmetric difference);
+                        # applies to set
+o.__le__(o2)            # Implements o <= o2;
+                        # applies to str,list,tuple,namedtuple,bytes,bytearray,set,
+                        # frozenset,Counter,deque
+o.__len__()             # Implements len(o) (item count); len([5,6]) returns 2;
+                        # applies to str,list,tuple,namedtuple,bytes,bytearray,memoryview,
+                        # range,set,frozenset,dict,defaultdict,OrderedDict,Counter,deque
+o.__lt__(o2)            # Implements o < o2;
+                        # applies to str,list,tuple,namedtuple,bytes,bytearray,set,
+                        # frozenset,Counter,deque
+o.__match_args__        # TBD
+                        # applies to namedtuple
+o.__missing__(x)        # Implements o[x] if x is not one of o's keys; returns the default
+                        # value for a missing key;
+                        # applies to defaultdict,Counter
+o.__mod__(x)            # Implements o % x (formatting); '%-3s%03u' % ('hi', 9) returns
+                        # 'hi 009';
+                        # applies to str,bytes,bytearray
+o.__mul__(x)            # Implements o * x (repetition); [1,2] * 3 returns [1,2,1,2,1,2];
+                        # applies to str,list,tuple,namedtuple,bytes,bytearray,deque
+o.__ne__(o2)            # Implements o != o2;
+                        # applies to str,list,tuple,namedtuple,bytes,bytearray,memoryview,
+                        # range,set,frozenset,dict,defaultdict,OrderedDict,Counter,deque
+o.__neg__()             # Implements -o (negation); for Counter each count is negated (and
+                        # then items with non-positive counts are removed);
+                        # applies to Counter
+o.__or__(o2)            # Implements o | o2 (union);
+                        # {1,'a',3} | {'a',3,4} returns {1,'a',3,4};
+                        # {'x':2,'y':3} | {'x':1,'z':4} returns {'x':1,'y':3,'z':4};
+                        # for Counter the union applies to the keys and the largest count
+                        # is chosen for equal keys (and then items with non-positive counts
+                        # are removed);
+                        # applies to set,frozenset,dict,defaultdict,OrderedDict,Counter
+o.__pos__()             # Implements +o; for Counter this removes items with non-positive
+                        # counts;
+                        # applies to Counter
+o.__rand__(o2)          # Implements o2 & o (reverse intersection);
+                        # applies to set,frozenset
+o.__release_buffer__(b) # See buffer protocol special methods;
+                        # applies to bytearray,memoryview
+o.__replace__(**kwargs) # Implements copy.replace(o, **kwargs); returns a shallow copy of o
+                        # with replacements given by kwargs;
+                        # if NT = namedtuple('NT', 'x,y,z') and o = NT(3,[4],5) then
+                        # copy.replace(o,x=6,z=2) returns a new namedtuple NT(6,[4],2)
+                        # which shares the list object [4] with the original namedtuple;
+                        # applies to namedtuple
+o.__reversed__()        # Implements reversed(o); returns a reverse order iterator for o;
+                        # applies to list,range,dict,defaultdict,OrderedDict,Counter,deque
+o.__rmod__(o2)          # Implements o2 % o (reverse formatting);
+                        # applies to str,bytes,bytearray
+o.__rmul__(x)           # Implements x * o (reverse repetition); 3 * [1,2] returns
+                        # [1,2,1,2,1,2];
+                        # applies to str,list,tuple,namedtuple,bytes,bytearray,deque
+o.__ror__(o2)           # Implements o2 | o (reverse union);
+                        # applies to set,frozenset,dict,defaultdict,OrderedDict,Counter
+o.__rsub__(o2)          # Implements o2 - o (reverse difference);
+                        # applies to set,frozenset
+o.__rxor__(o2)          # Implements o2 ^ o (reverse symmetric difference);
+                        # applies to set,frozenset
+o.__setitem__(x, v)     # Implements o[x] = v;
+                        # o.__setitem__(slice(x,y,z), v) implements o[x:y:z] = v;
+                        # applies to list,bytearray,memoryview,dict,defaultdict,
+                        # OrderedDict,Counter,deque
+o.__sub__(o2)           # Implements o - o2 (difference); {1,'a',3} - {'a',3,4} returns {1};
+                        # for Counter the counts of equal keys are subtracted (and then
+                        # items with non-positive counts are removed);
+                        # applies to set,frozenset,Counter
+o.__xor__(o2)           # Implements o ^ o2 (symmetric difference); {1,'a',3} ^ {'a',3,4}
+                        # returns {1,4};
+                        # applies to set,frozenset
+
+ +
+o._asdict()             # Returns a dict mapping o's field names to values; if o =
+                        # namedtuple('NT', 'x,y')(3,4) then o._asdict() returns
+                        # {'x':3, 'y':4};
+                        # applies to namedtuple
+o._field_defaults       # Dict mapping o's field names to default values; if o =
+                        # namedtuple('NT', 'x,y,z', defaults=(2,3)) then o._field_defaults
+                        # is {'y':2, 'z':3};
+                        # applies to namedtuple
+o._fields               # Tuple of o's field names; if o = namedtuple('NT', 'x,y') then
+                        # o._fields is ('x', 'y');
+                        # applies to namedtuple
+o._make(o2)             # Class method; returns a new object of the same class as o and
+                        # initializes the new object with the values in o2; if o =
+                        # namedtuple('NT', 'x,y') then o._make([3,4]) returns a new named
+                        # tuple o(x=3, y=4) - same as o(*[3,4]);
+                        # applies to namedtuple
+o._replace(**kwargs)    # Returns a copy of o with new values for the specified fields;
+                        # if NT = namedtuple('NT', 'x,y,z') and o = NT(3,4,5) then
+                        # o._replace(x=6,z=2) returns a new named tuple NT(6,4,2);
+                        # applies to namedtuple
+o.add(x)                # Puts x into o; if o = {3} then o.add(5) makes o {3,5};
+                        # applies to set
+o.append(x)             # Inserts x at end of o; if o = [3] then o.append(5) makes o [3,5];
+                        # applies to list,bytearray,deque
+o.appendleft(x)         # Inserts x at start of o; if o = deque([3]) then o.appendleft(5)
+                        # makes o deque([5, 3]);
+                        # applies to deque
+o.c_contiguous          # Read-only bool which is True if o's memory layout is contiguous
+                        # and C-style (last index of array increments fastest); always True
+                        # if o is 1-dimensional and contiguous; if o =
+                        # memoryview(b'abcd').cast('B',[2,2]) then o.c_contiguous is True;
+                        # applies to memoryview
+o.capitalize()          # Returns a copy of o with first character capitalized;
+                        # 'hi ho'.capitalize() returns 'Hi ho';
+                        # applies to str,bytes,bytearray
+o.casefold()            # Returns a copy of o suitable for caseless comparisons;
+                        # 'Heiß'.casefold() returns 'heiss';
+                        # applies to str
+o.cast(f,s)             # Returns a new memoryview of o's buffer with format f and shape s;
+                        # if o = memoryview(bytes([1,2,3,255])) then
+                        # o.cast('B', [2,2]).tolist() returns [[1,2], [3,255]] (unsigned),
+                        # o.cast('h').tolist() returns [513, -253] (16-bit signed int),
+                        # o.cast('i').tolist() returns [-16580095] (32-bit signed int)
+                        # (last 2 examples assume little-endian platform);
+                        # applies to memoryview
+o.center(w,c)           # Returns a copy of o centered in a string of length w filled with
+                        # c (space if no c); returns an unmodified copy if len(o) >= w;
+                        # 'hi'.center(5,'*') returns '**hi*';
+                        # applies to str,bytes,bytearray
+o.clear()               # Makes o empty; if o = {3:9,5:25} then o.clear() makes o {};
+                        # applies to list,bytearray,set,dict,defaultdict,OrderedDict,
+                        # Counter,deque
+o.contiguous            # Read-only bool which is True if o's memory layout is contiguous
+                        # (the numpy module supports non-contiguous arrays);
+                        # applies to memoryview
+o.copy()                # Returns a shallow copy of o (similar to copy.copy(o) but doesn't
+                        # call o.__copy__()); if o = {4:[5]} then o.copy() returns a new
+                        # {4:[5]} referencing the same list [5] as o;
+                        # applies to list,bytearray,set,frozenset,dict,defaultdict,
+                        # OrderedDict,Counter,deque
+o.count(x)              # Returns count of non-overlapping occurrences of x in o;
+                        # 'hohohoho'.count('hoho') returns 2;
+                        # applies to str,list,tuple,namedtuple,bytes,bytearray,range,deque
+o.count(x,a,b)          # Returns count of non-overlapping occurrences of x in o[a:b];
+                        # a,b are optional; 'hohohoho'.count('hoho',1) returns 1;
+                        # 'hohohoho'.count('hoho',0,7) returns 1;
+                        # applies to str,bytes,bytearray
+o.decode(enc,err)       # Returns string equal to o decoded using encoding enc
+                        # (default 'utf-8') and error scheme err (default 'strict')
+                        # b'A\xc7\xbf'.decode() returns 'A\u01ff';
+                        # b'A\xc0'.decode() raises UnicodeDecodeError;
+                        # b'A\xc0'.decode('utf-8','ignore') returns 'A';
+                        # b'A\xc0'.decode('utf-8','replace') returns 'A\ufffd';
+                        # applies to bytes,bytearray
+o.default_factory       # Function called by o to get default value for nonexistent keys;
+                        # if o = defaultdict(int) then o.default_factory returns class int,
+                        # o[5] returns 0 (from int()) and makes o defaultdict(int, {5:0}),
+                        # o.default_factory = str makes o defaultdict(str, {5:0}), and o[6]
+                        # returns '' (str()) and makes o defaultdict(str, {5:0, 6:''});
+                        # applies to defaultdict
+o.difference(o2,...)        # Same as o - set(o2) - ... (but doesn't call o.__sub__());
+                            # {1,2,3,4}.difference({2,6},[7,3]) returns {1,4};
+                            # applies to set,frozenset
+o.difference_update(o2,...) # Same as o -= set(o2) | ... (but doesn't call o.__isub__());
+                            # if o = {1,2,3,4} then o.difference_update({2,6},[7,3]) makes
+                            # o {1,4};
+                            # applies to set
+o.discard(x)            # Removes item x from o; does nothing if x is not in o;
+                        # if o = {3,5} then o.discard(5) makes o {3};
+                        # applies to set
+o.elements()            # Returns an iterator which returns each item of o repeated
+                        # according to its count (items with non-positive counts are
+                        # excluded); if o = Counter({'a': 4, 'b': -4, 'c': 3}) or o =
+                        # Counter('acaacca') then ''.join(o.elements()) returns 'aaaaccc';
+                        # applies to Counter
+o.encode(enc,err)       # Returns bytes object equal to o encoded using encoding enc
+                        # (default 'utf-8') and error scheme err (default 'strict')
+                        # 'A\u01ff'.encode() returns b'A\xc7\xbf';
+                        # 'A\u0080'.encode('ascii') raises UnicodeEncodeError;
+                        # 'A\u0080'.encode('ascii','ignore') returns b'A';
+                        # 'A\u0080'.encode('ascii','replace') returns b'A?';
+                        # 'A\u0080'.encode('ascii','xmlcharrefreplace') returns b'A&#128;';
+                        # 'A\u0080'.encode('ascii','backslashreplace') returns b'A\\x80';
+                        # applies to str
+o.endswith(x,a,b)       # Returns True if o[a:b] ends with x (or with an item in tuple x);
+                        # 'abc'.endswith(('bc','z')) returns True;
+                        # applies to str,bytes,bytearray
+o.expandtabs(n)         # Returns a copy of o with tab characters replaced by up to n
+                        # spaces (enough spaces to reach the next tab column);
+                        # '\ta\tbc\td'.expandtabs(3) returns '   a  bc d';
+                        # applies to str,bytes,bytearray
+o.extend(o2)            # Same as o += o2 (but doesn't call o.__iadd__()); if o = [3,5]
+                        # then o.extend([1,2]) makes o [3,5,1,2];
+                        # applies to list,bytearray,deque
+o.extendleft(o2)        # Inserts all items from o2 (in reverse order) at start of o; if o
+                        # = deque([3,5]) then o.extendleft([1,2]) makes o deque([2,1,3,5]);
+                        # applies to deque
+o.f_contiguous          # Read-only bool which is True if o's memory layout is contiguous
+                        # and Fortran-style (first index of array increments fastest; the
+                        # numpy module supports Fortran-style arrays);
+                        # always True if o is 1-dimensional and contiguous; if o =
+                        # memoryview(b'abcd').cast('B',[2,2]) then o.f_contiguous is False;
+                        # applies to memoryview
+o.find(o2,a,b)          # Returns index of first occurrence of substring o2 in o[a:b] (a=0,
+                        # b=len(o) if not given), or -1 if none found;
+                        # 'abab'.find('ab') returns 0; 'abab'.find('ab',1,3) returns -1;
+                        # applies to str,bytes,bytearray
+o.format(...)           # Returns a string representing the arguments formatted according
+                        # to the directives in o; see string formatting;
+                        # '{:03d}{:4.1f}{x:>2.1s}'.format(6,7,x='AB') returns '006 7.0 A';
+                        # applies to str
+o.format_map(o2)        # Returns a string representing the values of dict o2 formatted
+                        # according to the directives in o (which refer to o2's keys);
+                        # '{x:03d}{y:4.1f}'.format_map(dict(x=6,y=7)) returns '006 7.0';
+                        # applies to str
+o.fromhex(s)            # Class method; returns object of same class as o containing bytes
+                        # corresponding to pairs of hex digits in string s;
+                        # bytes.fromhex('4142 43 0a') returns b'ABC\n';
+                        # applies to bytes,bytearray
+o.fromkeys(o2,x)        # Class method; returns object of same class as o containing all
+                        # items of sequence o2 as keys with all values equal to x (default
+                        # None); dict.fromkeys(('a','b'), 5) returns {'a':5, 'b':5};
+                        # applies to dict,defaultdict,OrderedDict
+o.get(k,d)              # Returns o[k], or d if k is not in o (d is None if omitted);
+                        # {'a':6}.get('a',5) returns 6, {'a':6}.get('b',5) returns 5, and
+                        # {'a':6}.get('b') returns None;
+                        # applies to dict,defaultdict,OrderedDict,Counter
+o.hex(sep,n)            # Returns string containing pairs of hex digits corresponding to
+                        # bytes in o, with separator sep inserted every n bytes from the
+                        # right (or left if n < 0); raises ValueError if sep is given and
+                        # not a single character; sep == '' and n == 1 if not given;
+                        # b'ABC\n'.hex() returns '4142430a';
+                        # b'ABC'.hex(':') returns '41:42:43'
+                        # b'ABC'.hex(':',2) returns '41:4243'
+                        # b'ABC'.hex(':',-2) returns '4142:43'
+                        # applies to bytes,bytearray,memoryview
+o.index(x)              # Returns index of first occurrence of item x in o; raises
+                        # ValueError if x is not in o;
+                        # for str,bytes,bytearray: x may be a substring of o;
+                        # [4,5,4].index(4) returns 0; 'abab'.index('ba') returns 1;
+                        # applies to str,list,tuple,namedtuple,bytes,bytearray,range,deque
+o.index(x,a,b)          # Returns index of first occurrence of item x in o[a:b] (a=0,
+                        # b=len(o) if not given); raises ValueError if x is not in o[a:b];
+                        # for str,bytes,bytearray: x may be a substring of o;
+                        # [4,5,4].index(4) returns 0; 'abab'.index('ab',1) returns 2;
+                        # applies to str,list,tuple,namedtuple,bytes,bytearray,deque
+o.insert(i,x)           # Inserts item x in o at index i; same as o[i:i] = [x];
+                        # if o = [4,5,6] then o.insert(2,'a') makes o [4,5,'a',6];
+                        # applies to list,bytearray,deque
+o.intersection(o2,...)        # Same as o & set(o2) & ... (but doesn't call o.__and__());
+                              # {1,2,3,4}.intersection({3,2,6},[7,3]) returns {3};
+                              # applies to set,frozenset
+o.intersection_update(o2,...) # Same as o &= set(o2) & ... (but doesn't call o.__iand__());
+                              # if o = {1,2,3,4} then o.intersection_update({2,6},[7,3])
+                              # makes o {3};
+                              # applies to set
+o.isalnum()             # Returns True if o is not empty and contains only alphanumeric
+                        # characters (alphabetic or numeric characters);
+                        # for characters 'Aªข': 'A\u00aa\u0e02'.isalnum() returns True;
+                        # for characters '2๒':  '2\u0e52'.isalnum() returns True;
+                        # for character '²':    '\u00b2'.isalnum() returns True;
+                        # for character '½':    '\u00bd'.isalnum() returns True;
+                        # applies to str,bytes,bytearray
+o.isalpha()             # Returns True if o is not empty and contains only alphabetic
+                        # characters;
+                        # for characters 'Aªข': 'A\u00aa\u0e02'.isalpha() returns True;
+                        # '2'.isalpha() returns False; '@'.isalpha() returns False;
+                        # applies to str,bytes,bytearray
+o.isascii()             # Returns True if o does not contain non-ASCII characters
+                        # (characters above '\x7F'); '\x00\x7f'.isascii() returns True;
+                        # '\x80'.isascii() returns False; ''.isascii() returns True;
+                        # applies to str,bytes,bytearray
+o.isdecimal()           # Returns True if o is not empty and contains only decimal
+                        # characters (a subset of digits);
+                        # for characters '2๒': '2\u0e52'.isdecimal() returns True;
+                        # for character '²':   '\u00b2'.isdecimal() returns False;
+                        # for character '½':   '\u00bd'.isdecimal() returns False;
+                        # applies to str
+o.isdigit()             # Returns True if o is not empty and contains only digits
+                        # (a subset of numeric characters);
+                        # for characters '2๒': '2\u0e52'.isdigit() returns True;
+                        # for character '²':   '\u00b2'.isdigit() returns True;
+                        # for character '½':   '\u00bd'.isdigit() returns False;
+                        # applies to str,bytes,bytearray
+o.isdisjoint(o2)        # Returns True if o and o2 have no common items;
+                        # {1,3}.isdisjoint([4,2]) returns True; {'A'}.isdisjoint('ABC')
+                        # returns False;
+                        # applies to set,frozenset
+o.isidentifier()        # Returns True if o fulfills the rules for being a valid Python
+                        # identifier; 'aBc_2'.isidentifier() returns True;
+                        # applies to str
+o.islower()             # Returns True if o contains at least 1 cased character and all
+                        # cased characters are lowercase; 'ver2.0'.islower() returns True;
+                        # applies to str,bytes,bytearray
+o.isnumeric()           # Returns True if o is not empty and contains only numeric
+                        # characters;
+                        # for characters '2๒': '2\u0e52'.isnumeric() returns True;
+                        # for character '²':   '\u00b2'.isnumeric() returns True;
+                        # for character '½':   '\u00bd'.isnumeric() returns True;
+                        # applies to str
+o.isprintable()         # Returns True if o doesn't contain non-printable characters
+                        # (separators other than the space character are considered non-
+                        # printable in this context); 'hi ho'.isprintable() returns True;
+                        # '\n'.isprintable() returns False; ''.isprintable() returns True;
+                        # applies to str
+o.isspace()             # Returns True if o is not empty and contains only whitespace
+                        # characters; ' \t\n\r\f\v'.isspace() returns True;
+                        # applies to str,bytes,bytearray
+o.issubset(o2)          # Same as o <= o2 (but doesn't call o.__le__());
+                        # {4,2}.issubset({1,2,3,4}) returns True;
+                        # {5,2}.issubset({1,2,3,4}) returns False;
+                        # applies to set,frozenset
+o.issuperset(o2)        # Same as o >= o2 (but doesn't call o.__ge__());
+                        # {1,2,3,4}.issuperset({4,2}) returns True;
+                        # {1,2,3,4}.issuperset({5,2}) returns False;
+                        # applies to set,frozenset
+o.istitle()             # Returns True if o contains at least 1 uppercase character, no
+                        # uppercase character follows a cased character, and any lowercase
+                        # character follows a cased character;
+                        # '2B|Not 2B'.istitle() returns True;
+                        # applies to str,bytes,bytearray
+o.isupper()             # Returns True if o contains at least 1 cased character and all
+                        # cased characters are uppercase; 'VER2.0'.isupper() returns True;
+                        # applies to str,bytes,bytearray
+o.items()               # Returns a live view of o's items; if o = {4:5,6:7} and v =
+                        # o.items() then list(v) returns [(4,5),(6,7)] and v will follow
+                        # changes to o;
+                        # applies to dict,defaultdict,OrderedDict,Counter
+o.itemsize              # Read-only size in bytes of each item in o; if o =
+                        # memoryview(array.array('h', [4,5,6])) then o.itemsize is 2;
+                        # applies to memoryview
+o.join(o2)              # Returns the object obtained by concatenating all items of o2
+                        # using o as separator; '/'.join('abc') returns 'a/b/c';
+                        # b'=='.join([b'x',b'42']) returns b'x==42';
+                        # applies to str,bytes,bytearray
+o.keys()                # Returns a live view of o's keys; if o = {4:5,6:7} and v = o.keys()
+                        # then list(v) returns [4,6] and v will follow changes to o;
+                        # applies to dict,defaultdict,OrderedDict,Counter
+o.ljust(w,c)            # Returns a copy of o left-justified in a string of length w filled
+                        # with c (space if no c); returns an unmodified copy if len(o) >= w;
+                        # 'hi'.ljust(5,'*') returns 'hi***';
+                        # applies to str,bytes,bytearray
+o.lower()               # Returns a copy of o with all uppercase characters converted to
+                        # lowercase; '2B|Not 2B'.lower() returns '2b|not 2b';
+                        # applies to str,bytes,bytearray
+o.lstrip(s)             # Returns a copy of o with first characters removed if present in
+                        # string s (whitespace if no s); 'abcd'.lstrip('dba') returns 'cd';
+                        # ' \t\na '.lstrip() returns 'a ';
+                        # applies to str,bytes,bytearray
+o.maketrans(d)          # Static method; returns dict d converted to a dict for use with
+                        # o.translate(); str.maketrans({'A':'B'}) returns {65:'B'};
+                        # applies to str
+o.maketrans(f,t)        # Static method; returns a table for use with o.translate() mapping
+                        # each character in f to the corresponding character in t;
+                        # str.maketrans('AB', 'CD') returns {65:67, 66:68};
+                        # bytes.maketrans(b'AB', b'CD') returns a 256-byte bytes object
+                        # with each byte value equal to its index, except the bytes at
+                        # indices 65 and 66 have values 67 and 68 instead of 65 and 66;
+                        # applies to str,bytes,bytearray
+o.maketrans(f,t,tnone)  # Static method; returns a dict for use with o.translate() mapping
+                        # each character in f to the corresponding character in t, and each
+                        # character in tnone to None;
+                        # str.maketrans('AB', 'CD', 'E') returns {65:67, 66:68, 69:None};
+                        # applies to str
+o.maxlen                # Read-only maximum length of o (None if o has no maximum length);
+                        # deque().maxlen returns None; deque(maxlen=5).maxlen returns 5;
+                        # applies to deque
+o.most_common(n)        # Returns a list of o's items and counts sorted by decreasing count;
+                        # if n is given, the list only includes the n items with largest
+                        # counts; if o = Counter({'a': 2, 'b': -4, 'c': 3}) then
+                        # o.most_common() returns [('c', 3), ('a', 2), ('b', -4)], and
+                        # o.most_common(1) returns [('c', 3)];
+                        # applies to Counter
+o.move_to_end(key,last) # Moves key to start (if last=False) or end (if last=True) of o;
+                        # default is end if last is not given;
+                        # if o = OrderedDict(a=4,b=5,c=6) then:
+                        #   o.move_to_end(key='b')        makes o OrderedDict(a=4,c=6,b=5);
+                        #   o.move_to_end('b',True)       makes o OrderedDict(a=4,c=6,b=5);
+                        #   o.move_to_end('b',last=False) makes o OrderedDict(b=5,a=4,c=6);
+                        # applies to OrderedDict
+o.nbytes                # Read-only number of bytes in o (excl. gaps between non-contiguous
+                        # parts); if o = memoryview(array.array('h', [1,2,3])) then
+                        # o.nbytes is 6 (on platforms where a C short is 2 bytes);
+                        # applies to memoryview
+o.ndim                  # Read-only number of dimensions in o; if o =
+                        # memoryview(b'abcd').cast('B',[1,4]) then o.ndim is 2 (1 row in
+                        # the 1st dimension and 4 columns in the 2nd);
+                        # applies to memoryview
+o.obj                   # Read-only reference to o's underlying object; if b = bytearray()
+                        # and o = memoryview(b) then o.obj is b;
+                        # applies to memoryview
+o.partition(o2)         # Returns (o[:i],o[i],o[i+1:]) where i is index of first occurrence
+                        # of o2 in o, or (o[:],type(o)(),type(o)()) if o2 is not found in o;
+                        # 'abba'.partition('b') returns ('a','b','ba');
+                        # b'abba'.partition(b'x') returns (b'abba',b'',b'');
+                        # applies to str,bytes,bytearray
+o.pop()                 # Removes and returns last item in o (arbitrary item if o is a set);
+                        # raises KeyError (set) or IndexError (others) if no item;
+                        # if o = [4,5,6] then o.pop() returns 6 and makes o [4,5];
+                        # applies to list,bytearray,set,deque
+o.pop(i)                # Removes and returns item o[i]; raises IndexError (list, bytearray)
+                        # or KeyError (others) if no item; if o = [4,5,6] then o.pop(1)
+                        # returns 5 and makes o [4,6]; if o = {4:9,5:3,6:9} then o.pop(5)
+                        # returns 3 and makes o {4:9,6:9};
+                        # applies to list,bytearray,dict,defaultdict,OrderedDict,Counter
+o.popitem()             # Removes and returns last added (key, o[key]) pair; raises
+                        # KeyError if o is empty; if o = {3:9,5:25} then o.popitem() makes
+                        # o {3:9} and returns (5,25);
+                        # applies to dict,defaultdict,OrderedDict,Counter
+o.popleft()             # Removes and returns first item in o; raises IndexError if no item;
+                        # if o = deque([3,5]) then o.popleft() returns 3 and makes o
+                        # deque([5]);
+                        # applies to deque
+o.readonly              # Read-only bool which is True if o is read-only;
+                        # if o = memoryview(b'abc') then o.readonly is True;
+                        # if o = memoryview(bytearray(3)) then o.readonly is False;
+                        # applies to memoryview
+o.release()             # Releases o's underlying object so it can no longer be accessed
+                        # via o; if o = memoryview(b'abc') and o.release() is called then
+                        # o.obj raises ValueError, and so does o[0], but o.release() may be
+                        # called any number of times;
+                        # applies to memoryview
+o.remove(x)             # Removes item x from o; raises ValueError (KeyError for set) if x
+                        # is not in o; if o = [3,5] then o.remove(5) makes o [3];
+                        # applies to list,bytearray,set,deque
+o.removeprefix(o2)      # Returns a copy of o with o2 removed if present at start of o;
+                        # 'abcd'.removeprefix('ab') returns 'cd';
+                        # 'abcd'.removeprefix('bc') returns 'abcd';
+                        # applies to str,bytes,bytearray
+o.removesuffix(o2)      # Returns a copy of o with o2 removed if present at end of o;
+                        # 'abcd'.removesuffix('cd') returns 'ab';
+                        # 'abcd'.removesuffix('bc') returns 'abcd';
+                        # applies to str,bytes,bytearray
+o.replace(s1,s2,n)      # Returns a copy of o with first n (or all if no n) occurrences of
+                        # s1 replaced with s2; 'boohoo'.replace('oo','*') returns 'b*h*';
+                        # 'boohoo'.replace('oo','*',1) returns 'b*hoo';
+                        # applies to str,bytes,bytearray
+o.reverse()             # Reverses the items of o; same as o[::-1] = o;
+                        # if o = [4,5,6] then o.reverse() makes o [6,5,4];
+                        # applies to list,bytearray,deque
+o.rfind(o2,a,b)         # Same as o.find(), except last occurrence is chosen;
+                        # 'abab'.rfind('ab') returns 2; 'abab'.rfind('ab',1,3) returns -1;
+                        # applies to str,bytes,bytearray
+o.rindex(x,a,b)         # Same as o.index(), except last occurrence is chosen;
+                        # 'abab'.rindex('ab') returns 2; 'abab'.rindex('ab',0,3) returns 0;
+                        # applies to str,bytes,bytearray
+o.rjust(w,c)            # Returns a copy of o right-justified in a string of length w
+                        # filled with c (space if no c); returns an unmodified copy if
+                        # len(o) >= w; 'hi'.rjust(5,'*') returns '***hi';
+                        # applies to str,bytes,bytearray
+o.rotate(n)             # Rotates o's items n places to the right (left if n < 0; 1 place
+                        # right if no n); if o = deque([1,2,3,4]) then o.rotate() makes o
+                        # deque([4,1,2,3], o.rotate(-1) makes o deque([1,2,3,4]) again, and
+                        # o.rotate(3) makes o deque([2,3,4,1]);
+                        # applies to deque
+o.rpartition(o2)        # Returns (o[:i],o[i],o[i+1:]) where i is index of last occurrence
+                        # of o2 in o, or (type(o)(),type(o)(),o[:]) if o2 is not found in o;
+                        # 'abba'.rpartition('b') returns ('ab','b','a');
+                        # b'abba'.rpartition(b'x') returns (b'',b'',b'abba');
+                        # applies to str,bytes,bytearray
+o.rsplit(sep,maxsplit)  # Same as o.split(), except splitting is done from the right when
+                        # maxsplit is given;
+                        # 'fooboohoo'.rsplit('oo', 1) returns ['foobooh',''];
+                        # applies to str,bytes,bytearray
+o.rstrip(s)             # Returns a copy of o with last characters removed if present in
+                        # string s (whitespace if no s); 'abcd'.rstrip('cda') returns 'ab';
+                        # ' a \t\n'.rstrip() returns ' a';
+                        # applies to str,bytes,bytearray
+o.setdefault(k,d)       # Returns o[k] if it exists, otherwise sets o[k] = d (None if no d)
+                        # and returns this value;
+                        # if o = {2:6} then o.setdefault(2,8) returns 6 (o is unchanged),
+                        # o.setdefault(3,8) makes o {2:6, 3:8} and returns 8, and
+                        # o.setdefault(4) makes o {2:6, 3:8, 4:None} and returns None;
+                        # applies to dict,defaultdict,OrderedDict,Counter
+o.shape                 # Read-only tuple containing the number of items in o's dimensions;
+                        # if o = memoryview(b'abcd').cast('B',[1,4]) then o.shape is (1,4);
+                        # applies to memoryview
+o.sort(key=kf,reverse=r)# Sorts the items of o using key function kf (kf(x) returns a
+                        # comparison key for each item x, and is lambda x:x if not given);
+                        # two items x and y are always compared using kf(x).__lt__(kf(y));
+                        # if kf is a class with a suitable __lt__ method, kf(x) creates a
+                        # new instance of this class as the comparison key for item x;
+                        # sort order is reversed if r is True (r is False if not given);
+                        # if o = [-6,5,10] then o.sort(reverse=True) makes o [10,5,-6], and
+                        # o.sort(key=abs) makes o [5,-6,10];
+                        # applies to list
+o.split(sep,maxsplit)   # Returns a list of parts of o split at each occurrence of sep, or
+                        # at each sequence of whitespace if sep is omitted or None;
+                        # if maxsplit is given and not -1, only maxsplit splits are done;
+                        # ' hi  ho '.split() returns ['hi','ho']; '  '.split() returns [];
+                        # ' hi  ho '.split(' ') returns ['','hi','','ho',''];
+                        # 'fooboohoo'.split('oo', 1) returns ['f','boohoo'];
+                        # ''.split(' ') returns [''];
+                        # applies to str,bytes,bytearray
+o.splitlines(keepends)  # Returns a list of lines in o, splitting at any type of newline,
+                        # and discarding newlines if keepends is omitted or False;
+                        # 'hi\nho\r'.splitlines() returns ['hi','ho'];
+                        # 'hi\r\nho\n\r'.splitlines(True) returns ['hi\r\n','ho\n','\r'];
+                        # 'hi\nho'.splitlines(keepends=True) returns ['hi\n','ho'];
+                        # '\n'.splitlines() returns ['']; ''.splitlines() returns [];
+                        # applies to str,bytes,bytearray
+o.start                 # Read-only start value of range o; range(10).start returns 0;
+                        # applies to range
+o.startswith(x,a,b)     # Returns True if o[a:b] starts with x (or with an item in tuple x);
+                        # 'abc'.startswith(('ab','z')) returns True;
+                        # applies to str,bytes,bytearray
+o.step                  # Read-only step value of range o; range(10).step returns 1;
+                        # applies to range
+o.stop                  # Read-only stop value of range o; range(10).stop returns 10;
+                        # applies to range
+o.strides               # Read-only tuple containing the distance in bytes from the start
+                        # of one item to the start of the next in each of o's dimensions;
+                        # if o = memoryview(b'abcd').cast('H',[1,2]) then o.strides is
+                        # (4,2);
+                        # applies to memoryview
+o.strip(s)              # Returns a copy of o with characters removed from both ends if
+                        # present in string s (whitespace if no s);
+                        # '0+a+b!'.strip('!+0') returns 'a+b';
+                        # ' a b\t\n'.strip() returns 'a b';
+                        # applies to str,bytes,bytearray
+o.suboffsets            # TBD
+                        # applies to memoryview
+o.subtract(o2)          # Subtracts the counts of o2's items from the counts of o's
+                        # corresponding items; if o = Counter({'a': 1}) then
+                        # o.subtract({'a': 2, 'b': -3}) returns Counter({'a': -1, 'b': 3});
+                        # applies to Counter
+o.swapcase()            # Returns a copy of o with all lower-/uppercase characters
+                        # converted to upper-/lowercase;
+                        # '2B|Not 2B'.swapcase() returns '2b|nOT 2b';
+                        # applies to str,bytes,bytearray
+o.symmetric_difference(o2)          # Same as o ^ o2 (but doesn't call o.__xor__());
+                                    # {2,3,4}.symmetric_difference({2,6} returns {3,4,6};
+                                    # applies to set,frozenset
+o.symmetric_difference_update(o2)   # Same as o ^= o2 (but doesn't call o.__ixor__());
+                                    # if o = {2,3,4} then o.symmetric_difference_update(
+                                    # {2,6}) makes o {3,4,6};
+                                    # applies to set
+o.title()               # Returns a copy of o with the first character of each sequence of
+                        # cased characters converted to uppercase, the rest to lowercase;
+                        # '2b|noT 2b'.title() returns '2B|Not 2B';
+                        # "they're DAD's".title() returns "They'Re Dad'S";
+                        # applies to str,bytes,bytearray
+o.tobytes(order)        # Returns a bytes object containing the bytes of o in the requested
+                        # order; the order may be (default is 'C' if not specified):
+                        # 'C': C-style (last index of array increments fastest);
+                        # 'F': Fortran-style (first index of array increments fastest);
+                        # 'A': the same style as used by o;
+                        # if o = memoryview(b'AbCd').cast('B',[2,2]) then o.tobytes()
+                        # returns b'AbCd' and o.tobytes('F') returns b'ACbd';
+                        # applies to memoryview
+o.tolist()              # Returns a list (of lists if o is multidimensional) containing the
+                        # data in o; if o = memoryview(b'abcd').cast('B',[2,2]) then
+                        # o.tolist() returns [[97, 98], [99, 100]];
+                        # applies to memoryview
+o.toreadonly()          # Returns a read-only copy of o; if o = memoryview(bytearray(b'A'))
+                        # and o2 = o.toreadonly() then o.readonly is False, o2.readonly is
+                        # True, o2 == o, o2 is not o, o2[0] == o[0] == 65, o[0] = 66 makes
+                        # o2[0] 66, and o2[0] = 67 raises TypeError (cannot modify
+                        # read-only memory);
+                        # applies to memoryview
+o.total()               # Returns sum of all counts; Counter(a=2,b=3).total() returns 5;
+                        # applies to Counter
+o.translate(t)          # Returns a copy of o with characters replaced according to table t
+                        # (o.maketrans() may be used to create t);
+                        # 'Aargh'.translate(str.maketrans('Ag','Bt','h')) returns 'Bart';
+                        # applies to str,bytes,bytearray
+o.union(o2,...)         # Same as o | set(o2) | ... (but doesn't call o.__or__());
+                        # {2,3,4}.union({2,6},[3,7]) returns {2,3,4,6,7};
+                        # applies to set,frozenset
+o.update(o2)            # Updates o with items from o2;
+                        # for set: same as o |= set(o2) (but doesn't call o.__ior__());
+                        # if o = {2,3,4} then o.update([2,6]) makes o {2,3,4,6};
+                        # applies to set,dict,defaultdict,OrderedDict,Counter
+o.update(o2,...)        # Updates o with items from o2, ...;
+                        # same as o |= set(o2) | ... (but doesn't call o.__ior__());
+                        # if o = {2,3,4} then o.update({2,6},[3,7]) makes o {2,3,4,6,7};
+                        # applies to set
+o.upper()               # Returns a copy of o with all lowercase characters converted to
+                        # uppercase; '2B|Not 2B'.upper() returns '2B|NOT 2B';
+                        # applies to str,bytes,bytearray
+o.values()              # Returns a live view of o's values; if o = {4:5,6:7} and v =
+                        # o.values() then list(v) returns [5,7] and v will follow changes
+                        # to o;
+                        # applies to dict,defaultdict,OrderedDict,Counter
+o.zfill(w)              # Returns a copy of o right-justified in a string of length w
+                        # filled with '0' (but a leading sign is left-justified); returns
+                        # an unmodified copy if len(o) >= w;
+                        # 'A'.zfill(4) returns '000A'; '-A'.zfill(4) returns '-00A';
+                        # applies to str,bytes,bytearray
+
+ +

Iterator Types

+ +
+# Iterator and iterable type detection
+import collections.abc                  # Imports abstract base class module
+isinstance(o, collections.abc.Iterator) # Returns True if o is an iterator object
+isinstance(o, collections.abc.Iterable) # Returns True if o is an iterable object (e.g.
+                        # container or iterator), in which case iter(o) returns an iterator
+                        # for o
+
+# Iterator types
+si = iter('señor')      # Assigns a string iterator
+sai = iter('hello')     # Assigns a faster string iterator for a pure ascii string
+type(si)                # Returns class with name 'str_iterator'
+type(sai)               # Returns class with name 'str_ascii_iterator'
+next(si)                # Returns 's', i.e. next item; raises StopIteration exception
+                        # when no more items; iterators normally can't be restarted (one
+                        # exception is a file f which can be restarted with f.seek(0))
+next(si, '.')           # Returns 'e'; returns '.' when no more items
+
+li = iter([3, 'hi'])    # Assigns a list iterator
+type(li)                # Returns class with name 'list_iterator'
+next(li)                # Returns 3
+
+ti = iter((3, 'hi'))    # Assigns a tuple iterator
+type(ti)                # Returns class with name 'tuple_iterator'
+next(ti)                # Returns 3
+
+seti = iter({3, 'hi'})  # Assigns a set iterator (iteration order is unpredictable)
+type(seti)              # Returns class with name 'set_iterator'
+next(seti)              # Returns 3 or 'hi'
+
+d = {'a':10, 'b':5}     # Assigns a dictionary
+dki = iter(d)           # Assigns a dictionary key iterator (same as iter(d.keys()))
+type(dki)               # Returns class with name 'dict_keyiterator'
+next(dki)               # Returns 'a'
+dvi = iter(d.values())  # Assigns a dictionary value iterator
+type(dvi)               # Returns class with name 'dict_valueiterator'
+next(dvi)               # Returns 10
+dii = iter(d.items())   # Assigns a dictionary item iterator
+type(dii)               # Returns class with name 'dict_itemiterator'
+next(dii)               # Returns ('a', 10)
+
+bi = iter(b'hello')     # Assigns a bytes iterator
+type(bi)                # Returns class with name 'bytes_iterator'
+next(bi)                # Returns 104 (ascii value of 'h')
+
+bai = iter(bytearray([65, 0])) # Assigns a bytearray iterator
+type(bai)               # Returns class with name 'bytearray_iterator'
+next(bai)               # Returns 65
+
+ri = iter(range(5))     # Assigns a range iterator
+type(ri)                # Returns class with name 'range_iterator'
+next(ri)                # Returns 0
+
+from random import random,seed  # Imports functions random and seed from module random
+seed(0, version=2)      # Sets the starting point for a well-defined pseudorandom sequence
+ci = iter(random, 0.1)  # Assigns a callable iterator that calls function random until that
+                        # function returns 0.1 (very unlikely); note that iter() with 2
+                        # args is quite different from iter() with 1 arg
+type(ci)                # Returns class with name 'callable_iterator'
+next(ci)                # Returns 0.8444218515250481
+next(ci)                # Returns 0.7579544029403025
+
+se = enumerate('hello') # Assigns an enumerate object (iterator) for a string
+type(se)                # Returns class enumerate
+isinstance(se, enumerate)   # Returns True
+next(se)                # Returns (0, 'h'); first item in this tuple is count
+next(se)                # Returns (1, 'e')
+xe = enumerate(ri, 100) # Assigns an enumerate object for a range iterator (see above)
+                        # with count starting at 100; ri already iterated once above, so
+                        # first xe iteration triggers second ri iteration
+next(xe)                # Returns (100, 1)
+next(xe)                # Returns (101, 2)
+next(ri)                # Returns 3; xe uses ri to iterate, so ri is also at item 3
+
+z = zip('ab',[3,4])     # Assigns a zip object (iterator)
+type(z)                 # Returns class zip
+isinstance(z, zip)      # Returns True
+next(z)                 # Returns ('a', 3)
+next(z)                 # Returns ('b', 4)
+
+ +Generator objects (see generator expressions +and generator functions) +and files are also iterators. + +

More Types

+ +"Everything is an object", so see these other object types: + + +

Control Flow Manipulation

+ +

Conditional Execution

+ +
+# 'If' statement
+if x == 3:
+    x = y               # Lines at same nesting level must have same indentation
+    if not z:           # (see compound statement format)
+        y += 1
+elif y != 4:
+    pass                # Does nothing (placeholder for empty statement list)
+else:
+    y = x
+    # Single-line 'if'
+    if z: x = 1; y = 2  # Semi-colon binds tighter than colon, so doesn't end the 'if'
+    else: y = 1; x = 2
+
+ +See also conditional expressions. + +

'Match' Statement

+ +The basics: + +
+# Define helper function to print info
+def log(expr, pattern, **vars):
+    print(f'{expr!r} matches "{pattern}"',
+          *('and sets', ', '.join(f'{v}={vars[v]!r}' for v in vars)) * (len(vars) > 0))
+
+# Define some variables for later use (x will be overridden by some case patterns)
+x = 3.14
+z = 5+7j
+
+# Feed some values one by one into the match statement and see which case gets matched
+for expr in ((2.0,1), [2,True], True, 1, 3, 4.0, 3.0, 4, (5,'A'), 'A', ('B',3.0),
+             (1,2,3,4), ((1,2),(3,4)), ((1,2,3),4), [3.0,(4,True)], [3.0,[4,True]],
+             (5,6,7), (5,7,9), (None,), ()):
+    match expr:
+        case 2, 1.0 as y:                               # int and float literal patterns
+                                                        # will match any int/float/bool;
+                                                        # a pattern sequence will match any
+                                                        # tuple/list/... sequence;
+                                                        # 'as y' assigns value matching 1.0
+                                                        # to y
+            log(expr, "2, 1.0 as y", y=y)
+        case True:                                      # bool literal patterns only match
+                                                        # bool values
+            log(expr, "True")
+        case int(3) | float(4):                         # int(3) matches only integer 3,
+                                                        # etc; '|' means 'or'
+            log(expr, "int(3) | float(4)")
+            print(f'    (and y is still {y!r})')        # Previous assignments remain
+        case int(x) | float(x), str(y):                 # int(x) matches any int and
+                                                        # assigns it to x
+            log(expr, "int(x) | float(x), str(y)", x=x, y=y)
+        case (str(x) as y) | (('B' as x, float()) as y):    # float() matches any float, no
+                                                            # assignment
+            log(expr, "(str(x) as y) | (('B' as x, float()) as y)", x=x, y=y)
+        case (1 | 'C') as x, *y, _ if len(y) < 3:    # *y matches zero or more values
+                                                        # and assigns them to y; _ matches
+                                                        # any single value, no assignment;
+                                                        # 'if' condition is checked after
+                                                        # pattern match and assignments
+            log(expr, "(1 | 'C') as x, *y, _ if len(y) < 3", x=x, y=y)
+        case (_, _), x, *_:                             # Tuple structure in pattern must
+                                                        # match ditto in value
+            log(expr, "(_, _), x, *_", x=x)
+        case list([float(), tuple((int(x), bool(y)))]): # list()/tuple() in pattern only
+                                                        # matches exactly those sequence
+                                                        # types
+            log(expr, "list([float(), tuple((int(x), bool(y)))])", x=x, y=y)
+        case z.real, x, z.imag:                         # Objects accessed via '.' syntax
+                                                        # behave like literals, they are
+                                                        # never assignment targets;
+            log(expr, "z.real, x, z.imag", x=x)
+        case _,:                                        # This matches any single-element
+                                                        # tuple
+            log(expr, "_,")
+        case _:                                         # This matches anything, even an
+                                                        # empty tuple
+            log(expr, "_")
+
+# After the end of the match statement, any assigned variables retain their last values
+print(f'At end: x={x!r}, y={y!r}')
+
+ +
+(2.0, 1) matches "2, 1.0 as y" and sets y=1
+[2, True] matches "2, 1.0 as y" and sets y=True
+True matches "True"
+1 matches "_"
+3 matches "int(3) | float(4)"
+    (and y is still True)
+4.0 matches "int(3) | float(4)"
+    (and y is still True)
+3.0 matches "_"
+4 matches "_"
+(5, 'A') matches "int(x) | float(x), str(y)" and sets x=5, y='A'
+'A' matches "(str(x) as y) | (('B' as x, float()) as y)" and sets x='A', y='A'
+('B', 3.0) matches "(str(x) as y) | (('B' as x, float()) as y)" and sets x='B', y=('B', 3.0)
+(1, 2, 3, 4) matches "(1 | 'C') as x, *y, _ if len(y) < 3" and sets x=1, y=[2, 3]
+((1, 2), (3, 4)) matches "(_, _), x, *_" and sets x=(3, 4)
+((1, 2, 3), 4) matches "_"
+[3.0, (4, True)] matches "list([float(), tuple((int(x), bool(y)))])" and sets x=4, y=True
+[3.0, [4, True]] matches "_"
+(5, 6, 7) matches "z.real, x, z.imag" and sets x=6
+(5, 7, 9) matches "_"
+(None,) matches "_,"
+() matches "_"
+At end: x=6, y=True
+
+ +A more useful example: + +
+import enum             # Imports enumeration class support
+import operator         # Imports function versions of standard operators
+import itertools        # Imports iterator tools, e.g. chain.from_iterable used by make_rpn
+import pprint           # Imports pretty printing support
+
+# Define an integer enumeration class for the levels of the expression grammar, such that
+# an increasing level value corresponds to an increasing depth in the grammar hierarchy
+# (SUM + 1 == MORE_SUM, etc.)
+Level = enum.IntEnum('Level', 'SUM MORE_SUM TERM MORE_TERM FACTOR POWER MORE_POWER ATOM')
+
+# Define a recursive function that creates a tuple hierarchy from a list of tokens; each
+# tuple in the hierarchy will contain an operator function followed by its arguments (which
+# may in turn be tuples)
+def make_tree(items, level=None):
+    # Find a case pattern below that matches the (level, items) tuple
+    match level, items:
+        # Handle initial call in order to do final check before returning to caller
+        case None, all_items:
+            match make_tree(all_items, Level.SUM):
+                case x,:
+                    return x
+                case _, *rest:
+                    raise ValueError(f'Unexpected token here: {rest}')
+        # Get 1st argument (by calling 2 levels down) of a possible sequence of infix
+        # operations; then call 1 level down to handle actual operation
+        case Level.SUM | Level.TERM | Level.POWER, all_items:
+            return make_tree(make_tree(all_items, Level(level + 2)), Level(level + 1))
+        # Handle another (possibly first) add/subtract operation if any - by calling next
+        # level to get 2nd argument; then call same level again to check for more of such
+        # operations
+        case Level.MORE_SUM, (x, ('+' | '-' as op), *rest):
+            y, *rest = make_tree(rest, Level.TERM)
+            opfunc = operator.add if op == '+' else operator.sub
+            return make_tree(((opfunc, x, y), *rest), Level.MORE_SUM)
+        # Handle another (possibly first) multiply/divide operation if any - by calling
+        # next level to get 2nd argument; then call same level again to check for more of
+        # such operations
+        case Level.MORE_TERM, (x, ('*' | '/' as op), *rest):
+            y, *rest = make_tree(rest, Level.FACTOR)
+            opfunc = operator.mul if op == '*' else operator.truediv
+            return make_tree(((opfunc, x, y), *rest), Level.MORE_TERM)
+        # Handle another (possibly first) prefix sign operation if any - by calling same
+        # level again to get argument (which may include another sign operation)
+        case Level.FACTOR, (('+' | '-' as op), *rest):
+            x, *rest = make_tree(rest, Level.FACTOR)
+            opfunc = operator.pos if op == '+' else operator.neg
+            return (opfunc, x), *rest
+        # If no more prefix sign operations, call next level to get non-signed argument
+        case Level.FACTOR, all_items:
+            return make_tree(all_items, Level.POWER)
+        # Handle another (possibly first) power operation if any - by calling previous(!)
+        # level to get 2nd argument (power operations are evaluated right to left and
+        # arguments may include prefix operations)
+        case Level.MORE_POWER, (x, '**', *rest):
+            y, *rest = make_tree(rest, Level.FACTOR)
+            return (operator.pow, x, y), *rest
+        # Handle parentheses if any - by calling highest level to get parenthesized
+        # content; then check for closing parenthesis
+        case Level.ATOM, ('(', *rest):
+            match make_tree(rest, Level.SUM):
+                case x, ')', *rest:
+                    return x, *rest
+            raise ValueError('Missing ")"')
+        # At any level, if none of the above cases is valid and the first item is a simple
+        # number or an already finalized tuple, then just pass everything up the call tree
+        case _, (int() | float() | tuple(), *_) as x:
+            return x
+        # If there are no more tokens at this point, it's an error
+        case _, ():
+            raise ValueError('Incomplete expression')
+        # If none of the above cases is valid, something is wrong with the next token
+        case _, all_items:
+            raise ValueError(f'Unexpected token here: {all_items}')
+
+# As an example of using an expression tree returned by make_tree, here's a recursive
+# function to calculate the numerical value of such an expression tree; it simply applies
+# the operator function (the first item) in each tuple to the arguments (the remaining
+# items in the same tuple)
+def calc_tree(tree):
+    return tree[0](*map(calc_tree, tree[1:])) if isinstance(tree, tuple) else tree
+
+# As a second example, here's a recursive function that produces a reverse polish notation
+# representation of an expression tree; it uses chain.from_iterable to flatten the argument
+# trees in each tuple, and places the operator name at the end
+def make_rpn(tree):
+    return (*itertools.chain.from_iterable(map(make_rpn, tree[1:])), tree[0].__name__) \
+        if isinstance(tree, tuple) else (tree,)
+
+# A list of tokens (e.g. produced by the get_tokens function defined in the
+# string tokenizer example)
+tokens = [
+    '-', 4, '**', '+', 3, '**', 2, '/', '-', '+', 8, '+', '(', 7, '-', 5, ')', '*', 6.1]
+
+# Call the 3 functions defined above and print their return values
+print(f'''\
+Tree:
+{pprint.pformat(tree := make_tree(tokens), indent=2)}
+-----
+Calculated: {calc_tree(tree)}
+Reference:  {eval(''.join(map(str, tokens)))}
+-----
+RPN:
+{make_rpn(tree)}''')
+
+ +
+Tree:
+( <built-in function add>,
+  ( <built-in function truediv>,
+    ( <built-in function neg>,
+      ( <built-in function pow>,
+        4,
+        (<built-in function pos>, (<built-in function pow>, 3, 2)))),
+    (<built-in function neg>, (<built-in function pos>, 8))),
+  (<built-in function mul>, (<built-in function sub>, 7, 5), 6.1))
+-----
+Calculated: 32780.2
+Reference:  32780.2
+-----
+RPN:
+(4, 3, 2, 'pow', 'pos', 'pow', 'neg', 8, 'pos', 'neg', 'truediv', 7, 5, 'sub', 6.1, 'mul', 'add')
+
+ +

Loops

+ +
+# While loop
+while x < 10:
+    x += 1
+    if x == 5:
+        continue        # Skips rest of loop body and goes back to testing loop condition
+    print(x)
+    if x == y:
+        break           # Exits loop and skips 'else' part
+else:                   # Optional; does something if loop condition tested false,
+                        # i.e. when no more iterations and no break
+    print('no break')
+
+# For loop
+for x in alist:         # x becomes each item of alist in turn; alist is evaluated once
+                        # (Note: alist can be any iterable type or iterator)
+    print(x)
+    for i in range(x):  # range(x) is a sequence of integers from 0 through x - 1
+        print(i)
+else:                   # Optional; does something when no more iterations and no break
+    print('no break')
+print(x,i)              # Loop variables remain visible and retain their last value after
+                        # the loop
+
+ +

Exception Handling

+ +
+import sys
+# Loop through tuple of expression strings, and set expr to each one in turn
+for expr in ('1/0', '[][1]', '{}[2]', '(3).a', ')', 'sys.exit(5)', '6'):
+    print('Trying expr', expr)
+    # Try (with all parts: 'except', 'else', 'finally')
+    try:
+        eval(expr)              # Evaluates expression, possibly raising exception
+        # Continue here if no exception occurred above
+        print('- no exception')
+    except ZeroDivisionError:
+        # Come here on ZeroDivisionError exception in 'try' part
+        print('- div by 0')
+    except (IndexError, KeyError, AttributeError) as e:
+        # Come here on any of the listed exceptions in 'try' part - with e set to exception
+        # object
+        print('-', repr(e))
+    except Exception as e:
+        # Come here on any (not already handled) non-system-exiting exception in 'try' part
+        # - with e set to exception object (compare with 'except:' in next example)
+        print('- other:', repr(e))
+        continue            # Skips rest of for-loop body (after executing 'finally' part)
+    except SystemExit as e:
+        # Come here on SystemExit exception in 'try' part - with e set to exception object
+        # (SystemExit is a subclass of BaseException, not of Exception, see class diagram
+        # under Exception Grouping)
+        print('-', repr(e))
+    else:                   # Optional 'else' part
+        # Come here if no exception in 'try' part; same as putting code at end of 'try'
+        # part, but exceptions in 'else' part are not handled
+        print('- all OK')
+        break               # Breaks out of for-loop (after executing 'finally' part)
+    finally:                # Optional 'finally' part
+        # Always come here as last step, even on unhandled exception or
+        # return/break/continue (in try/except/else parts)
+        print('- finally')
+    print('- rest of loop body')
+
+ +
+Trying expr 1/0
+- div by 0
+- finally
+- rest of loop body
+Trying expr [][1]
+- IndexError('list index out of range')
+- finally
+- rest of loop body
+Trying expr {}[2]
+- KeyError(2)
+- finally
+- rest of loop body
+Trying expr (3).a
+- AttributeError("'int' object has no attribute 'a'")
+- finally
+- rest of loop body
+Trying expr )
+- other: SyntaxError("unmatched ')'", ('<string>', 1, 1, ')', 1, 1))
+- finally
+Trying expr sys.exit(5)
+- SystemExit(5)
+- finally
+- rest of loop body
+Trying expr 6
+- no exception
+- all OK
+- finally
+
+ +
+import sys
+# Outer 'try' which catches any unhandled exception in inner 'try'
+try:
+    # Inner 'try' (with 'finally' part only)
+    try:
+        print('Raising exception')
+        sys.exit()          # Raises SystemExit exception which is not handled by this
+                            # 'try' (but by outer 'try')
+        print('Unreachable')
+    finally:                # 'finally' part is also executed on unhandled exception
+        print('Inner finally')
+except:
+    # Come here on any (not already handled) exception in 'try' part; this will catch the
+    # SystemExit exception in the inner 'try' part; note that unlike 'except Exception:'
+    # this bare 'except:' catches all exceptions - also system-exiting ones
+    print('Outer except')
+
+ +
+Raising exception
+Inner finally
+Outer except
+
+ +
+# Raise exceptions explicitly in different ways
+for case in range(1, 8):
+    print('Case', case)
+    try:
+        try:
+            if case == 1:
+                raise RuntimeError          # Raises exception using exception class
+            elif case >= 2:
+                raise RuntimeError('hi', 5) # Raises exception using exception object
+        except Exception as e:              # Catches any exception and puts it in e
+            print('-', repr(e))
+            if case == 3:
+                raise                                   # Raises same exception e again as
+                                                        # though it had never been caught
+                                                        # by the try-except
+            elif case == 4:
+                raise RuntimeError('ho')                # Raises new exception, but remem-
+                                                        # bers that this happened while
+                                                        # handling exception e
+            elif case == 5:
+                raise RuntimeError('ho') from None      # Raises new exception and forgets
+                                                        # about exception e
+            elif case == 6:
+                raise RuntimeError('ho') from e         # Raises new exception and notes
+                                                        # that it was caused by exception e
+            elif case == 7:
+                raise RuntimeError('ho') from KeyError('g') # Raises new exception and
+                                                        # notes that it was caused by
+                                                        # exception KeyError('g')
+    except Exception as e:
+        print('--', repr(e), 'with args', e.args, 'caused by', repr(e.__cause__))
+
+ +
+Case 1
+- RuntimeError()
+Case 2
+- RuntimeError('hi', 5)
+Case 3
+- RuntimeError('hi', 5)
+-- RuntimeError('hi', 5) with args ('hi', 5) caused by None
+Case 4
+- RuntimeError('hi', 5)
+-- RuntimeError('ho') with args ('ho',) caused by None
+Case 5
+- RuntimeError('hi', 5)
+-- RuntimeError('ho') with args ('ho',) caused by None
+Case 6
+- RuntimeError('hi', 5)
+-- RuntimeError('ho') with args ('ho',) caused by RuntimeError('hi', 5)
+Case 7
+- RuntimeError('hi', 5)
+-- RuntimeError('ho') with args ('ho',) caused by KeyError('g')
+
+ +If the outer try-except were removed from the above code, and if the loop were somehow able to restart at the next +iteration every time it stopped due to an exception, then the output would be: + +
+Case 1
+- RuntimeError()
+Case 2
+- RuntimeError('hi', 5)
+Case 3
+- RuntimeError('hi', 5)
+Traceback (most recent call last):
+  File "<string>", line 9, in <module>
+RuntimeError: ('hi', 5)
+
+ +...restarting at next loop iteration... + +
+Case 4
+- RuntimeError('hi', 5)
+Traceback (most recent call last):
+  File "<string>", line 9, in <module>
+RuntimeError: ('hi', 5)
+
+During handling of the above exception, another exception occurred:
+
+Traceback (most recent call last):
+  File "<string>", line 17, in <module>
+RuntimeError: ho
+
+ +...restarting at next loop iteration... + +
+Case 5
+- RuntimeError('hi', 5)
+Traceback (most recent call last):
+  File "<string>", line 21, in <module>
+RuntimeError: ho
+
+ +...restarting at next loop iteration... + +
+Case 6
+- RuntimeError('hi', 5)
+Traceback (most recent call last):
+  File "<string>", line 9, in <module>
+RuntimeError: ('hi', 5)
+
+The above exception was the direct cause of the following exception:
+
+Traceback (most recent call last):
+  File "<string>", line 24, in <module>
+RuntimeError: ho
+
+ +...restarting at next loop iteration... + +
+Case 7
+- RuntimeError('hi', 5)
+KeyError: 'g'
+
+The above exception was the direct cause of the following exception:
+
+Traceback (most recent call last):
+  File "<string>", line 27, in <module>
+RuntimeError: ho
+
+ +

Exception Grouping

+ +

Exception groups (added in Python 3.11) allow multiple exceptions to be raised at the same time, and the 'except*' +syntax allows partial handling of such groups.

+ +

The UML diagram below shows how the exception grouping classes (red) relate to the normal top level exception classes +(black). It also shows some examples of specific exception classes (gray). Arrows point from subclasses to the +superclasses/bases they inherit from. +See also about classes/types and objects

+ +
+ + + + + + + + + + + + + + + BaseException + + + + BaseExceptionGroup + + + + Exception + + + + ExceptionGroup + + + + SystemExit + + + + ValueError + + +
+ +
+try:
+    try:
+        # Raise a BaseExceptionGroup containing some exceptions and a nested ExceptionGroup
+        # (ExceptionGroup is a subclass of both BaseExceptionGroup and Exception, and
+        # BaseExceptionGroup is a subclass of BaseException, the latter is needed for system
+        # exiting exceptions)
+        eg = BaseExceptionGroup('Errors', [SystemExit(1),
+                                           ExceptionGroup('Sub', [ValueError(2),
+                                                                  TypeError(3)]),
+                                           ValueError(4)])
+        raise eg
+    except* ValueError as e:
+        # Come here if there are any ValueError exceptions in the (Base-)ExceptionGroup (or
+        # in nested groups) - with e set to a copy of the group containing only those
+        # ValueError exceptions (note the special 'except*' syntax which handles part of a
+        # (Base-)ExceptionGroup while allowing the remaining part to propagate to other
+        # 'except*' clauses or to outer code blocks if not handled)
+        print('Val:', type(e).__name__, e.args)
+    except* SystemExit as e:
+        # Also come here if there are any SystemExit exceptions in the BaseExceptionGroup -
+        # with e set to a copy of the BaseExceptionGroup containing only those SystemExit
+        # exceptions
+        print('Sys:', type(e).__name__, e.args)
+    finally:
+        # Always come here as last step, even if parts of the (Base-)ExceptionGroup are
+        # unhandled
+        print('Inner try done')
+    # The unhandled TypeError exception above will propagate to the outer 'try' as an
+    # ExceptionGroup containing only the TypeError exception, so the following print will
+    # not be executed
+    print('All parts of ExceptionGroup handled')
+except BaseException as e:
+    # Catch any remaining exception (group) here (since BaseExceptionGroup is a subclass of
+    # BaseException, it can be handled by a normal 'except' clause)
+    print('Any:', type(e).__name__, e.args)
+
+ +
+Val: ExceptionGroup ('Errors', [ExceptionGroup('Sub', [ValueError(2)]), ValueError(4)])
+Sys: BaseExceptionGroup ('Errors', [SystemExit(1)])
+Inner try done
+Any: ExceptionGroup ('Errors', [ExceptionGroup('Sub', [TypeError(3)])])
+
+ +
+for excp in (AttributeError(1), SystemExit(2)):
+    try:
+        # Raise a simple non-group exception
+        raise excp
+    except* BaseException as e:
+        # The 'except*' clause will wrap any simple non-group exception in an ExceptionGroup
+        # (or BaseExceptionGroup if needed) and assign that to e, so e is always guaranteed
+        # to be an ExceptionGroup (or BaseExceptionGroup)
+        print('Any:', type(e).__name__, e.args)
+
+ +
+Any: ExceptionGroup ('', (AttributeError(1),))
+Any: BaseExceptionGroup ('', (SystemExit(2),))
+
+ +

Assertions

+ +Assertion statements are meant for debugging and have no effect if optimizations are enabled when running the script +(i.e. if the script is run with "python3 -O script.py"). + +
+assert 2 == 2                           # Does nothing because the expression is True
+assert 2 == 3                           # Raises AssertionError exception because the
+                                        # expression is False
+
+ +
+assert 2 == 3, 'Oops'                   # Raises AssertionError('Oops') exception due to
+                                        # the False expression
+
+ +

'With' Statement

+ +The 'with' statement uses a context manager to guarantee that certain actions are taken when the 'with' block is exited +(e.g. cleanup of resources that were taken into use by the context manager when the 'with' block was entered), even if +the exit is caused by an exception. + +
+# 'With' statement using context manager which suppresses exception handling on exit
+import contextlib                               # Imports with-related utilities
+with contextlib.suppress(ZeroDivisionError):    # Enters a context where ZeroDivisionError
+                                                # exceptions are suppressed
+    print('Calculating...')                     # Prints something
+    print(1/0)                                  # Raises a ZeroDivisionError exception
+                                                # which exits the block and context, but is
+                                                # caught by the 'suppress' context manager,
+                                                # which takes no further action
+    print('No problem')                         # This line is never executed
+print('Done')                                   # Execution continues here
+
+ +
+Calculating...
+Done
+
+ +
+# 4 nested 'with' contexts which open streams and redirect stdout/stderr on entry, and
+# close the streams and cancel the redirection on exit
+import contextlib, io, sys                  # Imports various libraries
+with io.StringIO() as out, \
+     io.StringIO() as err:                  # Creates a (file-like) text stream named out
+                                            # and enters a context where out is guaranteed
+                                            # to be closed no matter how the context is
+                                            # exited; then creates err in the same way in
+                                            # a nested context
+    with (contextlib.redirect_stdout(out),
+          contextlib.redirect_stderr(err)): # Enters 2 nested contexts where sys.stdout and
+                                            # sys.stderr are redirected to out and err,
+                                            # respectively; note: the 'with' expression can
+                                            # be parenthesized to avoid backslash line-
+                                            # continuation
+        print('Hi')                         # Prints 'Hi' to out instead of to sys.stdout
+        print('Ho', file=sys.stderr)        # Prints 'Ho' to err instead of to sys.stderr
+    print('Done')                           # Prints 'Done' to sys.stdout as usual
+    print('Out:', out.getvalue(), end='')   # Prints text collected in out so far
+    print('Err:', err.getvalue(), end='')   # Prints text collected in err so far
+
+out.getvalue()                              # Raises ValueError exception because out was
+                                            # closed when outer 'with' exited
+
+ +
+Done
+Out: Hi
+Err: Ho
+Traceback (most recent call last):
+  File "<string>", line 22, in <module>
+ValueError: I/O operation on closed file
+
+ +

Using Custom Context Manager Class

+ +A custom class can be used to instantiate a context +manager object for use in a 'with' statement. Any class that defines the __enter__() and __exit__() +special methods can be used for this purpose. + +
+import io
+
+# Custom context manager class
+class CM:
+    def __init__(self, init_text='', *, suppress_excp=False): # Called to construct
+                                                              # context manager instance
+        print('  Creating context manager')
+        self.init_text = init_text
+        self.suppress_excp = suppress_excp
+    def __enter__(self):                                # Called when 'with' enters context
+        print('  Entering context')
+        self.strm = io.StringIO(self.init_text)
+        self.strm.seek(0, io.SEEK_END)
+        return self.strm                                # Return value will be assigned to
+                                                        # name after 'as' in 'with'
+    def __exit__(self, excp_type, excp_val, traceback): # Called when 'with' exits context
+        print('  Exiting context with text:', self.strm.getvalue())
+        self.strm.close()
+        if excp_type is None:                           # On normal exit, all args are None
+            print('  - normal exit')                    # and return value is ignored
+        else:                                           # Else, args have exception info
+            print('  - exception raised: %r, %r, %r' %
+                (excp_type, excp_val, traceback.tb_lineno))
+            if self.suppress_excp:
+                print('  - but suppressed')
+            return self.suppress_excp                   # and returning True suppresses
+                                                        # further exception handling
+# Loop through 3 cases: normal exit, suppressed exception, unsuppressed exception
+for i in range(3):                                  # i = 0, 1, 2
+    print('i =', i)
+    with CM('Hi', suppress_excp=(i==1)) as s:       # Creates instance of context mgr CM
+                                                    # (suppressing exceptions when i is 1),
+                                                    # calls this instance's __enter__(),
+                                                    # and sets s to return value from
+                                                    # __enter__()
+        s.write(' ho')
+        if i > 0:
+            raise RuntimeError('Oops')              # Raises exception (and exits 'with'
+                                                    # block) when i is 1 or 2
+        s.write(' hum')
+                                                    # Exits 'with' block normally
+        # On any exit from 'with' block, context manager instance's __exit__() is called
+
+ +
+i = 0
+  Creating context manager
+  Entering context
+  Exiting context with text: Hi ho hum
+  - normal exit
+i = 1
+  Creating context manager
+  Entering context
+  Exiting context with text: Hi ho
+  - exception raised: <class 'RuntimeError'>, RuntimeError('Oops'), 38
+  - but suppressed
+i = 2
+  Creating context manager
+  Entering context
+  Exiting context with text: Hi ho
+  - exception raised: <class 'RuntimeError'>, RuntimeError('Oops'), 38
+Traceback (most recent call last):
+  File "<string>", line 38, in <module>
+RuntimeError: Oops
+
+ +

Using Decorated Generator Function

+ +

It is also possible (and sometimes easier than defining a +complete context manager class) to use a generator function to +produce a context manager object for use in a 'with' statement. The 'contextlib' standard module provides a +'contextmanager' decorator for this purpose. When applied to a generator +function, the 'contextmanager' decorator automatically adds the necessary __enter__() and __exit__() special methods to the returned generator object to make it usable as a context manager.

+ +

The code before the 'yield' statement in the generator function will be executed on context entry, and the code after +the 'yield' statement will be executed on context exit. Any exception raised within the 'with' block will propagate to +the 'yield' statement and can be handled by a 'try' statement at that point.

+ +
+import contextlib, io
+
+@contextlib.contextmanager                      # Adds __enter__ and __exit__ methods to
+                                                # generator object returned from function
+                                                # cm, so it can be used as context manager
+def cm(init_text='', *, suppress_excp=False):
+    print('  Entering context')
+    strm = io.StringIO(init_text)
+    strm.seek(0, io.SEEK_END)
+    excp_val = None
+    try:
+        yield strm                          # Passes control back to 'with' statement
+                                            # which assigns strm to name after 'as' and
+                                            # executes body of 'with' block
+                                            # When 'with' block ends or raises exception,
+                                            # control comes back here
+    except Exception as e:
+        excp_val = e
+        if not suppress_excp:
+            raise
+    finally:
+        print('  Exiting context with text:', strm.getvalue())
+        strm.close()
+        if excp_val is None:
+            print('  - normal exit')
+        else:
+            print('  - exception raised: %r' % excp_val)
+            if suppress_excp:
+                print('  - but suppressed')
+
+# Loop through 3 cases: normal exit, suppressed exception, unsuppressed exception
+for i in range(3):                                  # i = 0, 1, 2
+    print('i =', i)
+    with cm('Hi', suppress_excp=(i==1)) as s:       # Gets context mgr instance from cm()
+                                                    # (suppressing exceptions when i is 1),
+                                                    # calls this instance's __enter__()
+                                                    # (which runs body of cm() until yield)
+                                                    # and sets s to return value from
+                                                    # __enter__() (i.e. yielded value)
+        s.write(' ho')
+        if i > 0:
+            raise RuntimeError('Oops')              # Raises exception (and exits 'with'
+                                                    # block) when i is 1 or 2
+        s.write(' hum')
+                                                    # Exits 'with' block normally
+        # On any exit from 'with' block, context manager instance's __exit__() is called
+        # (which causes execution of cm() to continue after yield if no exception, or
+        # triggers exception handling at the point of the yield)
+
+ +
+i = 0
+  Entering context
+  Exiting context with text: Hi ho hum
+  - normal exit
+i = 1
+  Entering context
+  Exiting context with text: Hi ho
+  - exception raised: RuntimeError('Oops')
+  - but suppressed
+i = 2
+  Entering context
+  Exiting context with text: Hi ho
+  - exception raised: RuntimeError('Oops')
+Traceback (most recent call last):
+  File "<string>", line 42, in <module>
+RuntimeError: Oops
+
+ +

Script Termination

+ +
+import sys              # Imports the sys module
+sys.exit()              # Raises a SystemExit exception which terminates the script with
+                        # exit code 0 (usually considered to mean success) -
+                        # unless the exception is caught by a try statement
+sys.exit(2)             # Same as above, but uses the specified exit code
+sys.exit('Oops!')       # Same as above, but prints the specified string and uses
+                        # exit code 1 (usually considered to mean failure)
+sys.exit(obj)           # Same as above, but converts the specified object to a string,
+                        # prints it, and uses exit code 1, unless obj is None, in which
+                        # case nothing is printed and exit code is 0
+exit()                  # Not recommended for use in scripts; intended for use in the
+                        # interactive interpreter where it works like sys.exit()
+quit()                  # Same as exit()
+
+ +

Input/Output

+ +

Script Arguments

+ +
+import sys              # Imports the sys module
+sys.argv                # Returns a list containing the script name and command line args
+print(sys.argv[0])      # Prints script name (possibly full path)
+if len(sys.argv) > 1:   # If there are any command line arguments, then ...
+    print(sys.argv[1])  # ... print first one
+
+ +

Standard In/Out/Error

+ +
+# Stdout
+x = 10
+d = {'a': 4, 'b': 5}
+print('d =', d)         # Prints 'd = {'a': 4, 'b': 5}' + newline to stdout;
+                        # args are separated by a space
+print('x =', x, end=' ')# Prints 'x = 10 ' to stdout without newline (default end is '\n')
+print('(decimal)')      # Prints '(decimal)', so whole line is 'x = 10 (decimal)'
+print('x', x, sep=' = ')# Prints 'x = 10' + newline to stdout (default sep is ' ')
+
+# Stderr
+import sys                          # Imports sys module
+print('x =', x, end='', file=sys.stderr)  # Prints 'x = 10' to stderr without newline;
+                                          # (default file is sys.stdout)
+print(' (decimal)', file=sys.stderr)  # Prints ' (decimal)'; whole line: 'x = 10 (decimal)'
+sys.stderr.write('x = %d' % x)      # Prints 'x = 10' to stderr (never automatic newline)
+sys.stderr.write(' (decimal)\n')    # Prints ' (decimal)' + newline;
+                                    # whole line printed to stderr: 'x = 10 (decimal)'
+a1 = ['hi\n', 'ho\n']               # List of strings incl. newlines
+sys.stderr.writelines(a1)           # Prints 'hi' + newline + 'ho' + newline
+
+# Stdin
+q = input('Q: ')        # Prints 'Q: ' to stdout (without newline), then reads a line from
+                        # stdin as a string, strips the newline, and assigns it to q
+s = sys.stdin.read()    # Reads stdin until end of file and assigns the whole thing
+                        # (incl. newlines) as a string to s
+s = sys.stdin.readline()    # Reads one line from stdin as string incl. newline;
+                            # returns empty string if no more lines
+a = sys.stdin.readlines()   # Reads all lines from stdin as list of strings incl. newlines
+
+ +

Files

+ +A file can be opened as either a text file or a binary file, and (unlike in Python 2) the class +of the opened file object and the supported operations depend on whether the file was opened as +text or binary. + +

Files Opened as Text

+ +

Text file operations deal with str objects (i.e. Unicode text) and provide automatic platform +dependent newline conversion (i.e. Python newlines '\n' are converted to/from whatever the +platform uses in text files, e.g. '\r\n' for MS Windows). The default newline conversion can +be controlled/disabled via the newline keyword parameter to open().

+ +

The file pointer of a file opened in text mode should only be moved (using f.seek()) to positions +previously returned by f.tell(), or to the start or end of the file. No assumptions should be made +about the meaning of a value returned by f.tell(), except that it can be passed to f.seek() to get +back to the same position in the file. In other words, f.tell() does not necessarily return the +number of bytes from the start of the file.

+ +
+import io                   # Import io module containing file related extras
+
+# Creating/truncating + writing text file, and misc. file methods
+fname = 'txtfile.txt'
+f = open(fname, 'w')        # Creates/truncates and opens file in text mode for writing
+                            # from position 0; optional newline parameter controls newline
+                            # handling:
+                            #   newline=None   ('\n' maps to os.linesep, this is default)
+                            #   newline=''     (no conversion)
+                            #   newline='\n'   ('\n' maps to '\n', i.e. no conversion)
+                            #   newline='\r'   ('\n' maps to '\r', i.e. Mac style)
+                            #   newline='\r\n' ('\n' maps to '\r\n', i.e. Windows style)
+type(f)                     # Returns class io.TextIOWrapper (same for all text modes)
+isinstance(f, io.TextIOWrapper) # Returns True
+isinstance(f, io.TextIOBase)    # Returns True (superclass of all text files)
+isinstance(f, io.IOBase)        # Returns True (superclass of both text and binary files)
+f.tell()                    # Returns 0 (position of file pointer in some sense)
+x = 10
+print('x =', x, end=' ', file=f)    # Writes 'x = 10 ' to file without newline
+print('m', file=f)                  # Writes 'm' + newline;
+                                    # whole line: 'x = 10 m'
+f.write('x = %d' % x)       # Writes 'x = 10' to file (never automatic newline) and returns
+                            # 6 (number of chars written)
+f.write(' m\n')             # Writes ' m' + newline and returns 3 (chars written);
+                            # whole line: 'x = 10 m'
+f.tell()                    # Returns 20 on Windows (position of file pointer in some sense)
+a1 = ['hi\n', 'ho\n']       # List of strings incl. newlines
+f.writelines(a1)            # Writes 'hi\n' + 'ho\n' to file
+f.tell()                    # Returns 28 on Windows (position of file pointer in some sense)
+f.close()                   # Closes file
+                            # File now contains 'x = 10 m\r\nx = 10 m\r\nhi\r\nho\r\n' on
+                            # Windows
+
+# Exclusively creating text file (only if it doesn't already exist)
+f = open(fname, 'x')        # Raises FileExistsError exception because file already exists;
+                            # same as mode 'w' if file doesn't exist
+                            # File still contains 'x = 10 m\r\nx = 10 m\r\nhi\r\nho\r\n' on
+                            # Windows
+
+# Reading text file, and misc. file methods
+f = open(fname, 'r')        # Opens existing file in text mode for reading from pos 0
+                            # ('r' is optional); optional newline parameter controls
+                            # newline handling:
+                            #   newline=None   (any newline maps to '\n' and separates lines,
+                            #                  this is default)
+                            #   newline=''     (no conversion, any newline separates lines)
+                            #   newline='\n'   (no conversion, only '\n' separates lines)
+                            #   newline='\r'   (no conversion, only '\r' separates lines)
+                            #   newline='\r\n' (no conversion, only '\r\n' separates lines)
+f.tell()                    # Returns 0 (position of file pointer in some sense)
+s = f.read()                # Reads entire file as string
+f.tell()                    # Returns 28 on Windows (position of file pointer in some sense)
+f.seek(0)                   # Moves file pointer back to start of file and returns 0 (pos)
+f.seek(20)                  # Moves file pointer to position 20 in some sense (we don't
+                            # know what 20 means, but we previously got it from f.tell()
+                            # before writing 'hi\nho\n', so we know it is that position)
+s = f.read()                # Reads remainder of file from current position: 'hi\nho\n'
+f.seek(0, io.SEEK_END)      # Moves file pointer to end of file and returns 28 on Windows
+                            # (position of file pointer in some sense);
+f.seek(-10, io.SEEK_END)    # Raises io.UnsupportedOperation exception because non-zero
+                            # move from end of file is not supported for text files
+f.seek(0, io.SEEK_CUR)      # Moves file pointer nowhere (no move) and returns 28 on Windows
+f.seek(-10, io.SEEK_CUR)    # Raises io.UnsupportedOperation exception because non-zero
+                            # move from current position is not supported for text files
+f.seek(0)                   # Moves file pointer back to start of file and returns 0 (pos)
+s = f.readline()            # Reads next line from file as string incl. newline;
+                            # returns empty string if no more lines
+f.tell()                    # Returns 10 on Windows (position of file pointer in some sense)
+a = f.readlines()           # Reads all remaining lines from file as list of strings
+                            # incl. newlines
+f.tell()                    # Returns 28 on Windows (position of file pointer in some sense)
+f.seek(0)                   # Moves file pointer back to start of file and returns 0 (pos)
+s = next(f)                 # Same as f.readline() but raises StopIteration at end of file
+                            # (files are iterators with additional control via f.seek())
+for s in f: print(s, end='')# Iterates through remaining lines in file and prints each one
+f.close()                   # Closes file
+                            # File still contains 'x = 10 m\r\nx = 10 m\r\nhi\r\nho\r\n' on
+                            # Windows
+
+# 'With' statement (good practice)
+with open(fname) as f:      # 'with' ensures that file is closed when the 'with' suite of
+    s = f.read()            # statements ends or raises an exception
+                            # File still contains 'x = 10 m\r\nx = 10 m\r\nhi\r\nho\r\n' on
+                            # Windows
+
+# Appending to text file (creating it if needed)
+f = open(fname, 'a')        # (Creates and) opens file in text mode for appending
+                            # (writing at end)
+f.tell()                    # Returns 28 on Windows (position of file pointer in some sense
+                            # - irrelevant for mode 'a')
+print('hum', file=f)        # Appends 'hum\n' to end of file
+f.tell()                    # Returns 33 on Windows (position of file pointer in some sense)
+f.close()                   # Closes file
+                            # File now contains 'x = 10 m\r\nx = 10 m\r\nhi\r\nho\r\nhum\r\n'
+                            # on Windows
+
+# Creating/truncating + writing & reading text file
+f = open(fname, 'w+')       # Creates/truncates and opens file in text mode for writing
+                            # and reading
+f.tell()                    # Returns 0 (position of file pointer in some sense)
+s = f.read()                # Reads entire file as string: '' because file was truncated
+print('hi', file=f)         # Writes 'hi\n' to file
+f.tell()                    # Returns 4 on Windows (position of file pointer in some sense)
+f.close()                   # Closes file
+                            # File now contains 'hi\r\n' on Windows
+
+# Reading & writing text file
+f = open(fname, 'r+')       # Opens existing file in text mode for reading and writing
+                            # (no truncating) from start of file
+s = f.read(1)               # Reads 1 char from file as string: 'h'
+f.tell()                    # Returns 1 on Windows (position of file pointer in some sense)
+f.seek(0, io.SEEK_CUR)      # Doesn't move file pointer but flushes line buffer (needed for
+                            # text files when switching between reading and writing) and
+                            # returns 1 on Windows (position of file pointer in some sense)
+print('o', end='', file=f)  # Writes 'o' to file - overwriting previous 'i' in 'hi\n'
+f.tell()                    # Returns 2 on Windows (position of file pointer in some sense)
+f.seek(0)                   # Moves file pointer back to start of file and returns 0 (pos)
+s = f.read()                # Reads entire file as string: 'ho\n'
+f.close()                   # Closes file
+                            # File now contains 'ho\r\n' on Windows
+
+# Appending to & reading text file (creating it if needed)
+f = open(fname, 'a+')       # (Creates and) opens file in text mode for appending and
+                            # reading from end of file
+f.tell()                    # Returns 4 on Windows (position of file pointer in some sense)
+f.seek(0)                   # Moves file pointer back to start of file and returns 0 (pos)
+s = f.read()                # Reads entire file as string: 'ho\n'
+f.tell()                    # Returns 4 on Windows (position of file pointer in some sense)
+f.seek(0)                   # Moves file pointer back to start of file (doesn't affect
+                            # append operation)
+print('hum', file=f)        # Appends 'hum\n' to end of file; file is now 'ho\nhum\n'
+f.tell()                    # Returns 9 on Windows (position of file pointer in some sense)
+f.read()                    # Reads and returns remainder of file: '' because file pointer
+                            # was at end of file
+f.tell()                    # Returns 9 on Windows (position of file pointer in some sense)
+f.close()                   # Closes file
+                            # File now contains 'ho\r\nhum\r\n' on Windows
+
+ +

Files Opened as Binary

+ +

Binary file operations deal with bytes-like objects and do not perform any newline conversion. +

+ +

The file pointer of a file opened in binary mode can be moved (using f.seek()) to any byte +position within the file, and f.tell() returns the number of bytes from the start of the file to +the position of the file pointer.

+ +
+import io                   # Import io module containing file related extras
+
+# Creating/truncating + writing binary file, and misc. file methods
+fname = 'binfile.txt'
+f = open(fname, 'wb')       # Creates/truncates and opens file in binary mode for writing
+                            # from position 0
+type(f)                     # Returns class io.BufferedWriter
+isinstance(f, io.BufferedWriter)# Returns True
+isinstance(f, io.BufferedIOBase)# Returns True (superclass of all binary files)
+isinstance(f, io.IOBase)        # Returns True (superclass of both text and binary files)
+f.tell()                    # Returns 0 (position of file pointer in bytes)
+x = 10
+f.write(b'x = %d' % x)      # Writes 'x = 10' to file (no newline) and returns 6 (number of
+                            # bytes written - always equal to size of argument)
+f.write(b' (decimal)\n')    # Writes ' (decimal)' + newline and returns 11 (bytes written);
+                            # whole line: 'x = 10 (decimal)'
+a1 = [b'hi\n', b'ho\n']     # List of strings incl. newlines
+f.writelines(a1)            # Writes 'hi\n' + 'ho\n' to file
+f.tell()                    # Returns 23 (position of file pointer in bytes)
+f.close()                   # Closes file
+                            # File now contains b'x = 10 (decimal)\nhi\nho\n'
+
+# Exclusively creating binary file (only if it doesn't already exist)
+f = open(fname, 'xb')       # Raises FileExistsError exception because file already exists;
+                            # same as mode 'wb' if file doesn't exist
+                            # File still contains b'x = 10 (decimal)\nhi\nho\n'
+
+# Reading binary file, and misc. file methods
+f = open(fname, 'rb')       # Opens existing file in binary mode for reading from pos 0
+type(f)                     # Returns class io.BufferedReader
+isinstance(f, io.BufferedReader)# Returns True
+isinstance(f, io.BufferedIOBase)# Returns True (superclass of all binary files)
+f.tell()                    # Returns 0 (position of file pointer in bytes)
+b = f.read()                # Reads entire file as bytes object
+f.tell()                    # Returns 23 (position of file pointer in bytes)
+f.seek(-10, io.SEEK_END)    # Moves file pointer 10 bytes back from end of file and returns
+                            # 13 (new position of file pointer in bytes)
+f.tell()                    # Returns 13 (position of file pointer in bytes)
+f.seek(-10, io.SEEK_CUR)    # Moves file pointer 10 bytes back from current position and
+                            # returns 3 (position of file pointer in bytes)
+f.seek(10)                  # Moves file pointer 10 bytes forward from start of file and
+                            # returns 10 (position of file pointer in bytes)
+f.seek(0)                   # Moves file pointer back to start of file and returns 0 (pos)
+b = f.readline()            # Reads next line from file as bytes object incl. newline;
+                            # returns empty bytes object if no more lines
+f.tell()                    # Returns 17 (position of file pointer in bytes)
+a = f.readlines()           # Reads all remaining lines from file as list of bytes objects
+                            # incl. newlines
+f.tell()                    # Returns 23 (position of file pointer in bytes)
+f.seek(0)                   # Moves file pointer back to start of file and returns 0 (pos)
+b = next(f)                 # Same as f.readline() but raises StopIteration at end of file
+                            # (files are iterators with additional control via f.seek())
+for b in f: print(b.decode(), end='')   # Iterates through remaining lines in file and
+                                        # prints each one (after decoding to str)
+f.close()                   # Closes file
+                            # File still contains b'x = 10 (decimal)\nhi\nho\n'
+
+# 'With' statement (good practice)
+with open(fname, 'rb') as f:# 'with' ensures that file is closed when the 'with' suite of
+    b = f.read()            # statements ends or raises an exception
+                            # File still contains b'x = 10 (decimal)\nhi\nho\n'
+
+# Appending to binary file (creating it if needed)
+f = open(fname, 'ab')       # (Creates and) opens file in binary mode for appending
+                            # (writing at end)
+type(f)                     # Returns class io.BufferedWriter
+isinstance(f, io.BufferedWriter)# Returns True
+isinstance(f, io.BufferedIOBase)# Returns True (superclass of all binary files)
+f.tell()                    # Returns 23 (position of file pointer; irrelevant for mode 'a')
+f.write(b'hum\n')           # Appends 'hum\n' to end of file and returns 4 (bytes written)
+f.tell()                    # Returns 27 (position of file pointer in bytes)
+f.close()                   # Closes file
+                            # File now contains b'x = 10 (decimal)\nhi\nho\nhum\n'
+
+# Creating/truncating + writing & reading binary file
+f = open(fname, 'w+b')      # Creates/truncates and opens file in binary mode for writing
+                            # and reading
+type(f)                     # Returns class io.BufferedRandom
+isinstance(f, io.BufferedRandom)# Returns True
+isinstance(f, io.BufferedIOBase)# Returns True (superclass of all binary files)
+b = f.read()                # Reads entire file as bytes object: b'' because file was
+                            # truncated
+f.write(b'hi\n')            # Writes 'hi\n' to file and returns 3 (bytes written)
+f.tell()                    # Returns 3 (position of file pointer in bytes)
+f.close()                   # Closes file
+                            # File now contains b'hi\n'
+
+# Reading & writing binary file
+f = open(fname, 'r+b')      # Opens existing file in binary mode for reading and writing
+                            # (no truncating) from start of file
+type(f)                     # Returns class io.BufferedRandom
+isinstance(f, io.BufferedRandom)# Returns True
+isinstance(f, io.BufferedIOBase)# Returns True (superclass of all binary files)
+b = f.read(1)               # Reads 1 byte from file as bytes object: b'h'
+f.tell()                    # Returns 1 (position of file pointer in bytes)
+f.write(b'o')               # Writes 'o' to file - overwriting previous 'i' in 'hi\n' - and
+                            # returns 1 (bytes written)
+f.tell()                    # Returns 2 (position of file pointer in bytes)
+f.seek(0)                   # Moves file pointer back to start of file and returns 0 (pos)
+b = f.read()                # Reads entire file as bytes object: b'ho\n'
+f.close()                   # Closes file
+                            # File now contains b'ho\n'
+
+# Appending to & reading binary file (creating it if needed)
+f = open(fname, 'a+b')      # (Creates and) opens file in binary mode for appending and
+                            # reading from end of file
+type(f)                     # Returns class io.BufferedRandom
+isinstance(f, io.BufferedRandom)# Returns True
+isinstance(f, io.BufferedIOBase)# Returns True (superclass of all binary files)
+f.tell()                    # Returns 3 (position of file pointer in bytes)
+f.seek(0)                   # Moves file pointer back to start of file and returns 0 (pos)
+b = f.read()                # Reads entire file as bytes object: b'ho\n'
+f.tell()                    # Returns 3 (position of file pointer in bytes)
+f.seek(0)                   # Moves file pointer back to start of file (doesn't affect
+                            # append operation)
+f.write(b'hum\n')           # Appends 'hum\n' to end of file and returns 4 (bytes written);
+                            # file is now 'ho\nhum\n'
+f.tell()                    # Should return 7 but returns wrong value after append when
+                            # file pointer was not at end of file before append (bug?);
+                            # file pointer is actually at position 7, though
+f.read()                    # Reads and returns remainder of file: b'' because file pointer
+                            # was at end of file
+f.tell()                    # Returns 7 (position of file pointer in bytes)
+f.close()                   # Closes file
+                            # File now contains b'ho\nhum\n'
+
+ +

Expressions

+ +

Operators

+ +All operators are listed below (highlighted) in precedence groups from highest to lowest.
+Within each group, x op y op z == (x op y) op z, unless otherwise noted. + +
+###########################################################################################
+(2 + 3)                 # Returns 5
+(2, 3, 4)               # Returns tuple (2, 3, 4)
+[2, 3, 4]               # Returns list [2, 3, 4]
+{2: 3, 4: 5}            # Returns dict {2: 3, 4: 5}
+{2, 3, 4}               # Returns set {2, 3, 4}
+###########################################################################################
+x[2]                    # Returns item/value with index/key 2 from tuple/list/dict/string x
+                        # (or other object with __getitem__() method)
+x[1:6:2]                # Returns tuple/list/string by extracting slice (indices 1,3,5)
+                        # from x (x can't be a dict)
+x[2, 6:0:-2,            # Returns item(s) from x selected by expression list of indices/
+    slice(6,0,-2), ...] # slices/Ellipsis; built-in types other than memoryview allow only
+                        # 1 item between [] (not Ellipsis); numpy module allows any
+f(2, 3, 4)              # Returns result of calling function f with given arguments
+x.y                     # Returns member y of object x
+###########################################################################################
+await asyncio.sleep(1,9)# Suspends current coroutine, runs sleep coroutine (for 1 second),
+                        # resumes this coroutine, and returns 9 (return value from sleep)
+###########################################################################################
+2**3                    # Returns 8 (exponentiation); 4**3**2 == 4**(3**2) == 262144;
+                        # -2**-2 == -(2**(-2)) == -0.25
+###########################################################################################
++1                      # Returns 1
+-1                      # Returns -1
+~1                      # Returns -2 (bitwise NOT)
+###########################################################################################
+2 * 3                   # Returns 6
+'hi' * 3                # Returns 'hihihi' (sequence repetition)
+x @ y                   # Matrix multiplication (supported by numpy module, not by built-in
+                        # types)
+-5 / 2                  # Returns -2.5 (always a float)
+-5.0 // 2               # Returns -3.0 (floor div); for int: -5 // 2 == -3
+-5 % 3                  # Returns 1 (modulo); x == floor(x/y)*y + x%y
+'%0*d %X' % (5, 3, 12)  # Returns '00003 C' (string formatting)
+###########################################################################################
+2 + 3                   # Returns 5
+[1,2] + [3,4]           # Returns [1, 2, 3, 4] (sequence concatenation)
+2 - 3                   # Returns -1
+{1,2,3} - {3,4}         # Returns {1,2} (set difference)
+###########################################################################################
+6 << 2                  # Returns 24 (left shift); x << y == x * 2**y; y >= 0
+-6 >> 2                 # Returns -2 (right shift); x >> y == x // 2**y; y >= 0
+###########################################################################################
+6 & 3                   # Returns 2 (bitwise AND)
+{1,2,3} & {3,4}         # Returns {3} (set intersection)
+###########################################################################################
+6 ^ 3                   # Returns 5 (bitwise XOR)
+{1,2,3} ^ {3,4}         # Returns {1,2,4} (set symmetric difference)
+###########################################################################################
+6 | 3                   # Returns 7 (bitwise OR)
+{1,2,3} | {3,4}         # Returns {1,2,3,4} (set union)
+{'x':2,'y':3} | {'x':1,'z':4}   # Returns {'x':1,'y':3,'z':4} (dict union)
+###########################################################################################
+# Comparisons and tests (chainable, i.e. x < y < z means x < y and y < z (but y is
+# evaluated only once)):
+5 in (3, 5, 8)          # Returns True (membership test)
+'a' not in 'hi'         # Returns True (non-membership test)
+[] is []                # Returns False (identity test); these lists are not same object
+                        # (but immutable objects might be identical, e.g. maybe 5 is 5)
+{} is not {}            # Returns True (non-identity test)
+2 < 3                   # Returns True
+'ab' <= 'abc'           # Returns True (lexicographic Unicode comparison)
+[2,3] > [2]             # Returns True (lexicographic comparison of corresponding items)
+(3,) >= (2,5)           # Returns True (lexicographic comparison of corresponding items)
+{2,3} > {3}             # Returns True (proper superset)
+2 != '2'                # Returns True (different types generally compare unequal)
+2 == 2.0                # Returns True (comparison works across different numeric types)
+###########################################################################################
+not 2                   # Returns False (boolean NOT)
+###########################################################################################
+2 and 3                 # Returns 3 (boolean AND, returns 1st arg if False, else 2nd arg;
+                        # 2nd arg is not evaluated if 1st arg is returned)
+###########################################################################################
+0 or 'a'                # Returns 'a' (boolean OR, returns 1st arg if True, else 2nd arg;
+                        # 2nd arg is not evaluated if 1st arg is returned)
+###########################################################################################
+2 if True else 3        # Returns 2 (conditional expression);
+                        # 3rd arg is not evaluated if 1st arg is returned, and vice versa;
+                        # (x if a else y if b else z) == (x if a else (y if b else z))
+###########################################################################################
+lambda x,y: x + y       # Returns anonymous function which will return sum of its 2 args
+                        # (lambda expression)
+###########################################################################################
+(x := 2)                # Assignment expression; binds name x to object 2 and returns that
+                        # object; needs parentheses when at top level of expression state-
+                        # ment or at top level of right side of assignment statement (or
+                        # certain other places)
+###########################################################################################
+#=========================================================================================#
+# The "operators" below this point are not officially operators, but are included here to #
+# show their effective relative precedence in the special contexts where they are valid   #
+#=========================================================================================#
+###########################################################################################
+f(x=2)                  # Passes named argument to function f, i.e. binds f's formal param
+                        # x to object 2 regardless of x's position in f's parameter list
+f(*[4, 'hi'])           # Passes all items of given iterable as args to function f
+                        # (same as f(4, 'hi'))
+x,*y,z = range(5)       # Unpacks iterable (same as x,y,z = 0,[1,2,3],4)
+f(**{'x': 2, 'y':3})    # Passes key/value pairs of given dictionary as named args to f
+                        # (same as f(x=2, y=3))
+###########################################################################################
+2, 3                    # Returns tuple (2, 3) or expression list (see enclosing operators
+                        # above and multiple assignments below for uses)
+###########################################################################################
+(yield 2, 3)            # Returns (2,3) to caller of next() or send() on generator produced
+                        # by function containing this yield, suspends generator until next
+                        # call to next()/send(), then returns None or send's argument as
+                        # return value of yield expression; needs parentheses except when
+                        # at top level of right side of assignment, or when used as a
+                        # statement, so e.g. print((yield 2)) needs double parentheses;
+                        # (yield) is same as (yield None)
+(yield from range(5))   # Same as executing yield in a loop taking each item from range(5)
+                        # until exhausted, then returning any StopIteration value from
+                        # range(5) (i.e. None); passes send's argument to range(5)'s send
+                        # (not supported)
+###########################################################################################
+# Normal assignments (chainable, i.e. x = y = z means x = z, then y = z (but z is
+# evaluated only once); note the counterintuitive left-to-right assignment order!):
+x = 2                   # Binds name x to object 2
+o[0] = 2                # Sets item 0 of mutable object o to object 2
+                        # (by calling o.__setitem__(0, 2))
+o.x = 2                 # Sets attribute x of mutable object o to object 2
+                        # (by calling o.__setattr__('x', 2))
+x = o[x] = o[x]         # Chained assignments; same as tmp = o[x]; x = tmp; o[x] = tmp;
+                        # if x and o are initially 0 and [1, 2], they become 1 and [1, 1]
+                        # (o changes due to left-to-right assignment order)
+x, o[0], o.x = 2, 2, 2  # Multiple assignments using expression lists
+# Augmented assignments (not chainable; supports same targets as above except expression
+# lists):
+x += 2                  # Same as x = x + 2, but x is evaluated only once and updated in
+                        # place if possible
+x -= 2                  # x = x - 2 (but see x += 2)
+x *= 2                  # x = x * 2 (but see x += 2)
+x @= y                  # x = x @ y (not supported by built-in types)
+x /= 2                  # x = x / 2 (but see x += 2)
+x //= 2                 # x = x // 2 (but see x += 2)
+x %= 2                  # x = x % 2 (but see x += 2)
+x **= 2                 # x = x ** 2 (but see x += 2)
+x >>= 2                 # x = x >> 2 (but see x += 2)
+x <<= 2                 # x = x << 2 (but see x += 2)
+x &= 2                  # x = x & 2 (but see x += 2)
+x ^= 2                  # x = x ^ 2 (but see x += 2)
+x |= 2                  # x = x | 2 (but see x += 2)
+###########################################################################################
+
+ +

String Operations

+ +
+'hello' + ' there\n'    # Returns 'hello there\n' ('\n' is a single newline)
+'-' * 5                 # Returns '-----'
+ord('A')                # Returns 65
+chr(65)                 # Returns 'A'
+ord('\u0E01')           # Returns 3585
+chr(3585)               # Returns '\u0E01' (1 character)
+ord('\U0001F60E')       # Returns 128526
+chr(128526)             # Returns '\U0001F60E' (1 character)
+
+ +

String Formatting

+ +There are several ways in which special codes embedded in a string can be replaced at run-time +with objects converted to strings. The various methods are listed below in order of increasing +flexibility. + +
Formatting with Template Class
+ +Simple approach similar to Unix shell variables. + +
+# Import Template class from string module
+from string import Template
+# Replace $-names in string with named arguments to substitute() method
+Template('$n $x or ${x}y $$').substitute(x='thing', n=1)    # Returns '1 thing or thingy $'
+
+ +
Formatting with Modulo Operator
+ +Old C printf-style formatting using '%' operator with many formatting options. + +
General Features
+ +
+# Single value (replaces %d-specifier)
+'answer = %d' % 42                                      # Returns 'answer = 42'
+# Tuple of values (number of %-specifiers must match length of tuple; otherwise TypeError
+# exception is raised)
+'%s = %d' % ('answer', 42)                              # Returns 'answer = 42'
+'%s = %d' % ('answer', 42, 1)                           # Raises TypeError exception
+'%s = %d' % ('answer',)                                 # Raises TypeError exception
+# Single value which is a tuple (needs to be embedded in another tuple)
+'mytuple = %s' % ((1, 2, 3),)                           # Returns 'mytuple = (1, 2, 3)'
+# Dictionary of values with key lookup (%()-specifiers can reference same key multiple
+# times, and not all keys need to be referenced; if key doesn't exist, KeyError exception
+# is raised)
+'%(x)d + %(x)d = %(z)d' % {'x':2, 'y':3, 'z':4}         # Returns '2 + 2 = 4'
+# Minimum field width and left/right alignment (right is default, left is specified with
+# '-')
+'%3s_%-3d_%7g_%3d' % ('A', 6, -1e7, 1234)               # Returns '  A_6  _ -1e+07_1234'
+# Dynamic minimum field width ('*' is replaced with the tuple item before the one that
+# replaces the whole %-specifier)
+'%*s_%-*d' % (2, 'A', 3, 6)                             # Returns ' A_6  '
+# Surrounding text (no whitespace needed)
+'one%dall' % 4                                          # Returns 'one4all'
+# '%%' produces a literal '%'
+'level in %% = %d%%' % 50                               # Returns 'level in % = 50%'
+
+ +
Integer Formats
+ +
+# Integer formats (all are identical, but %u is obsolete)
+'%d %i %u' % (-12, -13, -14)                            # Returns '-12 -13 -14'
+# Integer format with minimum field width and zero-padding (specified with '0' and field
+# width before 'd'; '*' is dynamic field width replaced with tuple item)
+'%3d_%03d_%0*d' % (-6, -7, 3, 8)                        # Returns ' -6_-07_008'
+# Integer format with forced sign (specified with '+'; '-' aligns left)
+'%+d_%+d_%-+3d_%+03d' % (6, -7, 8, 9)                   # Returns '+6_-7_+8 _+09'
+# Integer format with forced room for sign (specified with ' '; '-' aligns left but leaves
+# room for sign)
+'% d_% d_%- 3d_% 03d' % (6, -7, 8, 9)                   # Returns ' 6_-7_ 8 _ 09'
+# Hexadecimal formats ('#' prepends '0x' or '0X')
+'%x %x %X %04x %#x %#04X' % (10, -11, 12, 13, 14, 15)   # Returns 'a -b C 000d 0xe 0X0F'
+# Octal formats ('#' prepends '0o')
+'%o %o %04o %#o %#05o' % (8, -9, 10, 11, 12)            # Returns '10 -11 0012 0o13 0o014'
+# Integer format %d will round a float towards zero, but %x and %o will raise TypeError on
+# float
+'%d %d' % (4.9, -4.9)                                   # Returns '4 -4'
+
+ +
Floating Point Formats
+ +
+# Floating point formats (%f/e/g never/always/sometimes uses exponential format)
+'%f %e %g' % (1e-4, 2e-4, 3e-4)             # Returns '0.000100 2.000000e-04 0.0003'
+'%f %e %g' % (1e-5, 2e-5, 3e-5)             # Returns '0.000010 2.000000e-05 3e-05'
+'%f %e %g' % (1e5, 2e5, 3e5)                # Returns '100000.000000 2.000000e+05 300000'
+'%f %e %g' % (1e6, 2e6, 3e6)                # Returns '1000000.000000 2.000000e+06 3e+06'
+# Floating point formats with uppercase 'E' (%F is same as %f)
+'%F %E %G' % (1e-5, 2e-5, 3e-5)             # Returns '0.000010 2.000000E-05 3E-05'
+# Floating point formats %f/e with maximum number of digits after '.' (default 6)
+'%.1f %.1e' % (11.16, 22.6)                             # Returns '11.2 2.3e+01'
+# Floating point format %g with maximum total number of significant digits (default 6)
+'%.2g %.2g %.2g %.2g' % (11.6, 2.26, .336, 446)         # Returns '12 2.3 0.34 4.5e+02'
+# Floating point formats with minimum field width and zero-padding (specified with '0' and
+# field width before '.')
+'%4.1f_%04.1f_%08.1e_%04.2g' % (0.06, 1.16, 2.26, 3.36) # Returns ' 0.1_01.2_02.3e+00_03.4'
+# Floating point formats with dynamic widths ('*' is replaced with next tuple item)
+'%0*.*f_%0*.*e_%0*.*g' % (4, 1, 1.16,    8, 1, 2.26,
+                          4, 2, 3.36)                   # Returns'01.2_02.3e+00_03.4'
+# Floating point formats with forced sign (specified with '+')
+'%+.1f_%+.1e_%+.2g' % (1.16, 2.26, 3.36)                # Returns '+1.2_+2.3e+00_+3.4'
+'%+.1f_%+.1e_%+.2g' % (-1.16, -2.26, -3.36)             # Returns '-1.2_-2.3e+00_-3.4'
+# Floating point formats with forced room for sign (specified with ' ')
+'% .1f_% .1e_% .2g' % (1.16, 2.26, 3.36)                # Returns ' 1.2_ 2.3e+00_ 3.4'
+'% .1f_% .1e_% .2g' % (-1.16, -2.26, -3.36)             # Returns '-1.2_-2.3e+00_-3.4'
+# Alternate floating point formats (specified with '#' which always includes decimal point
+# and for %g also zeros); note that floating point formats accept int arguments but raise
+# TypeError on complex arguments
+'%#.0f %#.0e %#g' % (1, 2, 3)                           # Returns '1. 2.e+00 3.00000'
+'%.0f %.0e %g' % (1, 2, 3)                              # Returns '1 2e+00 3'
+
+ +
String Formats
+ +
+# String formats (%s/r/a uses str()/repr()/ascii() conversion)
+'%s %r %a' % (('rosé',) * 3)                            # Returns "rosé 'rosé' 'ros\\xe9'"
+# String format of any value that has a string representation
+'object = %s' % ((dict(x=5), list()),)                  # Returns "object = ({'x': 5}, [])"
+# String format with maximum field width
+'%.3s_%.3s' % ('A', 'ABCD')",                           # Returns 'A_ABC'
+# String format with minimum and maximum field width (maximum is applied first, and may be
+# smaller than minimum; '-' aligns left)
+'%-2.3s_%2.3s_%3.2s' % ('A', 'ABCD', 'ABC')",           # Returns 'A _ABC_ AB'
+# String format with dynamic minimum/maximum field width ('*' is replaced with next tuple
+# item)
+'%*s_%.*s_%*.*s' % (3, 'A', 2, 'ABC', 3, 2, 'ABC')",    # Returns '  A_AB_ AB'
+
+ +
Character Formats
+ +
+# Single-character format (with or without minimum field width)
+'%c_%3c' % ('A', 0xe9)                                  # Returns 'A_  é'
+
+ +
Formatting with str.format Method
+ +Newer str.format() method with more formatting and object access options than printf-style. + +
General Features
+ +
+# Single argument to format method (replaces {}-specifier)
+'answer = {}'.format(42)                                # Returns 'answer = 42'
+# Multiple positional arguments (replace {}-specifiers sequentially; number of arguments
+# must be equal to or greater than number of {}-specifiers, otherwise IndexError exception
+# is raised; extra arguments are ignored)
+'{} = {}'.format('answer', 42, 43)                      # Returns 'answer = 42'
+'{} = {}'.format('answer',)                             # Raises IndexError exception
+# Identified positional arguments ('{0}' refers to first argument, '{1}' to second, etc.;
+# same argument can be referenced multiple times, and not all arguments need to be
+# referenced; if argument doesn't exist, IndexError exception is raised)
+'{1} + {1} = {0}'.format(4, 2, 8)                       # Returns '2 + 2 = 4'
+'{1} + {1} = {0}'.format(4)                             # Raises IndexError exception
+# Identified named arguments (same argument can be referenced multiple times, and not all
+# arguments need to be referenced; if argument doesn't exist, KeyError exception is
+# raised)
+'{x} + {x} = {z}'.format(x=2, y=3, z=4)                 # Returns '2 + 2 = 4'
+'{x} + {x} = {z}'.format(y=3, z=4)                      # Raises KeyError exception
+# Identified named arguments can be mixed with either identified or sequential positional
+# arguments, but ValueError exception will be raised if there are both identified and
+# sequential positional arguments
+'{x} + {x} = {1}'.format(8, 4, y=3, x=2)                # Returns '2 + 2 = 4'
+'{x} + {x} = {}'.format(4, y=3, x=2)                    # Returns '2 + 2 = 4'
+'{0} + {0} = {}'.format(2, 4)                           # Raises ValueError exception
+# Accessing indexed items and attributes of arguments
+'{[a][1].imag} {.stop}'.format({'a':[7, 8+9j]}, range(5))       # Returns '9.0 5'
+'{0[a][1].imag} {x.stop}'.format({'a':[7, 8+9j]}, x=range(5))   # Returns '9.0 5'
+# Minimum field width and left/center/right alignment (specified with '<'/'^'/'>';
+# right is default for numbers, left for others, so this is different than when
+# formatting with the '%' operator)
+'{:3s}_{:3d}_{:7g}_{:3d}'.format('A', 6, -1e7, 1234)    # Returns 'A  _  6_ -1e+07_1234'
+'{:>3s}_{:^3d}_{:<7g}'.format('A', 6, -1e7)             # Returns '  A_ 6 _-1e+07 '
+# Minimum field width and specified fill character (alignment must also be specified)
+'{:x<3s}_{:>>5d}'.format('A', -6)                       # Returns 'Axx_>>>-6'
+# Dynamic minimum field width (arguments are taken in the order of the '{' characters, so
+# this makes the order different than for the '%*' specifier when
+# formatting with the '%' operator)
+'{:{}s}_{:<{}d}'.format('A', 2, 6, 3)                   # Returns 'A _6  '
+# Dynamic everything (same as above but now with all specifier parts (after colon) given as
+# arguments)
+'{:{}{}}_{:{}}'.format('A', 2, 's', 6, '<3d')           # Returns 'A _6  '
+'{0:{1}{2}}_{3:{4}}'.format('A', 2, 's', 6, '<3d')      # Returns 'A _6  '
+# Surrounding text (no whitespace needed)
+'one{}all'.format(4)                                    # Returns 'one4all'
+# '{{' and '}}' produce literal '{' and '}'
+'{{br{}s}}'.format('ace')                               # Returns '{braces}'
+
+ +
Integer Formats
+ +
+# Integer format ('{:d}' produces same result as '{}' but will raise ValueError exception
+# if argument is not an int (e.g. a float))
+'{0} {0:d}'.format(-12)                                 # Returns '-12 -12'
+'{:d}'.format(-12.0)                                    # Raises ValueError exception
+# Integer format with minimum field width and zero-padding (specified with '0' and field
+# width after ':'; nested '{}' is dynamic field width replaced with one of the arguments)
+'{:3d}_{:03d}_{:0{}d}'.format(-6, -7, 8, 3)             # Returns ' -6_-07_008'
+# Integer format with forced sign (specified with '+'; '<' aligns left)
+'{:+d}_{:+d}_{:<+3d}_{:+03d}'.format(6, -7, 8, 9)       # Returns '+6_-7_+8 _+09'
+# Integer format with forced room for sign (specified with ' '; '<' aligns left but leaves
+# room for sign)
+'{: d}_{: d}_{:< 3d}_{: 03d}'.format(6, -7, 8, 9)       # Returns ' 6_-7_ 8 _ 09'
+# Integer format with minimum field width, left aligned sign, and right aligned number
+# (specified with '='; this is the default when using zero-padding; 'x' is an arbitrary
+# fill character)
+'{:=3d}_{:=+3d}_{:x=5d}'.format(-6, 7, -8)              # Returns '- 6_+ 7_-xxx8'
+# Hexadecimal formats ('#' prepends '0x' or '0X')
+'{:x} {:x} {:X} {:04x} {:#x} {:#04X}'.format(
+                            10, -11, 12, 13, 14, 15)    # Returns 'a -b C 000d 0xe 0X0F'
+# Octal formats ('#' prepends '0o')
+'{:o} {:o} {:04o} {:#o} {:#05o}'.format(
+                            8, -9, 10, 11, 12)          # Returns '10 -11 0012 0o13 0o014'
+# Binary formats ('#' prepends '0b')
+'{:b} {:b} {:04b} {:#b} {:#05b}'.format(2, -3, 4, 5, 3) # Returns '10 -11 0100 0b101 0b011'
+# Integer format with thousands separator (specified with ',' or '_', the former is only
+# valid for 'd')
+'{:09,d} {:_d}'.format(6, 70000)                        # Returns '0,000,006 70_000'
+'{:_x} {:_o} {:_b}'.format(0x89abc, 0o34567, 31)        # Returns '8_9abc 3_4567 1_1111'
+'{:,x}'.format(1)                                       # Raises ValueError exception
+'{:,o}'.format(1)                                       # Raises ValueError exception
+'{:,b}'.format(1)                                       # Raises ValueError exception
+
+ +
Floating Point Formats
+ +
+# Floating point formats (f/e/g never/always/sometimes uses exponential format)
+'{:f} {:e} {:g}'.format(1e-4, 2e-4, 3e-4)   # Returns '0.000100 2.000000e-04 0.0003'
+'{:f} {:e} {:g}'.format(1e-5, 2e-5, 3e-5)   # Returns '0.000010 2.000000e-05 3e-05'
+'{:f} {:e} {:g}'.format(1e5, 2e5, 3e5)      # Returns '100000.000000 2.000000e+05 300000'
+'{:f} {:e} {:g}'.format(1e6, 2e6, 3e6)      # Returns '1000000.000000 2.000000e+06 3e+06'
+'{0:f} {0:e} {0:g}'.format(float('-inf'))   # Returns '-inf -inf -inf'
+'{0:f} {0:e} {0:g}'.format(float('nan'))    # Returns 'nan nan nan'
+# Floating point format '{}' is similar to '{:g}' with a few exceptions
+'{0} {0:g}'.format(1.00)                    # Returns '1.0 1'
+'{0} {0:g}'.format(1.23456789012345678)     # Returns '1.2345678901234567 1.23457'
+'{0} {0:g}'.format(1.2e15)                  # Returns '1200000000000000.0 1.2e+15'
+'{0} {0:g}'.format(1.2e16)                  # Returns '1.2e+16 1.2e+16'
+'{0} {0:g}'.format(1.2e-4)                  # Returns '0.00012 0.00012'
+'{0} {0:g}'.format(1.2e-5)                  # Returns '1.2e-05 1.2e-05'
+# Floating point formats with uppercase 'E' (F is same as f, except for inf and nan)
+'{:F} {:E} {:G}'.format(1e-5, 2e-5, 3e-5)   # Returns '0.000010 2.000000E-05 3E-05'
+'{0:F} {0:E} {0:G}'.format(float('-inf'))   # Returns '-INF -INF -INF'
+'{0:F} {0:E} {0:G}'.format(float('nan'))    # Returns 'NAN NAN NAN'
+# Floating point percentage format (similar to format f, but multiplies by 100 and appends
+# '%')
+'{:%} {:%}'.format(1, 1e-5)                 # Returns '100.000000% 0.001000%'
+# Floating point formats f/e/% with maximum number of digits after '.' (default 6)
+'{:.1f} {:.1e} {:.1%}'.format(11.16, 22.6, .3336)       # Returns '11.2 2.3e+01 33.4%'
+# Floating point format g with maximum total number of significant digits (default 6)
+'{:.2g} {:.2g} {:.2g} {:.2g}'.format(
+                                11.6, 2.26, .336, 446)  # Returns '12 2.3 0.34 4.5e+02'
+# Floating point formats with minimum field width and zero-padding (specified with '0' and
+# field width before '.')
+'{:4.1f}_{:04.1f}_{:08.1e}_{:04.2g}'.format(
+                                0.06, 1.16, 2.26, 3.36) # Returns ' 0.1_01.2_02.3e+00_03.4'
+# Floating point formats with dynamic widths (nested '{}' is replaced with next argument)
+'{:0{}.{}f}_{:0{}.{}e}_{:0{}.{}g}'.format(1.16, 4, 1,
+                                          2.26, 8, 1,
+                                          3.36, 4, 2)   # Returns '01.2_02.3e+00_03.4'
+# Floating point formats with forced sign (specified with '+')
+'{:+.1f}_{:+.1e}_{:+.2g}'.format(1.16, 2.26, 3.36)      # Returns '+1.2_+2.3e+00_+3.4'
+'{:+.1f}_{:+.1e}_{:+.2g}'.format(-1.16, -2.26, -3.36)   # Returns '-1.2_-2.3e+00_-3.4'
+# Floating point formats with forced room for sign (specified with ' ')
+'{: .1f}_{: .1e}_{: .2g}'.format(1.16, 2.26, 3.36)      # Returns ' 1.2_ 2.3e+00_ 3.4'
+'{: .1f}_{: .1e}_{: .2g}'.format(-1.16, -2.26, -3.36)   # Returns '-1.2_-2.3e+00_-3.4'
+# Alternate floating point formats (specified with '#' which always includes decimal point
+# and for format g also zeros); note that floating point formats accept int and complex
+# arguments
+'{:#.0f} {:#.0e} {:#g}'.format(1+0j, 2, 3)              # Returns '1.+0.j 2.e+00 3.00000'
+'{:.0f} {:.0e} {:g}'.format(1+0j, 2, 3)                 # Returns '1+0j 2e+00 3'
+# Floating point format with thousands separator (specified with ',' or '_')
+'{:09,.0f} {:09,.0e} {:,g}'.format(6, 7, 8e4)       # Returns '0,000,006 0,007e+00 80,000'
+'{:09_.0f} {:09_.0e} {:_g}'.format(6, 7, 8e4)       # Returns '0_000_006 0_007e+00 80_000'
+
+ +
String Formats
+ +
+# String format ('{:s}' produces same result as '{}' but will raise ValueError exception if
+# argument is not a string
+'{0} {0:s}'.format('ABC')                               # Returns 'ABC ABC'
+'{:s}'.format(42)                                       # Raises ValueError exception
+# String format with forced conversion of argument to string (!s/r/a uses
+# str()/repr()/ascii() conversion)
+'{!s:s}'.format(42)                                     # Returns '42'
+'{0!s} {0!r} {0!a}'.format('rosé')                      # Returns "rosé 'rosé' 'ros\\xe9'"
+# String format with maximum field width
+'{:.3s}_{:.3s}'.format('A', 'ABCD')                     # Returns 'A_ABC'
+# String format with minimum and maximum field width (maximum is applied first, and may be
+# smaller than minimum; '>' aligns right)
+'{:>2.3s}_{:2.3s}_{:3.2s}'.format('A', 'ABCD', 'ABC')               # Returns ' A_ABC_AB '
+# String format with dynamic minimum/maximum field width (nested '{}' is replaced with next
+# argument)
+'{:{}s}_{:.{}s}_{:{}.{}s}'.format('A', 3, 'ABC', 2, 'ABC', 3, 2)    # Returns 'A  _AB_AB '
+
+ +
Character Formats
+ +
+# Single-character format (with or without minimum field width); raises ValueError if
+# argument is not an int
+'{:c}_{:3c}'.format(65, 0xe9)                           # Returns 'A_  é'
+'{:c}'.format('A')                                      # Raises ValueError exception
+'{:c}'.format(65.0)                                     # Raises ValueError exception
+
+ +
Formatting with F-String Literals
+ +Latest f-string approach (formatted string literals added in Python 3.6) with the same formatting options as +str.format() but (almost) arbitrary expressions can be specified within the format string. However, unlike the other +methods above, f-strings cannot be stored for later formatting - they are immediately evaluated into string objects. + +
+# Misc initializations for use below
+k = 1
+n = 4
+x = 5+6j
+
+# F-strings are prefixed with 'f' or 'F' (no difference) and support same formatting as
+# str.format method
+f'{n:03d} {x.real:0{n}.{k}f} {x.imag!s:.2s}'                # Returns '004 05.0 6.'
+F'{x:-^{k}{n}}'                                             # Returns '----(5+6j)----'
+# Arbitrary expressions are allowed in f-strings (unlike in str.format)
+f'There {"is" if k==1 else "are"} {k} item{"s"[:k!=1]}'     # Returns 'There is 1 item'
+f'There {"is" if n==1 else "are"} {n} item{"s"[:n!=1]}'     # Returns 'There are 4 items'
+# Backslashes and quotes (even the same type of quotes as those delimiting the f-string)
+# can be used freely (since Python 3.12)
+f'{'A\\B':\t^7}\n'                                          # Returns '\t\tA\\B\t\t\n'
+# The expressions themselves can be included in the result (specified with '=')
+f'{n=},{ n * 2 = :+d}'                                      # Returns 'n=4, n * 2 = +8'
+
+ +

Conditional Expressions

+ +
+r = x if a else y       # Assigns x to r if a is True (y is not evaluated),
+                        # otherwise assigns y to r (x is not evaluated)
+r = x if a \
+    else y if b \
+    else z              # (Note: backslashes used to break single line)
+
+ +

Regular Expressions

+ +

Functions and Methods

+ +Compiled regular expression objects are highlighted below for clarity, as many +module functions (re.xxx()) have compiled object method equivalents (myobj.xxx()), +but do not support quite the same parameters (module functions support flags; +compiled object methods support start/end indexes). + +
+import re                   # Imports regular expression module
+
+# Compile and match
+rs1 = r'(\w)(.*?)([0-5](Z)?)'   # Assigns a (raw) string containing a regular expression
+rc1 = re.compile(rs1)       # Compiles regular expr for faster repeated execution
+type(rc1)                   # Returns class re.Pattern
+isinstance(rc1, re.Pattern) # Returns True
+re.compile(r'(')            # Raises re.error exception due to bad regular expression
+s1 = 'abc950'               # Some string to search for matches
+m1 = re.match(rs1, s1)      # Finds a match at start of string s1, and returns
+                            # a match object - or None if no match was found
+m1 = rc1.match(s1)          # Same as above, but uses compiled regular expression object
+if m1:                      # If a match was found, then...
+    print(m1.group())       # Prints 'abc95' - the part of s1 matched by rs1
+    print(m1[0])            # Prints 'abc95' (same as above)
+    print(m1.group(1))      # Prints 'a' - captured by 1st '()' in rs1
+    print(m1[1])            # Prints 'a' (same as above)
+    print(m1.group(3, 2))   # Prints "('5', 'bc9')" - from 3rd & 2nd '()' in rs1
+    print(m1.groups())      # Prints "('a', 'bc9', '5', None)" - from all '()' in rs1
+                            # Note: non-matching '()' returns None
+    print(m1.start())       # Prints 0 - start index of match in s1
+    print(m1.end())         # Prints 5 - end index + 1 of match in s1
+    print(m1.span())        # Prints '(0, 5)' - start and end of match
+    print(m1.start(2))      # Prints 1 - start index of 2nd '()' capture in s1
+    print(m1.end(2))        # Prints 4 - end index + 1 of 2nd '()' capture in s1
+    print(m1.span(2))       # Prints '(1, 4)' - start and end of 2nd '()'
+
+# Fullmatch
+m1 = rc1.fullmatch(s1)      # Like rc1.match() but finds a match to whole string s1
+print(m1.group())           # Prints 'abc950' - the part of s1 matched by rs1
+print(m1.groups())          # Prints "('a', 'bc95', '0', None)" - from all '()' in rs1
+
+# Search
+s2 = '.20 391Z'                 # A new string to search for matches
+m2 = rc1.search(s2)             # Finds first match in string s2
+if m2:
+    print(m2.groups())          # Prints "('2', '', '0', None)" - from all '()' in rs1
+m2 = rc1.search(s2, m2.end())   # Finds first match in string s2 starting from previous end
+if m2:
+    print(m2.groups())          # Prints "('3', '9', '1Z', 'Z')" - from all '()' in rs1
+
+# Finditer
+ri1 = rc1.finditer(s2)          # Returns an iterator
+type(ri1)                       # Returns class with name 'callable_iterator'
+print(next(ri1).groups())       # Prints "('2', '', '0', None)"
+print(next(ri1).groups())       # Prints "('3', '9', '1Z', 'Z')"
+
+# Findall
+print(rc1.findall(s2))          # Prints "[('2', '', '0', ''), ('3', '9', '1Z', 'Z')]"
+                                # Note: non-matching '()' returns '' (not None)
+rs3 = r'\d\d'                   # String containing regular expression with no '()'
+s3 = ' 12.345-6789a'            # A new string to search for matches
+print(re.findall(rs3, s3))      # Prints "['12', '34', '67', '89']"
+
+# Split
+print(re.split(rs3, s3))        # Prints "[' ', '.', '5-', '', 'a']"
+
+# Sub and subn (substitution)
+print(re.sub(rs3, 'xy', s3))        # Prints ' xy.xy5-xyxya'
+print(re.subn(rs3, 'xy', s3))       # Prints "(' xy.xy5-xyxya', 4)" (4 substitutions)
+print(rc1.sub(r'_\1_\g<1>4_', s1))  # Prints '_a_a4_0' (\1 = \g<1> = 1st captured group)
+print(rc1.sub(r'(\g<0>)', s1))      # Prints '(abc95)0' (\g<0> = whole match)
+def f(m): return m.group(1).upper() # Function that returns replacement string for a match
+print(rc1.sub(f, s1))               # Prints 'A0' (calls function f for each match)
+
+ +

Start/End Index Parameters

+ +

Start/end indices may be supplied to compiled regular expression object methods to restrict their operation to a +portion of the input string.

+ +

WARNING: ONLY compiled object methods (e.g. rc1.match()) support start/end index parameters! If used with module +functions (e.g. re.match()), these parameters may be interpreted as flags and you may not get an error - just strange +behavior!

+ +
+import re
+
+rs1 = r'(\w)(.*?)([0-5](Z)?)'   # Assigns a (raw) string containing a regular expression
+rc1 = re.compile(rs1)       # Compiles regular expr
+s1 = 'abc950'
+m1 = rc1.match(s1, 2)       # Finds a match at start of string s1[2:]
+if m1:                      # If a match was found, then...
+    print(m1.groups())      # Prints "('c', '9', '5', None)" - from all '()' in rs1
+print(rc1.match(s1, 1, 4))  # Prints 'None' because rs1 does not match s1[1:4] ('bc9')
+
+ +

Flags

+ +

Flags may be supplied to regular expression module functions to modify the behavior of a regular expression.

+ +

WARNING: ONLY module functions (e.g. re.match()) support flags! If used with compiled object methods (e.g. rc1.match()), +the flags may be interpreted as indexes and you may not get an error - just strange behavior!

+ +
+import re
+
+# Flags:
+#   re.I (or re.IGNORECASE): case-insensitive matching;
+#   re.M (or re.MULTILINE):  '^' and '$' match start/end of each line within string;
+#   re.S (or re.DOTALL):     '.' matches also newline
+
+rs4 = r'^hi.\w+$'
+rc4 = re.compile(rs4, re.I|re.M|re.S)    # Applies flags I, M, and S to rs4 in rc4
+s4 = 'Hi\nHo\nHi\nHUM'
+print(rc4.findall(s4))                   # Prints "['Hi\nHo', 'Hi\nHUM']"
+
+# Flags:
+#   re.X (or re.VERBOSE): extra whitespace and comments allowed in regular expression
+
+rs5 = r"""      # This is a verbose regular expression string (these comments are inside it)
+    (           # Start of 1st capturing group
+        \w      # Word character
+    )           # End of 1st capturing group
+    (           # Start of 2nd capturing group
+        .*?     # Minimal sequence of 0 or more characters except \n
+    )           # End of 2nd capturing group
+    (           # Start of 3rd capturing group
+        [0-5]   # Digit in range 0-5
+        (       # Start of 4th capturing group
+            Z   # 'Z' character
+        )       # End of 4th capturing group
+        ?       # 4th group is optional
+    )           # End of 3rd capturing group
+"""
+m1 = re.match(rs5, 'abc950', re.X)  # Applies flag X to rs5; returns the same result as
+                # re.match(r'(\w)(.*?)([0-5](Z)?)', 'abc950') - see earlier
+
+# Flags:
+# (These character set flags cannot be combined with each other)
+#   re.A (or re.ASCII):   \d, \s, \w classes are restricted to ASCII characters (this also
+#                         affects \b, \B, \D, \S, \W);
+#                         this is the default for bytes-type regular expressions;
+#   re.L (or re.LOCALE):  \w class and re.I flag depend on the current locale (discouraged);
+#                         only allowed for bytes-type regular expressions;
+#   re.U (or re.UNICODE): \d, \s, \w classes follow unicode rules (this also affects
+#                         \b, \B, \D, \S, \W);
+#                         this is the default for str-type regular expressions;
+#                         only allowed for str-type regular expressions
+
+re.search(r'\d\s\w', '३\u2003Ω 3 z')[0]       # Returns '३\u2003Ω'
+re.search(r'\d\s\w', '३\u2003Ω 3 z', re.A)[0] # Returns '3 z'
+
+# Flags:
+#   re.NOFLAG: no effect; convenient name for the value 0 which represents no flags
+
+ +There is also a DEBUG flag which prints detailed - but somewhat cryptic - information about the regular expression: + +
+import re
+
+# Flags:
+#   re.DEBUG:  debug info is printed
+
+re.match(r'\w+', 'ab', re.DEBUG)        # Returns 'ab' and prints the debug info below
+
+ +
+MAX_REPEAT 1 MAXREPEAT
+  IN
+    CATEGORY CATEGORY_WORD
+
+ 0. INFO 4 0b0 1 MAXREPEAT (to 5)
+ 5: REPEAT_ONE 9 1 MAXREPEAT (to 15)
+ 9.   IN 4 (to 14)
+11.     CATEGORY UNI_WORD
+13.     FAILURE
+14:   SUCCESS
+15: SUCCESS
+
+ +

Example: String Tokenizer

+ +Here's an example of a string tokenizer which tries to match various regular expressions at the same position in the +input string until a match is found, then repeats the process at the position following the match: + +
+import re                           # Imports regular expression module
+
+# Prepare a sequence of compiled regular expressions and associated functions;
+# each function converts the matched string to a token
+token_matchers = [(func, re.compile(regx)) for func, regx in (
+    (float, r'\s*((?:\d+\.\d*|\.\d+)(?:[eE][-+]?\d+)?)\s*'),
+    (int,   r'\s*(\d+)\s*'),
+    (str,   r'\s*(\*\*|\W)\s*'))]
+
+# Define a function which parses a string and returns a list of found tokens
+def get_tokens(in_str):
+    tokens = []
+    pos = 0                                     # Sets matching position to start of string
+    while pos < len(in_str):                 # Repeats while not at end of string
+        for func, regx in token_matchers:       # Tries each regular expr in turn
+            if m := regx.match(in_str, pos):    # When a regular expr matches at pos:
+                tokens.append(func(m.group(1))) # Uses func to convert matched string to
+                                                # token and adds it to list of tokens
+                pos = m.end()                   # Moves position to next char after match
+                break                           # Ends for-loop
+        else:                                   # If for-loop found nothing, then
+            raise ValueError(f'Bad token: {in_str[pos:]!r}')    # raises exception
+    return tokens                               # Returns list of tokens to caller of
+                                                # get_tokens
+
+get_tokens('23*(.45 + -6.7e-2)')    # Returns [23, '*', '(', 0.45, '+', '-', 0.067, ')']
+
+ +

Regular Expression Language

+ +This section details the regular expression language used in the string passed as the first argument to e.g. re.match. +In the following examples, these phrases are used: + +Note that re.match(REGEX, INPUT) only finds a match at the start of INPUT. + +
+# Basic combinations
+r'XY'       # X then Y; binds tighter than X|Y but looser than quantifiers;
+            #   r'abc' matches 'abc' in 'abcd', but not 'acb'
+r'X|Y'      # X or Y;
+            #   r'ab|c|d' matches 'ab' in 'abcd', 'c' in 'cd', 'd' in 'de', but not 'ac'
+
+ +
+# Character classes
+r'.'        # Any single character - except newline if not in dot-all mode;
+            #   r'.' matches 'a' in 'ab', ' ' in ' a', '\r' in '\r', but not '\n';
+            #   re.match(r'.', '\n', re.DOTALL)[0] returns '\n'
+r'\d'       # Any digit character (as defined by o.isdecimal(), see section
+            # Container Object Attributes);
+            #   r'\d' matches '7' in '78', '\u0e52' in '\u0e52', but not '\u00b2'
+r'\D'       # Any non-digit character;
+            #   r'\D' matches 'a' in 'ab', '\n' in '\n', but not '7'
+r'\s'       # Any whitespace character;
+            #   r'\s' matches ' ', '\t', '\n', '\r', '\f', '\v', but not '.'
+r'\S'       # Any non-whitespace character;
+            #   r'\S' matches '.', but not ' ', '\t', '\n', '\r', '\f', '\v'
+r'\w'       # Any word character (as defined by o.isalnum() plus '_', see section
+            # Container Object Attributes);
+            #   r'\w' matches 'a', 'A', '7', '_', '\u00b2', but not ' ', '.', '-'
+r'\W'       # Any non-word character;
+            #   r'\W' matches ' ', '.', '-', but not 'a', 'A', '7', '_', '\u00b2'
+r'[XYA-C]'  # Any single character that is X, Y, or in range A-C;
+            #   r'[-a\]]' matches '-' in '-4', 'a' in 'ab', ']' in ']a', but not 'b';
+            #   r'[a-c6-8]' matches 'b' in 'bc', 'c' in 'cd', '7' in '78', but not 'd';
+            #   r'[\d\s]' matches '7' in '78', ' ' in ' a', but not 'a';
+r'[^XYA-C]' # Any single character that is NOT X, Y, or in range A-C;
+            #   r'[^a-c3]' matches 'd' in 'de', '\n' in '\n', but not 'a', 'b', 'c', or '3'
+
+ +
+# Exact quantifier
+r'X{3}'     # Sequence of 3 Xs;
+            #   r'ab{3}' matches 'abbb' in 'abbbbb', but not 'abb'
+
+# Greedy quantifiers
+r'X?'       # Largest sequence of 0 or 1 X;
+            #   r'ab?' matches 'a' in 'a', 'ab' in 'abbb'
+r'X*'       # Largest sequence of 0 or more Xs;
+            #   r'ab*' matches 'a' in 'a', 'abbb' in 'abbb'
+r'X+'       # Largest sequence of 1 or more Xs;
+            #   r'ab+' matches 'ab' in 'ab', 'abbb' in 'abbb', but not 'a'
+r'X{2,}'    # Largest sequence of 2 or more Xs;
+            #   r'ab{2,}' matches 'abb' in 'abb', 'abbbb' in 'abbbb', but not 'ab'
+r'X{,3}'    # Largest sequence of 0 to 3 Xs;
+            #   r'ab{,3}' matches 'a' in 'a', 'abbb' in 'abbbb'
+r'X{2,3}'   # Largest sequence of 2 to 3 Xs;
+            #   r'ab{2,3}' matches 'abb' in 'abb', 'abbb' in 'abbbb', but not 'ab'
+
+# Minimal quantifiers
+r'X??'      # Smallest sequence of 0 or 1 X;
+            #   r'ab??' matches 'a' in 'abbb';
+            #   r'ab??c' matches 'ac' in 'ac', 'abc' in 'abc', but not 'abbc'
+r'X*?'      # Smallest sequence of 0 or more items;
+            #   r'ab*?' matches 'a' in 'abbb';
+            #   r'ab*?c' matches 'ac' in 'ac', 'abbbc' in 'abbbc'
+r'X+?'      # Smallest sequence of 1 or more items;
+            #   r'ab+?' matches 'ab' in 'abbb';
+            #   r'ab+?c' matches 'abc' in 'abc', 'abbbc' in 'abbbc', but not 'ac'
+r'X{2,}?'   # Smallest sequence of 2 or more Xs;
+            #   r'ab{2,}?' matches 'abb' in 'abbb';
+            #   r'ab{2,}?c' matches 'abbc' in 'abbc', 'abbbc' in 'abbbc', but not 'abc'
+r'X{,3}?'   # Smallest sequence of 0 to 3 Xs;
+            #   r'ab{,3}?' matches 'a' in 'abbb';
+            #   r'ab{,3}?c' matches 'ac' in 'ac', 'abbbc' in 'abbbc', but not 'abbbbc'
+r'X{2,3}?'  # Smallest sequence of 2 to 3 Xs;
+            #   r'ab{2,3}?' matches 'abb' in 'abbb';
+            #   r'ab{2,3}?c' matches 'abbc' in 'abbc', 'abbbc' in 'abbbc', but not 'abc' or
+            #   'abbbbc'
+
+# Greedy and possessive quantifiers
+r'X?+'      # Largest sequence of 0 or 1 X with no back-tracking;
+            #   r'ab?+' matches 'a' in 'a', 'ab' in 'abbb';
+            #   r'ab?+b' matches 'abb' in 'abb', but not 'ab'
+r'X*+'      # Largest sequence of 0 or more Xs with no back-tracking;
+            #   r'ab*+' matches 'a' in 'a', 'abbb' in 'abbb';
+            #   r'ab*+b' does not match anything
+r'X++'      # Largest sequence of 1 or more Xs with no back-tracking;
+            #   r'ab++' matches 'ab' in 'ab', 'abbb' in 'abbb', but not 'a';
+            #   r'ab++b' does not match anything
+r'X{2,}+'   # Largest sequence of 2 or more Xs with no back-tracking;
+            #   r'ab{2,}+' matches 'abb' in 'abb', 'abbb' in 'abbb', but not 'ab';
+            #   r'ab{2,}+b' does not match anything
+r'X{,3}+'   # Largest sequence of 0 to 3 Xs with no back-tracking;
+            #   r'ab{,3}+' matches 'a' in 'a', 'abbb' in 'abbbb';
+            #   r'ab{,3}+b' matches 'abbbb' in 'abbbb', but not 'abbb'
+r'X{2,3}+'  # Largest sequence of 2 to 3 Xs with no back-tracking;
+            #   r'ab{2,3}+' matches 'abb' in 'abb', 'abbb' in 'abbbb', but not 'ab';
+            #   r'ab{2,3}+b' matches 'abbbb' in 'abbbb', but not 'abbb'
+
+ +
+# Zero-width assertions (consuming no characters)
+r'^'        # Matches start of string (or after each newline in multiline mode);
+            #   re.findall(r'^\d', '23\n4') returns ['2'];
+            #   re.findall(r'^\d', '23\n4', re.MULTILINE) returns ['2', '4']
+r'\A'       # Matches start of string (regardless of multiline mode);
+            #   re.findall(r'\A\d', '23\n4') returns ['2'];
+            #   re.findall(r'\A\d', '23\n4', re.MULTILINE) returns ['2']
+r'$'        # Matches end of string or before newline at end of string (or before each
+            # newline in multiline mode);
+            #   both r'\n$' and r'$\n' match '\n';
+            #   re.findall(r'$', '\n') returns ['', ''];
+            #   re.findall(r'\d$', '2\n34') returns ['4'];
+            #   re.findall(r'\d$', '2\n34', re.MULTILINE) returns ['2', '4']
+r'\Z'       # Matches end of string (regardless of multiline mode);
+            #   r'\n\Z' matches '\n', whereas r'\Z\n' matches nothing;
+            #   re.findall(r'\Z', '\n') returns [''];
+            #   re.findall(r'\d\Z', '2\n34') returns ['4'];
+            #   re.findall(r'\d\Z', '2\n34', re.MULTILINE) returns ['4']
+r'\b'       # Matches start or end of word (\w characters);
+            #   r'\b.+?\b' matches 'a2_Ω' in 'a2_Ω,a';
+            #   re.findall(r'\b.+?\b', 'A2! _Ω') returns ['A2', '! ', '_Ω']
+r'\B'       # Matches anywhere but start or end of word (\w characters);
+            #   r'.\B.+?\B' matches 'a2,_ Ω' in 'a2,_ Ωa';
+            #   re.findall(r'\B.+?\B', 'A2! _Ω') returns ['2!', ' _']
+r'(?=X)'    # Positive lookahead assertion matching current position if a match for X
+            # starts at this position;
+            #   r'ab(?=cd)' matches 'ab' in 'abcd', but not 'abdc'
+r'(?!X)'    # Negative lookahead assertion matching current position if no match for X
+            # starts at this position;
+            #   r'ab(?!cd)' matches 'ab' in 'abdc', but not 'abcd'
+r'(?<=X)'   # Positive lookbehind assertion matching current position if a match for X
+            # ends at this position;
+            #   re.findall(r'(?<=a).', 'aabacd') returns ['a', 'b', 'c']
+r'(?<!X)'   # Negative lookbehind assertion matching current position if no match for X
+            # ends at this position;
+            #   re.findall(r'(?<!a).', 'aabacd') returns ['a', 'a', 'd']
+
+ +
+# Groups
+r'(X)'          # Capturing group matching X;
+                #   r'(.*?)(\d)' matches 'ab2' in 'ab23' and captures 'ab' and '2', i.e.:
+                #     re.match(r'(.*?)(\d)', 'ab23').groups() returns ('ab', '2');
+                #   groups may be nested and capture in the order of their '(', e.g.:
+                #     re.match(r'((a(b))c)d', 'abcd').groups() returns ('abc', 'ab', 'b');
+                #   if a group doesn't contribute to the match, it captures None, e.g.:
+                #     re.match(r'a(.)*|(.)', 'a').groups() returns (None, None);
+                #   if a group is repeated, only the last match is captured, e.g.:
+                #     re.match(r'(\s)*(\d)*(.)*', '2ab').groups() returns (None, '2', 'b');
+                #   note: putting the quantifier inside the group is entirely different:
+                #     re.match(r'(\s*)(\d*)(.*)', '2ab').groups() returns ('', '2', 'ab')
+r'(?P<name>X)'  # Named capturing group matching X;
+                #   r'(?P<first>\d*)' captures '23' in '23a' and names it 'first', i.e.:
+                #     re.match(r'(?P<first>\d*)', '23a')['first'] returns '23';
+                #     re.match(r'(?P<first>\d*)', '23a')[1] returns '23'
+r'(?:X)'        # (Non-capturing) group matching X;
+                #   r'(?:aa)+' matches 'aaaa' in 'aaaaa' and captures nothing, i.e.:
+                #     re.match(r'(?:aa)+', 'aaaaa')[0] returns 'aaaa';
+                #     re.match(r'(?:aa)+', 'aaaaa').groups() returns ()
+r'(?auLimsx-imsx:X)'    # Flagged group matching X; each letter corresponds to a flag to be
+                        # enabled (or disabled if preceded by '-'), e.g. (?i:X) enables
+                        # re.I for expression X, and (?-i:X) disables re.I for X;
+                        #   r'(?ims:.*?^b.c$)' matches 'a\nB\nc' in 'a\nB\nc\nd';
+                        #   r'(?x: a b c)' matches 'abc' in 'abcd';
+                        #   r'(?a:\w+)' matches 'a2' in 'a2Ω';
+                        #   re.match(r'(?u:\w+)', 'a2Ω', re.A)[0] returns 'a2Ω'
+r'(?>X)'        # Atomic group matching X (no back-tracking to points inside X once X is
+                # matched);
+                #   r'ab?b' matches both 'ab' and 'abb', but - like r'ab?+b' - r'a(?>b?)b'
+                #   matches 'abb' but not 'ab';
+r'(?#X)'        # Comment group matching nothing (X is the comment);
+                #   r'a(?#That was an a, now comes a b)b' matches 'ab'
+
+ +
+# Backreferences (referencing results of previous capturing groups)
+r'\1'           # Matches what 1st capturing group matched;
+                #   r'(.)(.)\2\1' matches 'abba', but not 'abab'
+r'(?P=name)'    # Matches what named capturing group matched;
+                #   r'(?P<first>\d+)(?P=first)' matches '123123', but not '123456'
+r'(?(1)X)'      # Matches X if 1st capturing group matched something, otherwise matches
+                # current position;
+                #   r'(\()?(\[)?a(?(2)\])(?(1)\))' matches '([a])', '(a)', '[a]', 'a', but
+                #   not '([a]', '([a)', '([a)]'
+r'(?(1)X|Y)'    # Matches X if 1st capturing group matched something, otherwise matches Y;
+                #   r'(?>(1)|\d+) (?(1)mouse|mice)' matches '1 mouse' and '3 mice', but not
+                #   '1 mice' or '3 mouse'
+r'(?(name)X)'   # Matches X if named capturing group matched something, otherwise matches
+                # current position;
+                #   r'(?P<round>\()?(?P<square>\[)?a(?(square)\])(?(round)\))' behaves like
+                #   r'(\()?(\[)?a(?(2)\])(?(1)\))' above
+r'(?(name)X|Y)' # Matches X if named capturing group matched something, otherwise matches Y;
+                #   r'(?>(?P<n>1)|\d+) (?(n)mouse|mice)' behaves like
+                #   r'(?>(1)|\d+) (?(1)mouse|mice)' above
+
+ +
+# Other
+r'(?auLimsx)X'  # Flags to be applied to entire regular expression X (must be placed at
+                # start of expression); each letter corresponds to a flag to be enabled,
+                # e.g. (?i)X enables re.I for expression X;
+                #   r'(?ims).*?^b.c$' matches 'a\nB\nc' in 'a\nB\nc\nd';
+                #   r'(?x) a b c' matches 'abc' in 'abcd';
+                #   r'(?a)\w+' matches 'a2' in 'a2Ω';
+                # (?a), (?u), (?L) are not allowed to override re.A, re.U, re.L given as
+                # argument to e.g. re.match
+
+ +

Comprehensions

+ +For each iteration of the inner (last) 'for' loop, +the expression highlighted below is evaluated +to produce another item in the resulting list +- unless an 'if' condition is false, in which case no item is produced for that iteration. + +
+# List comprehension
+[x * y for x in [1, -1] for y in range(4) if y > x] # Returns list [2, 3, 0, -1, -2, -3]
+
+# Dictionary comprehension
+{x: y for x, y in ((0, 3), (1, 4), (2, 3))}         # Returns dict {0: 3, 1: 4, 2: 3}
+
+# Set comprehension
+{x**2 for x in range(4)}                            # Returns set {0, 1, 4, 9}
+
+# Tuple comprehension - has no dedicated syntax,
+# but a generator expression can be passed to tuple()
+tuple(chr(x) for x in range(65, 67))                # Returns tuple ('A', 'B')
+
+ +

Generator Expressions

+ +
+g = (x for x in 'hello' if x < 'm')     # Assigns a generator object prepared to produce
+                                        # the sequence 'h', 'e', 'l', 'l';
+                                        # generator objects are also iterators
+type(g)                                 # Returns class types.GeneratorType with name
+                                        # 'generator'
+next(g)                                 # Returns 'h', i.e. next (first) item
+next(g)                                 # Returns 'e', i.e. next item
+list(g)                                 # Returns ['l', 'l'], i.e. all remaining items;
+                                        # g is useless now and can't be restarted
+list(g)                                 # Returns []; no more items
+next(g)                                 # Raises StopIteration exception; no more items
+
+g = (x**2 for x in range(5))            # Assigns a new generator object
+for i in g:                             # Assigns each generated item to i in turn
+    if i == 9:                          # If item is 9, then...
+        try:
+            i = next(g)                 # ... skip to next item if any
+        except StopIteration:
+            i = 'end'                   # If no more, set i to 'end' (will not happen)
+    print(i)                            # Prints '0', '1', '4', '16', one by one
+
+ +See also generator functions. + +

Lambda Expressions

+ +
+f = lambda x, y: x + y  # Assigns a lambda expression (anonymous function) that takes 2
+                        # arguments and returns the sum of these; this is basically the
+                        # same as 'def f(x, y): return x + y', except a lambda doesn't
+                        # need to be bound to a name, and is limited to one expression
+type(f)                 # Returns class types.FunctionType with name 'function'
+f(3,5)                  # Calls lambda expression bound to name f; returns 8
+map(lambda x: x**2, range(4))   # Applies lambda to range and returns iterator for sequence
+                                # 0, 1, 4, 9
+g = lambda x: lambda y: x + y   # Binds g to a function which returns a function
+g(3)                            # Returns a function which adds 3 to stuff
+g(3)(4)                         # Returns 7
+
+ +

Functions

+ +

Function Definitions and Calls

+ +
+# Function definitions
+def f1(x, y=0):         # Arguments may have default values (calculated only once when
+                        # 'def' is executed, so beware if using mutable values, e.g. y=[])
+
+    # Here's a docstring for this function:
+    """This docstring is accessible via f1.__doc__
+    """
+
+    print(x, y)
+    if x > y:
+        return          # Exits function with return value None
+    if x < y:
+        return y, x     # Exits function with expression list as return value
+                        # Return value is None if function ends without 'return'
+
+def f2(x, *args, **keyargs): # Special * and ** syntax explained in function body:
+    print(x, end=' ')   # Prints first argument (and a space, no newline)
+    print(args, end=' ')# Prints a tuple of all remaining unnamed arguments
+    print(keyargs)      # Prints a dict of all remaining named arguments
+
+def f3(x, /, y, *, z):  # Special / and * syntax: parameters before / are positional only
+                        # (f3(5,...) is OK, but f3(x=5,...) is not); parameters between /
+                        # and * may be positional or named (f(5,6,...) and f(5,y=6,...) are
+                        # both OK); parameters after * are named only (f(5,6,z=7) is OK,
+                        # but f(5,6,7) is not)
+    print(x, y, z)      # Prints the 3 arguments
+
+def f4(x):
+    def g(y):           # Defines an inner function (function object) inside f4
+        return x + y    # Function g uses object referenced by f4's local x, so keeps that
+                        # object in existence after f4 returns
+    return g            # Function f4 returns the created function object (in this case a
+                        # 'closure' because it keeps data (x) in an outer scope (f4) alive
+                        # even though that scope has ended when the function is later
+                        # called)
+
+type(f1)                # Returns class types.FunctionType with name 'function' (functions
+                        # are also objects)
+
+# Function calls
+f1(3)                   # Calls f1 which prints '3 0' and returns None
+print(f1(3,5))          # Calls f1 which prints '3 5', then prints result '(5, 3)'
+f1(y=5, x=3)            # Passes named arguments to f1 which prints '3 5'
+a1 = [3, 5]
+f1(a1, [4])             # Passes a1 and [4] to f1 which prints '[3, 5] [4]' and returns
+                        # ([4], [3, 5]) because [3,5] is lexicographically smaller than [4]
+f1(*a1)                 # Passes each item of a1 as an argument to f1 which prints '3 5'
+                        # and returns (5, 3)
+d = {'y':5, 'x':3}      # Creates a dictionary
+f1(**d)                 # Passes values of d as named arguments to f1 which prints '3 5'
+f1(*[3], **{'y':5})     # Passes items of list and values of dictionary as arguments
+                        # to f1 which prints '3 5'
+f2(3)                   # Prints '3 () {}'
+f2(3, 4, 5, a=6)        # Prints "3 (4, 5) {'a': 6}"
+f3(5, 6, z=7)           # Prints "5 6 7"
+f3(5, z=7, y=6)         # Prints "5 6 7"
+f3(5, 6, 7)             # Raises TypeError (parameter z requires a named argument)
+f3(x=5, y=6, z=7)       # Raises TypeError (parameter x requires an unnamed argument)
+
+add10 = f4(10)          # Calls f4 which returns new function that adds 10 to its argument
+print(add10(9))         # Calls function add10 and prints return value '19'
+
+f2 = f1                 # (Re-)binds name f2 to same function object as f1
+f2(3)                   # Calls f2 (now same as f1) which prints '3 0' and returns None
+
+ +Notes: + + +

Generator Functions

+ +
+# Using 'yield'
+def f1(m):              # The yield statement in the body of this function causes it to
+                        # return a generator object, which produces a new item whenever
+                        # the yield statement is reached;
+                        # generator objects are also iterators
+    print('1st')        # Prints '1st' when first item is requested from generator (first
+                        # call to next())
+    end = 5 * m + 1
+    for x in range(m, end, m):
+        yield x                 # Returns x to caller of next() on generator object, and
+                                # stops execution until next() is called again, whereafter
+                                # execution continues after yield statement
+                        # When the loop ends and f1 returns, the generator object raises a
+                        # StopIteration exception
+
+g = f1(3)               # Assigns the generator object returned from function f1
+type(g)                 # Returns class types.GeneratorType with name 'generator'
+next(g)                 # Prints '1st' and returns 3, i.e. next (first) item of generator
+next(g)                 # Returns 6, i.e. next item
+list(g)                 # Returns [9, 12, 15], i.e. all remaining items;
+                        # g is useless now and can't be restarted (but f1 can be called
+                        # again to get a new generator object)
+list(g)                 # Returns []; no more items
+next(g)                 # Raises StopIteration exception; no more items
+
+ +
+# Using 'yield from'
+def f2(m):              # Identical to f1 above, but uses 'yield from' instead of 'yield'
+    print('1st')
+    end = 5 * m + 1
+    yield from range(m, end, m) # Returns items one by one from iterable to caller of
+                                # next(), stopping execution each time
+
+g = f2(3)               # Assigns the generator object returned from function f2
+next(g)                 # Prints '1st' and returns 3, i.e. next (first) item of generator
+list(g)                 # Returns [6, 9, 12, 15], i.e. all remaining items
+
+ +
+# Using 'send' and return value from 'yield',
+# and assigning a value to StopIteration exception
+def f3(m):              # Identical to f1 above, but allows values to be sent into the
+                        # generator at any time (and returned from yield) to modify its
+                        # behavior while iterating over it; also sets a StopIteration value
+    print('1st')
+    end = 5 * m + 1
+    x = m
+    while x < end:
+        y = yield x     # Returns x to caller of next() or send(), stops execution until
+                        # next() or send() is called again, then sets y to None (for
+                        # next()) or to argument of send(), and resumes execution here
+        x = x + m if y is None else y  # Updates next item or uses value provided by send()
+    return x            # Puts next x (which would have been generated if iteration hadn't
+                        # ended) into value attribute of StopIteration exception
+
+g = f3(3)               # Assigns the generator object returned from function f3
+g.send(4)               # Raises TypeError exception; can't send non-None value to
+                        # just-started generator (no yield to receive it)
+next(g)                 # Prints '1st' and returns 3, i.e. next (first) item of generator
+next(g)                 # Returns 6, i.e. next item
+g.send(4)               # Sends 4 into generator, which sets next item to 4 and returns 4
+next(g)                 # Returns 7, i.e. next item
+next(g)                 # Returns 10, i.e. next item
+next(g)                 # Returns 13, i.e. next item
+try:
+    next(g)                 # Raises StopIteration exception due to no more items
+except StopIteration as e:  # Catches StopIteration exception and assigns it to e
+    print(e.value)          # Prints '16' (StopIteration value returned at end of f3)
+    print(e.args)           # Prints '(16,)' (more general way to get arguments used to
+                            # create an exception; e.value is specific to StopIteration)
+try:
+    next(g)                 # Raises StopIteration exception again (still no more items)
+except StopIteration as e:
+    print(e.value)          # Prints 'None' (StopIteration value returned by f3 can only be
+                            # obtained once)
+
+ +
+# Using 'send' and return value from 'yield from';
+# see above for definition of f3()
+def f4(m):
+    print('first-', end='')
+    y = yield from f3(m)    # Returns items one by one from f3 generator to caller of
+                            # next() or send(); sets y to f3's StopIteration value when f3
+                            # is exhausted; argument to send() is passed to f3's send();
+    yield from (y, y * 2)   # Provide 2 more items (one by one) after f3 is exhausted
+
+g = f4(3)               # Assigns the generator object returned from function f4
+g.send(4)               # Raises TypeError exception; can't send non-None value to
+                        # just-started generator (no yield to receive it)
+next(g)                 # Prints 'first-1st' and returns 3 (first item from f4, which got
+                        # it from f3)
+next(g)                 # Returns 6 (next item from f4, which got it from f3)
+g.send(4)               # Sends 4 into f4, which forwards it to f3, which sets next item to
+                        # 4 and returns 4 to f4, which returns 4 here
+next(g)                 # Returns 7 (next item from f4, which got it from f3)
+list(g)                 # Returns [10, 13, 16, 32] (all remaining items from f4, which got
+                        # the first 2 items from f3, then produced 2 more items based on
+                        # f3's StopIteration value (16))
+
+ +
+# Using 'throw', and 'close'
+def f5():
+    try:
+        yield from (1,2,3)  # Returns items one by one from a tuple to the caller (f6), and
+                            # raises any exception passed in via throw()
+    except ValueError as e: # Catches a ValueError exception and
+        yield from e.args   # returns its arguments one by one to the caller (f6)
+
+def f6():
+    yield from f5()         # Returns items one by one from f5 to caller of next(), send(),
+                            # or throw() (after forwarding those calls to f5)
+
+g = f6(3)               # Assigns the generator object returned from function f6
+next(g)                 # Returns 1 (first item from f6, which got it from f5)
+next(g)                 # Returns 2 (next item from f6, which got it from f5)
+g.throw(ValueError, (7,8,9)) # Passes the exception ValueError(7,8,9) to f6 (via f6's
+                             # 'yield'), which passes it to f5 (via f5's first 'yield'),
+                             # which can't pass it any further so raises the exception at
+                             # that 'yield', catches the exception in the 'except', then
+                             # starts returning items one by one from the tuple of
+                             # arguments passed to ValueError, i.e. (7,8,9); thus f5
+                             # returns 7 to f6, which returns 7 here
+next(g)                 # Returns 8 (next item from f6, which got it from f5)
+g.close()               # Closes/exhausts the generator early (so skips the last item 9)
+next(g)                 # Raises StopIteration exception due to no more items (closed)
+g.close()               # Closing an already exhausted generator has no effect
+
+ +See also generator expressions. + +

Decorators

+ +
+from functools import wraps # Imports the 'wraps' decorator factory which copies attributes
+                            # (__name__, __doc__, __module__) from the wrapped function to
+                            # the wrapper function to make the wrapping more transparent
+
+def deco1(f):               # Defines a function deco1 which takes another function and
+                            # returns a modified version of it; any function that takes a
+                            # function or class as its sole argument can be used as a
+                            # decorator regardless of what it returns (see how to use deco1
+                            # below)
+    @wraps(f)               # Applies the 'wraps' decorator factory to f_wrapper1
+    def f_wrapper1(*args):                      # Defines the wrapper function which
+        return 2 * f(args[0] * 10, *args[1:])   # calls the wrapped/decorated function
+    return f_wrapper1       # Returns the wrapper function which will later be called
+                            # instead of the wrapped/decorated function
+
+def deco_factory(inscale, outscale):    # Defines a function deco_factory which uses its
+                            # arguments to produce a function that can be used as a
+                            # decorator; any function that does this can be used as a
+                            # decorator factory (see how to use deco_factory below)
+    def deco2(f):           # Defines a function deco2 similar to deco1 above, but this
+                            # one is customized based on the arguments to deco_factory
+        @wraps(f)
+        def f_wrapper2(*args):
+            return outscale * f(args[0] * inscale, *args[1:])
+        return f_wrapper2
+    return deco2            # Returns the deco2 function
+
+# The following line decorates the myadd1 function with the deco1 function;
+# same as doing myadd1 = deco1(myadd1) after defining myadd1,
+# so the name myadd1 will end up referring to f_wrapper1 which, when called,
+# will call the original myadd1 defined below
+@deco1
+def myadd1(x, y):
+    return x + y
+
+# The following line calls deco_factory and uses the returned function (deco2)
+# as a decorator for the myadd2 function;
+# same as doing myadd2 = deco_factory(100, 10)(myadd2) after defining myadd2,
+# so the name myadd2 will end up referring to f_wrapper2 which, when called,
+# will call the original myadd2 defined below
+@deco_factory(100, 10)
+def myadd2(x, y):
+    return x + y
+
+# Any number of decorators can be applied to the same function; they are applied
+# in reverse order;
+# the following is the same as doing myadd3 = deco_factory(100, 10)(deco1(myadd3))
+# after defining myadd3
+@deco_factory(100, 10)
+@deco1
+def myadd3(x, y):
+    return x + y
+
+myadd1(3, 4)                # Calls f_wrapper1 which calls the original myadd1 and returns
+                            # 68 (the result of 2 * (3 * 10 + 4))
+myadd2(3, 4)                # Calls f_wrapper2 which calls the original myadd2 and returns
+                            # 3040 (the result of 10 * (3 * 100 + 4))
+myadd3(3, 4)                # Calls f_wrapper2 which calls f_wrapper1 which calls the
+                            # original myadd3; returns 60080 (10 * (2 * (3 * 100 * 10 + 4)))
+
+ +Examples of standard functions often used as decorators are: +classmethod(), staticmethod(), +property(), functools.total_ordering(). +Most decorators take a function and return a function, but property() takes a function and returns +a property object, and functools.total_ordering() takes a class and returns a class. +Examples of standard functions often used as decorator factories are: functools.wraps(). + +

Built-in Functions

+ +
+__build_class__(f,'C')  # TBD
+__import__('sys')       # TBD
+abs(-3+4j)              # Returns 5.0
+aiter(o)                # Returns an asynchronous iterator for asynchronous iterable o;
+                        # (asynchronous version of iter())
+all([True,4,'0'])       # Returns True (Are all items True after conversion to bool? Yes);
+                        # all([]) returns True (not False!)
+anext(i,d)              # Returns an awaitable which, when awaited, returns next item from
+                        # asynchronous iterator i, or, if no more items, returns d or
+                        # raises StopIteration if no d; (asynchronous version of next())
+any([False,0,''])       # Returns False (Are any items True after conversion to bool? No);
+                        # any([]) returns False
+ascii(o)                # Same as repr(o) but uses escapes for non-ascii characters
+bin(12)                 # Returns '0b1100' (binary representation of 12)
+bool()                  # Returns a new bool
+breakpoint()            # Calls sys.breakpointhook() which by default pauses execution and
+                        # enters the Python debugger
+bytearray()             # Returns a new bytearray
+bytes()                 # Returns a new bytes object
+callable(f)             # Returns True if f appears to be callable (i.e. a function, class,
+                        # or other object with a __call__ method); note that some objects
+                        # may appear to be callable but will fail when called
+chr(65)                 # Returns 'A' (character with Unicode code 65)
+classmethod(f)          # Returns a class method for function f (usually used as decorator
+                        # @classmethod, see classes)
+compile('x=3\nprint(x)', '', 'exec') # Returns a code object which can be executed by exec()
+compile('2+5', '', 'eval')          # Returns a code object which can be evaluated by eval()
+complex()               # Returns a new complex
+delattr(o, 'x')         # Deletes object o's attribute x; same as del o.x
+dict()                  # Returns a new dict
+dir(o)                  # Returns a list of o's attributes, or a list of names in the
+                        # current local scope if no argument is given
+divmod(-5, 3)           # Returns (-2, 1); same as (-5 // 3, -5 % 3)
+enumerate(x)            # Returns a new enumerate; see iterator types
+eval('2+3')             # Returns 5; evaluates any Python expression (or compile() object)
+exec('if True:\n print("hi")') # Prints 'hi'; executes code in a string or compile() object
+exit()                  # Exits interactive interpreter; see script termination
+filter(f, 'hello')      # Returns iterator for sequence 'h','l','l','o' assuming f is:
+                        # def f(x): return x > 'g'
+filter(None, [3,0,''])  # Returns iterator for sequence 3 (all True items in list)
+float()                 # Returns a new float
+format(4, '<03')        # Returns '400' (same as '{:<03}'.format(4), see string operations)
+frozenset()             # Returns a new frozenset
+getattr(o, 'x', d)      # Returns the value of object o's attribute x (same as o.x), or, if
+                        # o.x doesn't exist, returns d or raises AttributeError if no d
+globals()               # Returns a dict representing the current global symbol table;
+                        # globals()['x'] = 3 is equivalent to global x; x = 3
+hasattr(o, 'x')         # Returns True if object o has attribute x
+hash(o)                 # Returns a hash value (integer) of immutable object o
+help(o)                 # Prints documentation on object o - or topic o if o is a string
+hex(254)                # Returns '0xfe' (hexadecimal respresentation of 254)
+id(o)                   # Returns the unique id (integer) of object o
+input('Input: ')        # Prints 'Input: ', reads a line from stdin, and returns the line
+                        # (excluding the final newline)
+int()                   # Returns a new int
+isinstance(o, c)        # Returns True if o is an instance of class c or of a subclass of c
+                        # - or of any item in c if c is a tuple of classes
+isinstance(o, c1 | c2)  # Same as isinstance(o, (c1,c2))
+issubclass(c1, c2)      # Returns True if c1 is a subclass of, or identical to, c2 - or any
+                        # item in c2 if c2 is a tuple of classes; c1 must be a class
+issubclass(c1, c2 | c3) # Same as issubclass(c1, (c2,c3))
+iter(o)                 # Returns an iterator for iterable o; see iterator types
+iter(f,x)               # Returns an iterator that calls f with no args until return value
+                        # equals x; see iterator types
+len([6,7,8])            # Returns 3 (number of items in list/tuple/set/...)
+list()                  # Returns a new list
+locals()                # Returns a dict representing the current local symbol table (this
+                        # dict should not be modified)
+map(f, [5,2,6], (3,4))  # Returns iterator for sequence '53','24' assuming f is:
+                        # def f(x,y): return str(x)+str(y);
+                        # the number of sequences must match the number of arguments to f
+max(3,5,2)              # Returns 5
+max([3,5,2])            # Returns 5
+max([], default=4)      # Returns 4
+max([3,5,2], key=lambda x:-x)       # Returns 2
+max([], key=lambda x:-x, default=4) # Returns 4
+memoryview(o)           # Returns a new memoryview
+min(3,5,2)              # Returns 2
+min([3,5,2])            # Returns 2
+min([], default=4)      # Returns 4
+min([3,5,2], key=lambda x:-x)       # Returns 5
+min([], key=lambda x:-x, default=4) # Returns 4
+next(i,d)               # Returns next item from iterator i, or, if no more items, returns
+                        # d or raises StopIteration if no d; see iterator types
+object()                # Returns a new object
+oct(8)                  # Returns '0o10' (octal representation of 8)
+open('file', 'w')       # Opens 'file' for writing and returns a file object; see files
+ord('A')                # Returns 65 (Unicode code of character 'A')
+pow(3.0, 2.0)           # Returns 9.0; same as 3.0**2.0;
+pow(3, 2, 4)            # Returns 1; same as 3**2 % 4 but more efficient; all args must be
+                        # integers
+print()                 # Prints its arguments; see standard in/out/error
+quit()                  # Exits interactive interpreter; see script termination
+property()              # Returns a new property
+range(10)               # Returns a new range
+repr(o)                 # Returns a formal string representation of o, preferably one that
+                        # can be executed by eval() to recreate o
+reversed([1,2,3])       # Returns an iterator for the sequence 3,2,1
+reversed('hello')       # Returns an iterator for the sequence 'o','l','l','e','h'
+round(25.16)            # Returns 25 (25.16 rounded to 0 digits after the point)
+round(25.16, 0)         # Returns 25.0 (25.16 rounded to 0 digits after the point)
+round(25.16, 1)         # Returns 25.2 (25.16 rounded to 1 digit after the point)
+round(25.16, -1)        # Returns 30.0 (25.16 rounded to 1 digit before the point)
+set()                   # Returns a new set
+setattr(o, 'x', 3)      # Sets object o's attribute x to 3; same as o.x = 3
+slice(10)               # Returns a new slice
+sorted([10,-1,9])       # Returns [-1, 9, 10] (takes the same additional args as o.sort())
+staticmethod(f)         # Returns a static method for function f (usually used as decorator
+                        # @staticmethod, see classes)
+str()                   # Returns a new str
+sum([1,2,3,4])          # Returns 10 (the sum of all items)
+sum([2,3,4], 1)         # Returns 10 (the sum of all items and the 2nd argument)
+super(C, self).m()      # Calls method m of class C's parent/sibling class (the next class
+                        # after C in the method resolution order of self's class) and
+                        # passes object self to that method; see class inheritance;
+                        # arguments C and self are optional inside class definitions
+tuple()                 # Returns a new tuple
+type(10)                # Returns int (i.e. a type object that is the type of the argument)
+type('MyT', (), {})     # Returns a new type; see class creation and instantiation
+vars(o)                 # Returns o.__dict__, or same as locals() if no o
+zip([5,2,6], (3,4))     # Returns an iterator for sequence (5, 3), (2, 4);
+                        # any number of collections are supported;
+                        # zip can also unzip, because if x is a list of same-length tuples,
+                        # and y = list(zip(*x)), then x == list(zip(*y))
+zip([5,2,6], (3,4), strict=True)  # Returns same iterator as above, except this iterator
+                        # raises ValueError instead of StopIteration when done, because
+                        # arguments don't have same length
+
+ +

Classes

+ +

About Classes/Types and Objects

+ +

Types and classes are two terms for the same thing: objects representing categories of other objects. +The UML diagram below illustrates the relationships between various types of objects +("int:type" means object int is an instance/object of class type, and arrows point +from subclasses to the superclasses/bases they inherit from).

+ +
+ + + + + + + + + Objects + + + + Classes + + + + Metaclasses + + + + Other Objects + + + + + + + + + + object:type + + + + type:type + + + + Mymetaclass:type + + + + int:type + + + + Myclass:type + + + + Mysubclass:type + + + + Myclass2:Mymetaclass + + + + 42:int + + + + x:Myclass + + + + y:Mysubclass + + + + z:Myclass2 + + + + o:object + + +
+ +

The following code creates the objects shown in the diagram above and checks their relationships.

+ +
+# Create the non-standard classes shown in the diagram above
+class Myclass: pass
+class Mysubclass(Myclass): pass
+class Mymetaclass(type): pass
+class Myclass2(metaclass=Mymetaclass): pass
+
+# Create the non-standard "other objects" shown in the diagram above
+x = Myclass()
+y = Mysubclass()
+z = Myclass2()
+o = object()
+
+# Create the object groups shown in the diagram above
+classes = {object, type, Mymetaclass, Myclass, Mysubclass, int, Myclass2}
+metaclasses = {type, Mymetaclass}
+other_objs = {42, x, y, z, o}
+objects = classes | other_objs
+
+# All objects (even 'object' itself) are instances of 'object' (possibly instances of a
+# subclass of 'object')
+all(isinstance(obj, object) for obj in objects)             # Returns True
+# All objects have a __class__ attribute referencing the class of which the object is a
+# direct instance; this is also the class returned when the object is passed to the type()
+# function
+all(obj.__class__ is type(obj) for obj in objects)          # Returns True
+
+# All metaclasses are subclasses of 'type', except in the hypothetical and probably not
+# very useful case where they are NOT subclasses of 'type' but nevertheless behave like
+# 'type' (no known examples of this); note that Python considers any class to be a subclass
+# of itself
+all(issubclass(cls, type) for cls in metaclasses)           # Returns True
+
+# All classes (even 'type' itself) are instances of 'type' (possibly instances of a
+# subclass of 'type' in the case of metaclass instances), except if they are instances of
+# one of the unlikely metaclasses mentioned above
+all(isinstance(cls, type) for cls in classes)               # Returns True
+all(type(cls) is type for cls in (classes - {Myclass2}))    # Returns True
+# Myclass2 is an example of an instance of a subclass of 'type'
+type(Myclass2) is Mymetaclass                               # Returns True
+issubclass(Mymetaclass, type)                               # Returns True
+
+# Other objects than classes are not instances of 'type' (not even instances of a subclass
+# of 'type'), they are instances of some other class
+any(isinstance(obj, type) for obj in other_objs)            # Returns False
+any(issubclass(type(obj), type) for obj in other_objs)      # Returns False
+expected_class_for_obj = {42:int, x:Myclass, y:Mysubclass, z:Myclass2, o:object}
+all(isinstance(obj, expected_class_for_obj[obj])
+    for obj in other_objs)                                  # Returns True
+all(type(obj) is expected_class_for_obj[obj]
+    for obj in other_objs)                                  # Returns True
+
+# All classes are subclasses of 'object' (possibly subclasses of a subclass of 'object';
+# note that Python considers any class to be a subclass of itself)
+all(issubclass(cls, object) for cls in classes)             # Returns True
+# Mymetaclass and Mysubclass are examples of subclasses of subclasses of 'object'
+issubclass(Mymetaclass, type)                               # Returns True
+issubclass(type, object)                                    # Returns True
+issubclass(Mysubclass, Myclass)                             # Returns True
+issubclass(Myclass, object)                                 # Returns True
+# All classes have a (possibly empty) __bases__ tuple containing their superclasses
+all(hasattr(cls, '__bases__') for cls in classes)           # Returns True
+all(cls.__bases__ == (object,)
+    for cls in classes - {object, Mymetaclass, Mysubclass}) # Returns True
+object.__bases__                                            # Returns ()
+Mymetaclass.__bases__                                       # Returns (type,)
+Mysubclass.__bases__                                        # Returns (Myclass,)
+
+# Other objects than classes obviously cannot be subclasses (issubclass will raise
+# TypeError) and do not have the __bases__ tuple
+any(hasattr(obj, '__bases__') for obj in other_objs)        # Returns False
+
+ +

Class Creation and Instantiation

+ +
+# Class definitions
+class Myclass:          # Defines a class (which inherits only from 'object')
+
+    # Here's a docstring for this class:
+    """This docstring is accessible via Myclass.__doc__
+    or e.g. o1.__doc__ where o1 is an instance of Myclass.
+    """
+
+    n = 3               # Defines a class variable, shared by all instances of this class
+
+    @staticmethod       # Decorator that defines a static method to be invoked on the class
+    def setn(n):        # itself (or optionally on instances of the class)
+        Myclass.n = n   # Updates the class variable
+
+    @classmethod        # Decorator that defines a class method to be invoked on the class
+    def setn2(cls, n):  # itself (or optionally on instances of the class); first arg is
+                        # the class, conventionally named 'cls'
+        cls.n = n       # Updates the class variable
+
+    def __init__(self, x):  # Defines the instance constructor; first arg is the instance,
+                            # conventionally named 'self' (like 'this' in C++)
+        self.x = x          # Creates an instance variable belonging to the given instance
+
+    def add(self, y):       # Defines an instance method to be invoked on a given instance
+        self.x += (y *      # Updates the previously created instance variable
+            self.n)         # Class variables may be read (not written!) via 'self'
+                            # (if written, a new instance variable is created hiding the
+                            # class variable!)
+
+    def __str__(self):      # Defines informal nicely printable string representation of
+                            # an instance of this class
+        return str(self.x)  # Returns instance variable converted to string
+
+    def __repr__(self):     # Defines formal string representation of an instance of this
+                            # class, preferably executable by eval() to recreate instance
+        return 'Myclass(%d)' % self.x
+
+    def __getitem__(self, item):        # Defines special method for getting indexed item
+        print('get', item)
+        t = item if isinstance(item, tuple) else (item,) # Make item a tuple if not already
+        for i in t:                                      # Step through tuple
+            if isinstance(i, slice):                     # Handle slice by converting it to
+                print(range(*i.indices(self.n)), end=' ')# range (self.n sets upper limit)
+            elif i == Ellipsis:                          # Handle Ellipsis object by just
+                print('...', end=' ')                    # printing 3 dots
+            else:
+                print(i, end=' ')
+        print()
+        return self.x
+
+    def __setitem__(self, key, val):    # Defines special method for setting indexed item
+        print('set', key, val)
+
+    def __add__(self, other):           # Defines special method overriding '+' operator
+        return self.x + other
+
+    def __radd__(self, other):          # Defines special method overriding '+' operator if
+                                        # this object is 2nd arg and other.__add__()
+                                        # returned NotImplemented
+        return self.x + other + self.n
+
+type(Myclass)               # Returns class type; same as Myclass.__class__
+isinstance(Myclass, type)   # Returns True
+issubclass(Myclass, object) # Returns True
+Myclass.__name__            # Returns 'Myclass'
+Myclass.__bases__           # Returns (object,) (tuple of base classes)
+Myclass.mro()               # Returns [Myclass, object]
+                            # (method resolution order: order in which classes are searched
+                            # for a method definition)
+Myclass.n                   # Returns 3
+type(Myclass.setn)          # Returns class types.FunctionType with name 'function'
+type(Myclass.setn2)         # Returns class types.MethodType with name 'method'
+type(Myclass.add)           # Returns class types.FunctionType with name 'function'
+                            # (unbound method)
+
+# Dynamically defined classes
+type('Mydynclass', (Myclass,), {'n': 4})    # Creates and returns a class with __name__ ==
+                        # 'Mydynclass' but not bound to any name in current namespace;
+                        # this class inherits from Myclass and sets class variable n to 4;
+                        # the class will be lost unless a reference to it is saved, e.g.
+                        # Someclass = type('Mydynclass', ...)
+
+# Instantiation
+o1 = Myclass(10)        # Creates an object as an instance of class 'Myclass' and runs
+                        # the __init__ constructor with parameter x = 10
+type(o1)                # Returns class Myclass; same as o1.__class__
+type(o1.add)            # Returns class types.MethodType with name 'method'; more about
+                        # method objects below
+o2 = Myclass(20)        # Creates a second instance of the same class using x = 20
+o1.x                    # Returns 10
+o2.x                    # Returns 20
+o1.n                    # Returns 3 (the value of class variable n)
+str(o1)                 # Returns '10' (return value from o1.__str__())
+repr(o1)                # Returns 'Myclass(10)' (return value from o1.__repr__())
+dir(o1)                 # Returns list of all o1's attributes: [..., '__doc__', ...,
+                        # '__init__', ..., 'add', 'n', 'setn', 'setn2', 'x']
+
+o1[4]                   # Calls o1.__getitem__(4)
+o1[::-1] = 2            # Calls o1.__setitem__(slice(None,None,-1),2); see slice
+o1[2,:3,...]            # Calls o1.__getitem__((2,slice(None,3,None),Ellipsis))
+                        # (note: this extended syntax is not supported by built-in types
+                        # such as list and tuple)
+
+o1 + 4                  # Calls o1.__add__(4) which returns 14
+5 + o1                  # Calls o1.__radd__(5) (when (5).__add__(o1) returns NotImplemented)
+                        # which returns 18
+o1.add(2)               # Passes 2 to the 'add' method of o1 which updates o1's x;
+                        # equivalent to Myclass.add(o1, 2)
+o1.x                    # Returns 16 (2 * 3 was added to the previous value 10)
+o2.x                    # Returns 20 (no change)
+
+Myclass.setn(5)         # Changes the class variable n value to 5
+Myclass.setn2(5)        # Same effect as above (Myclass is automatically passed as 1st arg
+                        # to setn2, and 5 becomes 2nd arg)
+Myclass.n = 5           # Same effect as above
+o1.setn(5)              # Same effect as above (o1 is only used to access Myclass)
+o1.setn2(5)             # Same effect as above (o1 is only used to access Myclass)
+                        # (don't do o1.n = 5, it hides the class variable from o1)
+o1.n                    # Returns 5
+o2.n                    # Returns 5 (same class var n is accessed from any instance)
+
+o2.add(-1)
+o1.x                    # Returns 16
+o2.x                    # Returns 15 (-1 * 5 was added to 20)
+
+o1.s = 'hi'             # Creates a new instance variable on o1 only
+Myclass.k = 100         # Creates a new class variable (visible in all existing and new
+                        # instances)
+
+# Bound method objects
+o1a = o1.add            # Assigns a bound method object referencing o1's 'add' method (a
+                        # new object is created every time a user defined method is
+                        # accessed like this, so (o1.add is o1.add) evaluates to False!)
+type(o1a)               # Returns class types.MethodType with name 'method'
+o1a.__self__            # Returns o1
+o1a.__func__            # Returns Myclass.add
+o1a(4)                  # Passes 4 to o1's 'add' method, which updates o1's x
+o1.x                    # Returns 36 (4 * 5 was added to 16)
+
+# Built-in function/method objects
+ss = 'abba'.strip       # Assigns a bound method object referencing the built-in strip
+                        # method of string 'abba'
+type(ss)                # Returns class types.BuiltinFunctionType with name
+                        # 'builtin_function_or_method'
+ss.__self__             # Returns 'abba'
+ss.__func__             # ILLEGAL! Raises AttributeError exception because built-in methods
+                        # don't have the __func__ attribute
+ss('a')                 # Returns 'bb' (same as 'abba'.strip('a'))
+type(len)               # Returns class types.BuiltinFunctionType with name
+                        # 'builtin_function_or_method'; built-in functions are actually
+                        # bound methods of the 'builtins' module object (which is hidden
+                        # unless explicitly imported)
+len.__self__            # Returns builtins module object
+
+ +

Class Inheritance

+ +
+class A(list):                          # Defines a class A which inherits from list (which
+                                        # inherits from object)
+    def __str__(self):                  # Overrides list's __str__ method in order to...
+        return ('A:' +                  # ... prepend 'A:' to...
+            super().__str__())          # ... whatever is returned from __str__() of the
+                                        # next classes in the method resolution order (i.e.
+                                        # the previous classes in the inheritance order);
+                                        # the next class is list when self is an instance
+                                        # of A, but B when self is an instance of C!
+
+class B(list):                          # Defines a class B just like A, except...
+    def __str__(self):
+        return ('B:' +                  # ... prepend 'B:' to...
+            super().__str__())          # ... whatever is returned from __str__() of the
+                                        # next classes in the method resolution order; the
+                                        # next class is list when self is an instance of
+                                        # either B or C
+
+class C(A, B):                          # Defines a class C which inherits primarily from A
+                                        # and secondarily from B
+    def __str__(self):                  # Overrides the __str__ method in order to...
+        return ('C:' +                  # ... prepend 'C:' to...
+            super().__str__())          # ... whatever is returned from __str__() of the
+                                        # next classes in the method resolution order; the
+                                        # next class is A when self is an instance of C
+
+C.__bases__ # Returns (A, B)
+
+# Method resolution order (MRO) for classes A, B, and C (see notes)
+A.mro()     # Returns [A, list, object]; this means that A().__str__() will first look for
+            # an __str__ method in class A, then in class list, then in class object, until
+            # a class is found which has the method
+B.mro()     # Returns [B, list, object]
+C.mro()     # Returns [C, A, B, list, object]
+
+a = A([0])  # Assigns an instance of class A initialized by calling a.__init__([0]) which
+            # resolves to list.__init__(a,[0]) (list is 1st class with __init__ in A.mro())
+            # which sets the initial value to [0]
+b = B([1])  # Assigns an instance of class B initialized to [1] by list.__init__(b,[1])
+c = C([2])  # Assigns an instance of class C initialized to [2] by list.__init__(c,[2])
+
+print(a)    # Prints 'A:[0]', because print calls a.__str__()
+            # which resolves to A.__str__(a) (A is a's class and has __str__)
+            # which calls super(A, a).__str__()
+            # which resolves to list.__str__(a) (list follows A in A.mro() and has __str__)
+            # which returns '[0]' to A.__str__
+            # which returns 'A:[0]' to print
+print(b)    # Prints 'B:[1]', because print calls b.__str__()
+            # which resolves to B.__str__(b) (B is b's class and has __str__)
+            # which calls super(B, b).__str__()
+            # which resolves to list.__str__(b) (list follows B in B.mro() and has __str__)
+            # which returns '[1]' to B.__str__
+            # which returns 'B:[1]' to print
+print(c)    # Prints 'C:A:B:[2]', because print calls c.__str__()
+            # which resolves to C.__str__(c) (C is c's class and has __str__)
+            # which calls super(C, c).__str__()
+            # which resolves to A.__str__(c) (A follows C in C.mro() and has __str__)
+            # which calls super(A, c).__str__()
+            # which resolves to B.__str__(c) (B follows A in C.mro() and has __str__)
+            # which calls super(B, c).__str__()
+            # which resolves to list.__str__(c) (list follows B in C.mro() and has __str__)
+            # which returns '[2]' to B.__str__
+            # which returns 'B:[2]' to A.__str__
+            # which returns 'A:B:[2]' to C.__str__
+            # which returns 'C:A:B:[2]' to print
+
+ +Notes on method resolution order (MRO): + + +

Descriptors

+ +

A descriptor is an object attribute which calls special methods +to override the default behavior when getting, setting, and/or deleting the attribute. +In order to do so, a descriptor must be an instance of a class which defines the special methods +__get__, __set__, and/or __delete__.

+ +

A descriptor that defines both the __get__ and __set__ methods is a data descriptor and looks like +an instance/class variable. It overrides any instance/class variable with the same name. +A property attribute is an example of a data descriptor.

+ +

A descriptor that defines only the __get__ method is a non-data descriptor and looks like a normal method. +It is overridden by any normal method with the same name.

+ +
+class MyDescriptor:                             # Defines a descriptor class
+    def __set_name__(self, ownerclass, name):   # Special method called when descriptor
+                                                # instance is assigned to name in class
+        self.hidden_var_name = '_' + name       # Stores name '_x' in descriptor instance
+                                                # (assuming descriptor was assigned to name
+                                                # x in ownerclass definition)
+
+    def __get__(self, instance, ownerclass):    # Special method called when descriptor is
+                                                # accessed as instance.x or ownerclass.x
+        if instance is None:                    # If accessed as ownerclass.x, then
+            return ownerclass.__name__          # return name of ownerclass
+        return getattr(instance,                # Otherwise return instance._x
+                       self.hidden_var_name)
+
+    def __set__(self, instance, value):         # Special method called when descriptor is
+                                                # set to value, i.e. instance.x = value
+        setattr(instance,                       # Sets instance._x = float(value)
+                self.hidden_var_name,
+                float(value))
+
+    def __delete__(self, instance):             # Special method called when descriptor is
+                                                # deleted, i.e. del instance.x
+        delattr(instance,                       # Deletes instance._x (the descriptor
+                self.hidden_var_name)           # instance.x itself remains intact)
+
+class MyOwnerClass:         # Defines class MyOwnerClass; will contain our descriptor
+    def __init__(self, v):  # Defines the instance constructor
+        self.x = v          # Calls MyDescriptor.__set__(x, self, v) which sets self._x =
+                            # float(v)
+    x = MyDescriptor()      # Defines descriptor x as instance of class MyDescriptor
+
+MyOwnerClass.x,             # Returns 'MyOwnerClass' (calls MyDescriptor.__get__(x, None,
+                            # MyOwnerClass))
+o = MyOwnerClass(1)         # Assigns a new instance of MyOwnerClass with o._x set to 1.0
+o._x,                       # Returns 1.0
+o.x,                        # Returns 1.0 (calls MyDescriptor.__get__(x, o, MyOwnerClass))
+o.x = 2,                    # Sets o._x to 2.0 (calls MyDescriptor.__set__(x, o, 2))
+o.x,                        # Returns 2.0 (calls MyDescriptor.__get__(x, o, MyOwnerClass))
+del o.x                     # Deletes o._x (calls MyDescriptor.__delete__(x, o))
+o.x,                        # Raises AttributeError exception because o._x doesn't exist
+o.x = 3,                    # Sets o._x to 3.0 (calls MyDescriptor.__set__(x, o, 3))
+o.x,                        # Returns 3.0 (calls MyDescriptor.__get__(x, o, MyOwnerClass))
+
+ +

Property Attributes

+ +The built-in function property(), which creates a property object implementing the +descriptor protocol, can be used as a +decorator to define functions to be called +whenever a certain class attribute is read, written, or deleted. + +
+class C:
+    def __init__(self, v):  # Defines the instance constructor
+        self._x = float(v)  # Initializes an instance variable which is not supposed to be
+                            # accessed directly from outside class C
+
+    @property               # Creates a property attribute x whose __get__() method is
+    def x(self):            # this function (function name becomes property name)
+        return self._x
+
+    @x.setter               # Sets the __set__() method of property x to
+    def x(self, v):         # this function (use same name for function and property)
+        self._x = float(v)
+
+    @x.deleter              # Sets the __delete__() method of property x to
+    def x(self):            # this function (use same name for function and property)
+        del self._x
+
+type(C.x)                   # Returns class property
+isinstance(C.x, property)   # Returns True
+
+c = C(1)                    # Assigns a new instance of class C with c._x set to 1.0
+c._x                        # Returns 1.0 (but we're not supposed to access _x directly)
+c.x                         # Returns 1.0 (calls our getter C.x.__get__(c))
+c.x = 2                     # Sets c._x to 2.0 (calls our setter C.x.__set__(c, 2))
+c.x                         # Returns 2.0 (calls our getter C.x.__get__(c))
+del c.x                     # Deletes c._x (calls our deleter C.x.__delete__(c))
+c.x                         # Raises AttributeError exception because c._x doesn't exist
+c.x = 3                     # Sets c._x to 3.0 (calls our setter C.x.__set__(c, 3))
+c.x                         # Returns 3.0 (calls our getter C.x.__get__(c))
+
+ +

Special Methods

+ +

Certain special methods - if defined in the class hierarchy of an object (not on the object itself) - are automatically +called when certain built-in Python functions, statements, or syntax are applied to that object, and such calls are +never redirected to the __getattr__ or __getattribute__ methods even if those exist. +Built-in Python classes themselves have many of these special methods.

+ +

In the list below, all methods are instance methods unless specifically stated to be static methods or class methods +(the @staticmethod and @classmethod decorators are unnecessary for special +methods defined within the body of a class definition - the methods are automatically converted to the correct type), +and the methods are assumed to have been defined in a class C of which object o is in instance, like this:

+ +
+class C:
+    def __new__(cls, *args, **kwargs): pass
+    def __init__(self, *args, **kwargs): pass
+    # ...etc...
+
+o = C()
+
+ +List of special methods along with examples of code that causes them to be called: + +
+# Object creation/deletion
+o = C.__new__(C)            # Static method; called by o = C() to create object of class C
+o.__init__()                # Called by o = C() to initialize object created by __new__()
+o.__del__()                 # Called by del o; gc.collect(), i.e. when o is garbage
+                            # collected after last reference to it has been removed
+
+# Class creation
+C.__init_subclass__(C2)     # Class method; called by class C2(C): pass, i.e. when a
+                            # subclass of class C is defined
+C2 = C.__class_getitem__(t) # Class method; called by C2 = C[t] to create specialized class
+                            # C2 from generic class C using type t
+
+# Object attribute access
+y = o.__getattr__('x')      # Called by y = o.x if o.x and o.__getattribute__ don't exist,
+                            # or if o.__getattribute__('x') raises AttributeError
+y = o.__getattribute__('x') # Called by y = o.x
+o.__setattr__('x', 5)       # Called by o.x = 5
+o.__delattr__('x')          # Called by del o.x
+y = o.__dir__()             # Called by y = dir(o)
+
+# Container object item access
+y = o.__len__()             # Called by y = len(o)
+y = o.__getitem__(3)        # Called by y = o[3]
+o.__setitem__(3, 9)         # Called by o[3] = 9
+o.__delitem__(3)            # Called by del o[3]
+y = o.__contains__(3)       # Called by y = 3 in o
+y = o.__iter__()            # Called by y = iter(o)
+y = o.__reversed__()        # Called by y = reversed(o)
+y = o.__missing__(3)        # Called by y = o[3] (from within dict.__getitem__(3)) if o's
+                            # class inherits from dict and o[3] doesn't exist
+
+# Iterator object item access
+y = o.__next__()            # Called by y = next(o)
+
+# Object conversion
+y = o.__repr__()            # Called by y = repr(o)
+y = o.__str__()             # Called by y = str(o)
+y = o.__format__('^6')      # Called by y = format(o, '^6') or y = '{:^6}'.format(o)
+y = o.__bytes__()           # Called by y = bytes(o)
+y = o.__bool__()            # Called by y = bool(o)
+y = o.__hash__()            # Called by y = hash(o)
+y = o.__int__()             # Called by y = int(o)
+y = o.__float__()           # Called by y = float(o)
+y = o.__complex__()         # Called by y = complex(o)
+
+# Object calling
+y = o.__call__()            # Called by y = o()
+
+# Context management
+y = o.__enter__()           # Called when entering with o as y: pass
+o.__exit__(None, None, None)# Called when exiting with o: pass (if no exceptions)
+y = o.__exit__(excp_type, excp_val, traceback)  # Called when exiting with o: raise excp;
+                            # if bool(y) == True, the exception is suppressed
+
+# Object comparison
+y = o.__lt__(o2)            # Called by y = o < o2, or by y = o2 > o if o's type is
+                            # subclass of o2's type or if o2.__gt__(o) returns
+                            # NotImplemented
+y = o.__le__(o2)            # Called by y = o <= o2, or by y = o2 >= o if o's type is
+                            # subclass of o2's type or if o2.__ge__(o) returns
+                            # NotImplemented
+y = o.__eq__(o2)            # Called by y = o == o2, or by y = o2 == o if o's type is
+                            # subclass of o2's type or if o2.__eq__(o) returns
+                            # NotImplemented
+y = o.__ne__(o2)            # Called by y = o != o2, or by y = o2 != o if o's type is
+                            # subclass of o2's type or if o2.__ne__(o) returns
+                            # NotImplemented
+y = o.__gt__(o2)            # Called by y = o > o2, or by y = o2 < o if o's type is
+                            # subclass of o2's type or if o2.__lt__(o) returns
+                            # NotImplemented
+y = o.__ge__(o2)            # Called by y = o >= o2, or by y = o2 <= o if o's type is
+                            # subclass of o2's type or if o2.__le__(o) returns
+                            # NotImplemented
+
+# Unary arithmetic operations
+y = o.__neg__()             # Called by y = -o
+y = o.__pos__()             # Called by y = +o
+y = o.__abs__()             # Called by y = abs(o)
+y = o.__invert__()          # Called by y = ~o
+y = o.__round__()           # Called by y = round(o)
+y = o.__round__(2)          # Called by y = round(o, 2)
+y = o.__trunc__()           # Called by y = math.trunc(o)
+y = o.__floor__()           # Called by y = math.floor(o)
+y = o.__ceil__()            # Called by y = math.ceil(o)
+y = o.__index__()           # Called by y = operator.index(o) or 'hello'[:o] (returns
+                            # 'hello'[:y]) or hex(o) (returns hex(y)) or wherever an exact
+                            # integer is needed
+
+# Binary arithmetic operations
+y = o.__add__(o2)           # Called by y = o + o2 (but see __radd__)
+y = o.__sub__(o2)           # Called by y = o - o2 (but see __rsub__)
+y = o.__mul__(o2)           # Called by y = o * o2 (but see __rmul__)
+y = o.__matmul__(o2)        # Called by y = o @ o2 (but see __rmatmul__)
+y = o.__truediv__(o2)       # Called by y = o / o2 (but see __rtruediv__)
+y = o.__floordiv__(o2)      # Called by y = o // o2 (but see __rfloordiv__)
+y = o.__mod__(o2)           # Called by y = o % o2 (but see __rmod__)
+y = o.__divmod__(o2)        # Called by y = divmod(o, o2) (but see __rdivmod__)
+y = o.__pow__(o2)           # Called by y = o ** o2 or y = pow(o, o2) (but see __rpow__)
+y = o.__pow__(o2, 5)        # Called by y = pow(o, o2, 5) (no __rpow__ variant)
+y = o.__lshift__(o2)        # Called by y = o << o2 (but see __rlshift__)
+y = o.__rshift__(o2)        # Called by y = o >> o2 (but see __rrshift__)
+y = o.__and__(o2)           # Called by y = o & o2 (but see __rand__)
+y = o.__or__(o2)            # Called by y = o | o2 (but see __ror__)
+y = o.__xor__(o2)           # Called by y = o ^ o2 (but see __rxor__)
+
+# Reverse binary arithmetic operations
+y = o.__radd__(o2)          # Called by y = o2 + o if o's type is subclass of o2's
+                            # type or if o2.__add__(o) returns NotImplemented
+y = o.__rsub__(o2)          # Called by y = o2 - o if o's type is subclass of o2's
+                            # type or if o2.__sub__(o) returns NotImplemented
+y = o.__rmul__(o2)          # Called by y = o2 * o if o's type is subclass of o2's
+                            # type or if o2.__mul__(o) returns NotImplemented
+y = o.__rmatmul__(o2)       # Called by y = o2 @ o if o's type is subclass of o2's
+                            # type or if o2.__matmul__(o) returns NotImplemented
+y = o.__rtruediv__(o2)      # Called by y = o2 / o if o's type is subclass of o2's
+                            # type or if o2.__truediv__(o) returns NotImplemented
+y = o.__rfloordiv__(o2)     # Called by y = o2 // o if o's type is subclass of o2's
+                            # type or if o2.__floordiv__(o) returns NotImplemented
+y = o.__rmod__(o2)          # Called by y = o2 % o if o's type is subclass of o2's
+                            # type or if o2.__mod__(o) returns NotImplemented
+y = o.__rdivmod__(o2)       # Called by y = divmod(o2, o) if o's type is subclass of o2's
+                            # type or if o2.__divmod__(o) returns NotImplemented
+y = o.__rpow__(o2)          # Called by y = o2 ** o or y = pow(o2, o) if o's type is
+                            # subclass of o2's type or if o2.__pow__(o) returns
+                            # NotImplemented
+                            # pow(o2, o, 5) always calls o2.__pow__(o, 5), never __rpow__
+y = o.__rlshift__(o2)       # Called by y = o2 << o if o's type is subclass of o2's
+                            # type or if o2.__lshift__(o) returns NotImplemented
+y = o.__rrshift__(o2)       # Called by y = o2 >> o if o's type is subclass of o2's
+                            # type or if o2.__rshift__(o) returns NotImplemented
+y = o.__rand__(o2)          # Called by y = o2 & o if o's type is subclass of o2's
+                            # type or if o2.__and__(o) returns NotImplemented
+y = o.__ror__(o2)           # Called by y = o2 | o if o's type is subclass of o2's
+                            # type or if o2.__or__(o) returns NotImplemented
+y = o.__rxor__(o2)          # Called by y = o2 ^ o if o's type is subclass of o2's
+                            # type or if o2.__xor__(o) returns NotImplemented
+
+# Augmented arithmetic assignment
+o = o.__iadd__(o2)          # Called by o += o2 (falls back to o = o + o2 if no __iadd__)
+o = o.__isub__(o2)          # Called by o -= o2
+o = o.__imul__(o2)          # Called by o *= o2
+o = o.__imatmul__(o2)       # Called by o @= o2
+o = o.__itruediv__(o2)      # Called by o /= o2
+o = o.__ifloordiv__(o2)     # Called by o //= o2
+o = o.__imod__(o2)          # Called by o %= o2
+o = o.__ipow__(o2)          # Called by o **= o2
+o = o.__ilshift__(o2)       # Called by o <<= o2
+o = o.__irshift__(o2)       # Called by o >>= o2
+o = o.__iand__(o2)          # Called by o &= o2
+o = o.__ior__(o2)           # Called by o |= o2
+o = o.__ixor__(o2)          # Called by o ^= o2
+
+# Coroutine methods
+y = o.__await__()           # Called by z = await o (inside a coroutine), where y is a
+                            # coroutine wrapper (handled by await) and z is the coroutine's
+                            # return value when it completes
+y = o.__aiter__()           # Called by y = aiter(o) or async for z in o: pass (inside a
+                            # coroutine) to get an asynchronous iterator y for the
+                            # asynchronous iterable o; asynchronous variant of __iter__
+y = o.__anext__()           # Called by y = anext(o) or repeatedly by
+                            # async for z in o: pass (inside a coroutine) to get an
+                            # awaitable y which - when it completes - produces the next
+                            # item in o (to be assigned to z); asynchronous variant __next__
+y = o.__aenter__()          # Called when entering async with o as z: pass (inside a
+                            # coroutine); y is an awaitable which - when it completes -
+                            # produces the value to be assigned to z; asynchronous variant
+                            # of __enter__
+y = o.__aexit__(None, None, None)   # Called when exiting async with o: pass (inside a
+                            # coroutine) (if no exceptions); y is an awaitable which
+                            # completes when the __aexit__ coroutine completes;
+                            # asynchronous variant of __exit__
+y = o.__aexit__(excp_type, excp_val, traceback)     # Called when exiting
+                            # async with o: raise excp (inside a coroutine); y is an
+                            # awaitable which - when it completes - produces a value, and
+                            # if bool(value) == True, the exception is suppressed;
+                            # asynchronous variant of __exit__
+
+# Buffer protocol
+y = o.__buffer__(flags)     # Called by z = memoryview(o) which sets flags =
+                            # inspect.BufferFlags.FULL_RO and wraps y in z
+o.__release_buffer__(y)     # Called by z.release() where z = memoryview(o) and y =
+                            # o.__buffer__(flags) as described above
+
+ +See also special methods for descriptors. + +

Modules

+ +

Module Creation and Usage

+ +File mymodule.py: +
+# Here's a docstring for this module:
+"""Any Python file can be imported as a module,
+or run as a top level script.
+"""
+
+def f(x):
+    return x * 2
+
+if __name__ == '__main__':      # If this file is run as a script, its module name is
+                                # '__main__',
+    print(f(10))                # in which case call f and print the result '20'
+else:                           # Otherwise, this file is imported as a module,
+    print('Module:', __name__)  # so print 'Module: mymodule'
+
+ +Some other Python file: +
+import mymodule         # Runs mymodule.py; puts all its names into namespace 'mymodule';
+                        # the module prints 'Module: mymodule'
+import os, re           # Imports multiple modules in same statement
+type(mymodule)          # Returns class types.ModuleType with name 'module'
+print(mymodule.f(8))    # Calls mymodule's function f, and prints result '16'
+print(mymodule.__doc__) # Prints mymodule's docstring: 'Any Python file can be ...'
+print(__doc__)          # Prints 'None' (this module has no docstring)
+
+ +Some other Python file: +
+import mymodule as m    # Runs mymodule.py; puts all its names into namespace 'm';
+                        # the module prints 'Module: mymodule'
+import os as o, re as r # Imports multiple modules in same statement
+print(m.f(8))           # Calls mymodule's function f, and prints result '16'
+
+ +Some other Python file: +
+from mymodule import f  # Runs mymodule.py; puts its name f into our namespace;
+                        # the module prints 'Module: mymodule'
+from re import sub, subn    # Imports multiple names from module in same statement
+print(f(8))             # Calls function f (defined in mymodule), and prints result '16'
+
+ +Some other Python file: +
+from mymodule import f as g # Runs mymodule.py; binds name g in our namespace to whatever
+                            # mymodule's name f is bound to;
+                            # the module prints 'Module: mymodule'
+from re import (sub as s,   # Imports multiple names from module in same statement;
+                subn as sn) # parentheses can be used to avoid backslash line-continuation
+print(g(8))             # Calls function g (f in mymodule), and prints result '16'
+
+ +Some other Python file: +
+from mymodule import *  # Runs mymodule.py; puts all its names into our namespace;
+                        # the module prints 'Module: mymodule'
+print(f(8))             # Calls function f (defined in mymodule), and prints result '16'
+
+ +

Some Standard Modules

+ +Python has a large number of standard modules which are included in the Python installation. A few are mentioned here. + +
+import sys              # System functionality, e.g. argv, exit(), stdin, stdout, stderr,
+                        # path, version_info
+import os               # Operating system functions, e.g. getcwd(), chdir(), mkdir(),
+                        # makedirs(), rmdir(), remove(), rename(), walk()
+import os.path          # Path manipulation, e.g. exists(), join(), abspath(), dirname(),
+                        # basename()
+import subprocess       # Running external programs, e.g. run('echo hi', shell=True, \
+                        # capture_output=True).stdout
+import logging          # Logging, e.g. info(), warning(), error(), debug()
+import atexit           # Exit handler registration, e.g. register()
+
+import math             # Math constants and functions, e.g. pi, e, sqrt(), sin()
+import cmath            # Complex math functions, e.g. sqrt(-1)
+import decimal          # Class for precise representation of decimal numbers, e.g.
+                        # Decimal('0.1'); see float type
+import random           # Random number generation, e.g. random(), randint(), randbytes()
+import functools        # Function manipulation, e.g. partial(), reduce(), @wraps
+import itertools        # Iterator construction, e.g. cycle(), chain(), permutations()
+
+import re               # See regular expressions
+import collections      # See container types
+import copy             # Shallow/deep object copying functions, e.g. copy(), deepcopy()
+
+import time             # Time functions, e.g. sleep(), monotonic()
+import datetime         # Date/time objects, e.g. datetime.now(timezone.utc).astimezone() \
+                        # .strftime('%Y-%m-%d %H:%M:%S.%f UTC%z')
+
+ +

Non-Standard Modules

+ +In addition to the large number of standard modules, +an even larger number of non-standard modules are available for installation. A few are mentioned here. + +
+import numpy            # Numerical vector/matrix math
+import scipy            # Scientific/engineering math (uses numpy)
+import matplotlib       # Graphing (uses numpy)
+
+ +

Before they can be imported by Python scripts, non-standard modules/packages need to be installed on top of the +relevant Python installation. This may be done by running (on the command line) the 'pip' command belonging to the +Python installation. If you have multiple Python installations, e.g. for different Python versions, make sure to use the +'pip' command belonging to the one you wish to install modules for.

+ +

Example of a Linux command (not Python code) to install numpy:

+ +
+/path/to/correct/pip install numpy
+
+ +or + +
+/path/to/correct/python -m pip install numpy
+
+ +On Windows the Python launcher py.exe may be used in the following way (where 'X.Y' is the Python version to install the +module for): + +
+py -X.Y -m pip install numpy
+
+ +

Packages

+ +

A package is a collection of modules and may also contain nested subpackages. In its simplest form a package is a +directory (on a disk) containing an __init__.py file along with the module files and subpackage directories belonging to +the package.

+ +

When a package is imported, the resulting package object has the same type as a module object, but has an additional +__path__ attribute pointing to the package directory.

+ +

Let's assume we have the following directory structure and files:

+ +
mypackage/ +
__init__.py
+
mymodule0.py
+
subpkg1/ +
__init__.py
+
mymodule1.py
+
mymodule1b.py
+
+
subpkg2/ +
__init__.py
+
mymodule2.py
+
+
subpkg3/ +
__init__.py
+
mymodule3.py
+
mymodule3b.py
+
+
+ +

The file contents are as follows:

+ +File mymodule1.py: +
+# Importing using relative package references
+from . import mymodule1b        # Imports mymodule1b from same subpackage
+from ..subpkg3 import mymodule3 # Imports mymodule3 from sibling subpackage subpkg3
+from .. import mymodule0        # Imports mymodule0 from parent package mypackage
+# Importing using absolute package reference (from top level package)
+from mypackage.subpkg3 import mymodule3b    # Imports mymodule3b
+
+def who():
+    print(__name__)     # Prints the module name (incl. parent package names)
+
+def who1b():
+    mymodule1b.who()    # Calls the who function in mymodule1b
+
+def who3():
+    mymodule3.who()     # Calls the who function in mymodule3
+
+def who3b():
+    mymodule3b.who()    # Calls the who function in mymodule3b
+
+def who0():
+    mymodule0.who()     # Calls the who function in mymodule0
+
+ +All other mymodule*.py files: +
+def who():
+    print(__name__)     # Prints the module name (incl. parent package names)
+
+ +File __init__.py under subpkg1: +
+__all__ = ['mymodule1']     # Specifies which modules to import from subpkg1 if '*' is used
+
+ +All other __init__.py files are empty: +
+
+ +The package can now be used by some other Python file: +
+import mypackage.subpkg1.mymodule1  # Imports mymodule1 from the package
+type(mypackage)                     # Returns class types.ModuleType with name 'module'
+                                    # (a package is also a module)
+mypackage.subpkg1.mymodule1.who()   # Prints 'mypackage.subpkg1.mymodule1'
+
+ +Some other Python file: +
+from mypackage.subpkg1 import mymodule1 # Imports mymodule1 from the package
+mymodule1.who()                         # Prints 'mypackage.subpkg1.mymodule1'
+mymodule1.who1b()                       # Prints 'mypackage.subpkg1.mymodule1b'
+mymodule1.who3()                        # Prints 'mypackage.subpkg3.mymodule3'
+mymodule1.who3b()                       # Prints 'mypackage.subpkg3.mymodule3b'
+mymodule1.who0()                        # Prints 'mypackage.mymodule0'
+
+ +Some other Python file: +
+from mypackage.subpkg1 import *     # Imports all modules mentioned in the __all__ list in
+                                    # subpkg1's __init__.py  (i.e. mymodule1)
+from mypackage.subpkg2 import *     # Imports nothing because subpkg2's __init__.py doesn't
+                                    # define an __all__ list
+mymodule1.who()                     # Prints 'mypackage.subpkg1.mymodule1'
+mymodule2                           # Raises NameError because mymodule2 was never imported
+
+ +

Names

+ +

Binding Names to Objects

+ +Almost everything (values, functions, classes, modules) is an object - mutable or immutable. +Names are not objects themselves - they come into existence when they are bound (assigned) to +objects, and may subsequently be rebound to different objects or deleted. +An object may have multiple names bound to it, and becomes irrelevant (possibly deleted) when +there are no more references to it. +Names are NOT permanent references to fixed storage locations which can be filled with values +as in some other languages (e.g. C). + +
+x = 10                  # (Creates and) binds name x to (immutable) object 10
+y = x                   # Binds name y to same object as name x
+del x                   # Forgets name x; its previously bound object is still bound to y
+z = 10                  # Binds name z to (immutable) object 10 (possibly same object 10
+                        # that y is bound to; mutable objects will never be reused like
+                        # this)
+y = 11                  # Binds name y to a different object than before
+p = q = ['hi']          # Binds names p and q to same (mutable) object (first p, then q!)
+p, z = z, p             # Swaps objects bound to names p and z (so p = 10, z = ['hi'])
+
+def f1(b):              # Binds name f1 to function object defined here, and binds name b
+                        # to object passed as argument to f1
+    b = 3               # Binds name b to different object than was passed to f1 (this
+                        # does not alter the passed object nor rebind whatever name was
+                        # used to refer to that object when calling f1)
+    return b            # Returns object bound to name b (and name b goes out of scope)
+
+x = f1(y)               # Calls function object bound to name f1, and passes object bound
+                        # to name y as argument (name y itself is not passed and can't be
+                        # rebound from within f1);
+                        # also binds name x to object returned by function call
+
+class C1:               # Binds name C1 to class object defined here
+    pass
+
+c = C1()                # Binds name c to new instance object created from class object
+                        # bound to name C1
+
+y = (x := 2 + 3) + x    # Adds 2 and 3 and binds name x to resulting object 5, then adds
+                        # that and object bound to name x (i.e. 5) and binds name y to
+                        # resulting object 10; x is still bound to 5 after this statement
+
+ +

Name Scope

+ +
+def f1(x, y):
+    global d, e             # Allows this function to modify module level names d & e
+    print(b, x)             # Prints '1 1'; no need for 'global' to read external b, but
+                            # this will fail if b is assigned anywhere within f1
+                            # (UnboundLocalError exception if assigned after this line)
+                            # (except if we cheat and assign to globals()['b'])
+    c, d, e = 10, 11, 12    # Creates local c hiding external c (because no 'global')
+                            # (but we can still cheat and read/write globals()['c']);
+                            # also creates e at module level (did not exist before this!)
+    f[0] = 13               # f refers to mutable object which can be changed even though
+                            # f is not listed as 'global' (but without 'global' external f
+                            # can't be changed to reference another object)
+    x = 14                  # x was same as external b, but is now 14, while b is still 1
+    y[0] = 15               # y refers to same object as external g, and that object can
+                            # be changed via y (but g can't be changed to refer to another
+                            # object)
+    f2()                    # Calls external function f2
+    if x == 14:             # Function definitions may be conditional like any statement
+                            # (the 'if' body does not have its own local name scope)
+        def f3(d):          # f3 is defined within f1, so can read f1's locals
+            print(d)        # Prints local parameter d which is hiding external d
+            global c        # Gives f3 access to module level c - not local c in f1
+            c = x           # Assigns f1's local x to module level c (now c = 14)
+            nonlocal h      # Gives f3 access to outer scope h (excl. module level)
+            h = 'C'         # Changes f1's h from 'B' to 'C'
+
+    h = 'B'                 # Creates local h hiding external h
+    f3(30)                  # Calls inner function f3 which prints '30'
+    print(b,c,d,e,f,g,h)    # Prints '1 10 11 12 [13] [15] C'; f3 changed h
+
+def f2():                   # f2 is not defined within f1, so can't read f1's locals
+    pass
+
+b, c, d = 1, 2, 3           # Names read by function f1 must be defined before call to f1
+f, g, h = [4], [5], 'A'     # but not necessarily before definition of f1
+f1(b, g)                    # Calls function f1 and sets parameters x = b and y = g
+print(b,c,d,e,f,g,h)        # Prints '1 14 11 12 [13] [15] A'; f1 changed d, e, and objects
+                            # referenced by f & g (but didn't change f & g themselves);
+                            # f3 changed c
+
+ +Notes: + + +

Coroutines/Tasks/Threads/Processes

+ +
+import asyncio              # Support for multiple concurrent tasks/coroutines
+import threading            # Support for multiple threads
+import multiprocessing      # Support for multiple processes
+import concurrent.futures   # Used here for thread and process pool executors
+import contextlib           # Used here to suppress exceptions in a with statement
+import os                   # Used here to get process id
+import datetime             # Used here to get/format current time and do time calculations
+
+# A class to handle thread-safe and process-safe logging
+class Logger:
+    def __init__(self, job_id, lock):
+        self.job_id = job_id
+        self.lock = lock
+
+    # The __call__() method is called automatically when an instance of this class is
+    # called as a function
+    def __call__(self, msg):
+        # Grab the global lock before printing to avoid simultaneous printing from
+        # different threads/processes
+        with self.lock:
+            print('{}, job {} (proc {:5}, thread {:5}): {}'.format(
+                datetime.datetime.now().strftime('%H:%M:%S.%f'),
+                self.job_id, os.getpid(), threading.get_ident(), msg), flush=True)
+
+# A coroutine function identified by the async keyword; returns a coroutine object
+# representing the code in the function body, which is capable of cooperatively sharing
+# the same thread with other coroutines by occasionally allowing itself to be suspended
+# (e.g. by doing an await); execution of and switching between coroutines is handled by an
+# event loop
+async def concurrent_job(job_id, s, lock):
+    log = Logger(job_id, lock)
+    log(f'Started! Input={s!r}')
+    for c in s:
+        # Suspend this task for 1 second
+        await asyncio.sleep(1)
+        log(c)
+    log(f'Done! Result={c!r}')
+    return c
+
+# Another coroutine function whose coroutine object runs forever until cancelled
+async def endless_concurrent_job(job_id, lock, reraise=False):
+    log = Logger(job_id, lock)
+    loop = asyncio.get_running_loop()
+    time = loop.time()
+    log(f'Started! Time={time:.3f}')
+    try:
+        while True:
+            # Suspend this task for 1.7 second
+            await asyncio.sleep(1.7)
+            delta = loop.time() - time
+            time += delta
+            log(f'Time delta={delta:.3f}')
+    except asyncio.CancelledError as e:
+        # An exception was raised to cancel this job
+        log(f'Cancelled, msg={e.args[0]!r}')
+        if reraise:
+            raise
+    time = loop.time()
+    log(f'Time={time:.3f}')
+    log(f'Result={time!r}')
+    return time
+
+# A coroutine generator function identified by the async and yield keywords; returns a
+# generator object which - when iterated - runs each iteration in a coroutine and returns
+# the next yielded item as the result of the coroutine
+async def concurrent_generator_func(job_id, n, lock):
+    log = Logger(job_id, lock)
+    log(f'Started! Input={n}')
+    for i in range(n):
+        # Suspend this task for 1 second
+        await asyncio.sleep(1)
+        log(f'Sending {i}')
+        # Produce the iteration item
+        yield i
+    log('Done!')
+
+# A normal non-cooperative function which blocks the whole thread until it returns, so it
+# should be run on a separate thread or in a separate process if the main thread needs to
+# do other things in parallel
+def blocking_job(job_id, step, lock):
+    log = Logger(job_id, lock)
+    start_time = datetime.datetime.now()
+    end_time = start_time + datetime.timedelta(seconds=5)
+    log(f'Started! Input={step}')
+    i = 0
+    while datetime.datetime.now() < end_time:
+        i += step
+    log(f'Done! Result={i!r}')
+    return i
+
+async def main():
+    # Create a single global lock to be passed to all threads and processes to ensure that
+    # they don't corrupt each other's output (the simpler threading.RLock() can be used for
+    # single-process programs, and no lock is needed for single-thread programs)
+    lock = multiprocessing.Manager().RLock()
+
+    log = Logger('Main', lock)
+    log('Started!')
+
+    # Get running event loop for our thread
+    loop = asyncio.get_running_loop()
+
+    # Start 3 concurrent jobs/coroutines in new separate tasks (in same thread as ours;
+    # return value is a task which is a subclass of a 'future' which represents the job's
+    # promised result when it completes; in addition to being a 'future' a task handles the
+    # execution of the wrapped coroutine object)
+    con1_task = asyncio.create_task(concurrent_job('Con1', 'ABCDEF', lock))
+    con2_task = asyncio.create_task(endless_concurrent_job('Con2', lock))
+    con3_task = asyncio.create_task(endless_concurrent_job('Con3', lock, reraise=True))
+
+    # Start parallel blocking job in new separate thread (in same process as ours; 1st arg
+    # None selects default executor concurrent.futures.ThreadPoolExecutor, next arg
+    # blocking_job is function to call in new thread, and remaining args are passed to that
+    # function; return value is a 'future' object representing this job's promised result
+    # when it completes)
+    blk_t_future = loop.run_in_executor(None, blocking_job, 'BlkT', 1, lock)
+
+    # Start parallel blocking job in new separate process (a separate Python interpreter is
+    # started in that process, loads this module, and calls function blocking_job with
+    # specified args; WARNING: make sure all this code is not run again when this module is
+    # loaded in that new process, or else it will again spawn a new process etc.)
+    process_executor = concurrent.futures.ProcessPoolExecutor()
+    blk_p_future = loop.run_in_executor(process_executor, blocking_job, 'BlkP', -1, lock)
+
+    # While the above jobs are running, iterate through a generator by running each
+    # iteration in a separate coroutine (in same thread as ours)
+    con_g_generator = concurrent_generator_func('ConG', 3, lock)
+    async for i in con_g_generator:
+        log(f'Received {i} from ConG')
+
+    # Wait until all jobs (except the endless ones) complete, then get their results as a
+    # list (list items have same order as args to gather())
+    results = await asyncio.gather(con1_task, blk_t_future, blk_p_future)
+    # Convert the results into a dict with the job names as keys
+    results = dict(zip(('Con1', 'BlkT', 'BlkP'), results))
+
+    # Stop endless job Con2 (by raising a CancelledError exception inside it)
+    con2_task.cancel('Bye')
+    # Wait until the job actually stops and get its result (the CancelledError exception is
+    # caught and suppressed in Con2, so no exception is seen here)
+    results['Con2'] = await con2_task
+
+    # Stop endless job Con3 (by raising a CancelledError exception inside it)
+    con3_task.cancel('Ciao')
+    # Wait until the job actually stops (the CancelledError exception is not suppressed in
+    # Con3, so suppress it here; the exception prevents 'await' from returning a result)
+    with contextlib.suppress(asyncio.CancelledError):
+        results['Con3'] = await con3_task
+
+    for job in results:
+        log(f'{job} result: {results[job]!r}')
+    return 'Done!'
+
+# Make sure that main() only gets called when this module is run as a script, not when it
+# is imported as a module (as it will be inside the subprocess spawned by main() - see
+# WARNING above)
+if __name__ == '__main__':
+    # Run coroutine main() and print its return value when it completes
+    print(asyncio.run(main()))
+
+ +Example of output from above code: + +
+16:59:17.484854, job Main (proc 14204, thread 12668): Started!
+16:59:17.487854, job BlkT (proc 14204, thread 12036): Started! Input=1
+16:59:18.100757, job ConG (proc 14204, thread 12668): Started! Input=3
+16:59:18.148753, job BlkP (proc 10388, thread 11804): Started! Input=-1
+16:59:18.244754, job Con1 (proc 14204, thread 12668): Started! Input='ABCDEF'
+16:59:18.324757, job Con2 (proc 14204, thread 12668): Started! Time=1171.968
+16:59:18.388756, job Con3 (proc 14204, thread 12668): Started! Time=1172.062
+16:59:19.226306, job ConG (proc 14204, thread 12668): Sending 0
+16:59:19.257555, job Main (proc 14204, thread 12668): Received 0 from ConG
+16:59:19.319856, job Con1 (proc 14204, thread 12668): A
+16:59:20.120442, job Con2 (proc 14204, thread 12668): Time delta=1.828
+16:59:20.179725, job Con3 (proc 14204, thread 12668): Time delta=1.797
+16:59:20.336100, job ConG (proc 14204, thread 12668): Sending 1
+16:59:20.380381, job Main (proc 14204, thread 12668): Received 1 from ConG
+16:59:20.412978, job Con1 (proc 14204, thread 12668): B
+16:59:21.462500, job ConG (proc 14204, thread 12668): Sending 2
+16:59:21.493750, job Main (proc 14204, thread 12668): Received 2 from ConG
+16:59:21.524633, job ConG (proc 14204, thread 12668): Done!
+16:59:21.565310, job Con1 (proc 14204, thread 12668): C
+16:59:21.913473, job Con2 (proc 14204, thread 12668): Time delta=1.797
+16:59:21.977473, job Con3 (proc 14204, thread 12668): Time delta=1.797
+16:59:22.487480, job BlkT (proc 14204, thread 12036): Done! Result=10168136
+16:59:22.612480, job Con1 (proc 14204, thread 12668): D
+16:59:23.140135, job BlkP (proc 10388, thread 11804): Done! Result=-10056909
+16:59:23.612465, job Con1 (proc 14204, thread 12668): E
+16:59:23.674968, job Con2 (proc 14204, thread 12668): Time delta=1.766
+16:59:23.721724, job Con3 (proc 14204, thread 12668): Time delta=1.750
+16:59:24.623154, job Con1 (proc 14204, thread 12668): F
+16:59:24.623154, job Con1 (proc 14204, thread 12668): Done! Result='F'
+16:59:24.623154, job Con2 (proc 14204, thread 12668): Cancelled, msg='Bye'
+16:59:24.624165, job Con2 (proc 14204, thread 12668): Time=1178.312
+16:59:24.624165, job Con2 (proc 14204, thread 12668): Result=1178.312
+16:59:24.624165, job Con3 (proc 14204, thread 12668): Cancelled, msg='Ciao'
+16:59:24.625165, job Main (proc 14204, thread 12668): Con1 result: 'F'
+16:59:24.625165, job Main (proc 14204, thread 12668): BlkT result: 10168136
+16:59:24.625165, job Main (proc 14204, thread 12668): BlkP result: -10056909
+16:59:24.625165, job Main (proc 14204, thread 12668): Con2 result: 1178.312
+Done!
+
+ +

Running External Programs

+ +

High-Level 'subprocess.run' API

+ +The subprocess.run() method provides an easy way to run an external program in a subprocess and wait for it to complete. + +
+import subprocess                               # Imports subprocess module
+command_line = 'findstr /b [A-P] | sort'        # Prepares a shell command line to execute
+some_input = 'Lisa\nBart\nR2D2\n'               # Prepares some command input
+completed_proc = subprocess.run(command_line,         # Executes the command line
+                                shell=True,           # in a shell
+                                text=True,            # with text (not bytes) input/output,
+                                input=some_input,     # some_input as stdin,
+                                capture_output=True)  # stdout/stderr captured,
+                                                      # and waits for command completion
+completed_proc.returncode                       # Returns 0 (command succeeded)
+completed_proc.stdout                           # Returns 'Bart\nLisa\n' (command output)
+completed_proc.stderr                           # Returns '' (no error output from command)
+
+ +

Low-Level 'subprocess.Popen' API

+ +The subprocess.Popen class provides more fine-grained control than the run() method described above, including the +ability to do something else while the subprocess is running. + +
+import subprocess                               # Imports subprocess module
+
+# The following Windows command line will wait for 1 second (because the waitfor command
+# fails to receive the signal 'nothing' within the specified 1-second deadline), then
+# prints DONE; the final exit code is 0 because the echo command succeeds
+command_line = 'waitfor nothing /t 1 2>NUL || echo DONE'
+
+# An instance of the Popen class can be used as a context manager in a 'with' statement
+# to ensure that pipes are closed and the subprocess is waited for when the 'with' block
+# exits (but here the proc.wait() below explicitly waits for the subprocess)
+with subprocess.Popen(command_line,             # Executes the command line
+                      shell=True,               # in a shell
+                      text=True,                # with text (not bytes) input/output,
+                      stdout=subprocess.PIPE) as proc:  # stdout captured,
+                                                # and doesn't wait for command completion
+    print('Command launched')
+    assert proc.poll() is None                  # proc.poll() returns None while the
+                                                # subprocess is still running
+    proc.wait()                                 # Waits for the subprocess to complete
+                                                # (WARNING: if the subprocess produces more
+                                                # output than will fit in the pipe buffer,
+                                                # it will stall and never end because
+                                                # proc.wait does not read from proc.stdout
+                                                # while waiting)
+    assert proc.poll() == proc.returncode       # After completion, proc.poll() returns the
+                                                # command exit code
+    print('Finished with code %d and output: %s' % (proc.returncode, proc.stdout.read()))
+
+ +
+Command launched
+Finished with code 0 and output: DONE
+
+
+ +Here's another example showing how the external program output can be obtained line by line as each line becomes +available: + +
+import subprocess                               # Imports subprocess module
+
+# The following Windows command line prints the numbers 1 through 5 and waits for 1 second
+# after each number; the final exit code is 1 because the waitfor command fails to receive
+# the signal 'nothing'
+command_line = 'for /L %i in (1,1,5) do @(echo %i && waitfor nothing /t 1 2>NUL)'
+
+with subprocess.Popen(command_line,             # Executes the command line
+                      shell=True,               # in a shell
+                      text=True,                # with text (not bytes) input/output,
+                      bufsize=1,                # line buffering,
+                      stdout=subprocess.PIPE) as proc:  # stdout captured,
+                                                # and doesn't wait for command completion
+    for line in proc.stdout:                    # Gets 1 line at a time from the subprocess
+        assert proc.poll() is None              # proc.poll() returns None while the
+                                                # subprocess is still running
+        print(line, end='')                     # Prints the received line of text
+
+# When the above 'with' statement exits, it waits for the subprocess to complete
+assert proc.poll() == proc.returncode           # After completion, proc.poll() returns the
+                                                # command exit code
+print('Finished with code %d' % proc.returncode)
+
+ +
+1 
+2 
+3 
+4 
+5 
+Finished with code 1
+
+ +
+ +
+ + + diff --git a/programming/python_quick_ref.html b/programming/python_quick_ref.html new file mode 100644 index 0000000..972b23c --- /dev/null +++ b/programming/python_quick_ref.html @@ -0,0 +1,3105 @@ + + + + + + + +Python 2 Quick Reference + + + + + + + +
+ +

Python 2
Quick Reference

+ +
+ +This is a one-(long-)page overview of the Python 2 (2.7.18) programming +language in the form of commented lines of code. This was a work in progress until the official death of Python 2 in +2020. + +

See also the Python 3 quick reference.

+ +

Contents

+ +

Python Script Execution

+ +

Shebang

+ +
+#!/usr/bin/env python2
+
+ +
+#!/usr/bin/env python2.7
+
+ +
+#!/usr/bin/env python2.7.18
+
+ +With one of the above shebangs as the first line of the script, most Unix/Linux systems will +automatically pass the script to the latest installed version 2.x.x, 2.7.x, or 2.7.18 Python +interpreter when the script is run as a command. This also works on Windows if the script is passed +to (or the typical script extension .py is associated with) the Python launcher py.exe. + +

Syntax

+ +

Statement Boundaries

+ +
+a = 3                   # Statements are usually separated by newlines
+print a                 # ...
+b = 'hi'; print b       # (Non-compound) statements may be separated by semicolon
+c = 4;                  # and optionally terminated by semicolon
+                        # but using semicolons is discouraged (PEP 8)
+d = 2 * a + \
+    c                   # Any statement can be split across multiple lines
+                        # using backslash + newline (nothing allowed between the two)
+print 'hel\
+  lo'                   # Prints 'hel  lo' (any indention is included in string)
+print 'hel' \
+    'lo'                # Prints 'hello' (adjacent string literals are concatenated)
+d = 2 * (a +            # No backslash needed inside parentheses/brackets/...
+    c)
+print ('hel'            # Prints 'hello' (adjacent string literals are concatenated;
+    'lo')               # no backslash needed inside parentheses)
+
+ +

Comments and Docstrings

+ +
+# Comments start with the '#' and end at the end of the same line,
+# so a comment spanning multiple lines must have '#' at the start
+# of each line.
+a = 3                   # Here's a comment following some code
+b = a + \               # ILLEGAL comment after backslash
+    2 +                 # and backslash WON'T WORK after comment either -> \
+    3                   # Comment must be on last line when using backslashes
+
+"""Another way to make a multiline comment
+is to put it inside a multiline string which
+is not assigned to anything."""
+
+def f():
+    # Here's a docstring for this function (similar for classes, modules):
+    """When a string is the first statement of a function (or class
+    or module), it becomes that object's docstring, accessible via
+    the __doc__ attribute. All lines traditionally have the same
+    indentation, and those spaces become part of the string.
+    """
+    return 3.14
+
+print f.__doc__         # Prints f's docstring (or None if none): 'When a string ...'
+help(f)                 # Prints information about f - including f's docstring
+
+ +

Compound Statement Format

+ +
+if len(mylist) > 0:     # A compound statement contains a header
+    sum = 0             # and a suite of statements with same indentation
+    for x in mylist:    # and possibly nested compound statements
+        print x
+        sum += x
+    print sum
+else:                   # and possibly another header
+    print 'Empty list'  # and its associated suite
+
+def func(x):            # A compound statement cannot have an empty suite
+    pass                # but 'pass' can be used to do nothing
+
+if x < y: x = y; y = 0  # Single-line compound statement (discouraged)
+                        # (cannot contain nested compound statements)
+
+ +

Expression Lists

+ +
+# Expression list
+t = 4, a + 1, 'hi'      # Right-hand side expression list becomes tuple (4, 2, 'hi')
+                        # (assuming a = 1)
+a, (b, c) = 3, (4, 5)   # Multiple assignments a=3, b=4, c=5 using expression lists
+                        # (all right-hand expressions are evaluated before any assignments)
+a, (b, c) = [3, (4, 5)] # Some alternatives equivalent to above; [] could also be ()
+[a, (b, c)] = 3, (4, 5) # ...
+10,                     # Trailing comma is illegal/mandatory/optional if 0/1/more items
+[4, a + 1, 'hi']        # List created from expression list
+{4, a + 1, 'hi'}        # Set created from expression list
+f(4, a + 1, 'hi')       # Function call using expression list as argument list
+f(*range(2), **{'a':5}) # Iterable unpacking; same as f(0, 1, a=5)
+
+ +

Types

+ +

Basic Types (Immutable)

+ +
+# Int
+i = -2                  # Assigns an int (range from -sys.maxint-1 thru sys.maxint)
+type(i)                 # Returns type int
+isinstance(i, int)      # Returns True
+int('20')               # Returns 20 (an int)
+int('20', 16)           # Returns 32 (second arg is base, 16 means hex)
+i += 0xA + 0o12 + 0b10  # i is now 20 (-2 + 10 + 10 + 2); this is hex + octal + binary
+012                     # Returns 10; this octal format is discouraged, use 0o12
+i.bit_length()          # Returns 5 (minimum number of bits needed to represent 20)
+(5).bit_length()        # Returns 3 (5.bit_length() would fail because 5. means 5.0)
+
+# Long
+j = -5L                 # Assigns a long (infinite range and precision)
+type(j)                 # Returns type long
+isinstance(j, long)     # Returns True
+long(2)                 # Returns 2L
+long('20', 16)          # Returns 32L
+
+# Float
+x = -3.4                # Assigns a float (range: sys.float_info.min to sys.float_info.max)
+type(x)                 # Returns type float
+isinstance(x, float)    # Returns True
+float(3)                # Returns 3.0
+float('2.5e6')          # Returns 2500000.0
+float('inf')            # Returns positive infinity (greater than sys.float_info.max)
+float('-inf')           # Returns negative infinity (less than sys.float_info.min)
+float('nan')            # Returns the "not a number" (NaN) error value
+0 * float('inf')        # Returns float('nan')
+import math                 # Imports math module
+math.isinf(float('-inf'))   # Returns True
+math.isnan(float('nan'))    # Returns True
+float('nan') == float('nan')# Returns False; NaN is unequal to everything, incl. itself
+1. + .2 + 3.4e-2        # Returns 1.234 (1. means 1.0, .2 means 0.2)
+
+# Complex
+c = 1+2j                # Assigns a complex (pair of floats)
+type(c)                 # Returns type complex
+isinstance(c, complex)  # Returns True
+c.real                  # 1.0
+c.imag                  # 2.0
+c.real = 3              # ILLEGAL! Raises TypeError exception (complex is immutable)
+c.conjugate()           # Returns (1-2j)
+complex(1, 2)           # Returns (1+2j)
+complex('1+2j')         # Returns (1+2j)
+complex(1+2j, 10j)      # Returns (-9+2j)
+
+# Bool
+b = True                # Assigns a bool (True or False)
+type(b)                 # Returns type bool
+isinstance(b, bool)     # Returns True
+bool(0)                 # Returns False for 0 (else True)
+bool('')                # Returns False for empty sequence type (else True)
+bool(None)              # Returns False
+int(True)               # Returns 1
+int(False)              # Returns 0
+3 + True                # Returns 4
+False * 5               # Returns 0
+
+# None
+x = None                # Assigns null object (nothing, unassigned argument/return value)
+type(x)                 # Returns type with name 'NoneType'; None is the only instance of
+                        # this type
+isinstance(x, type(None)) # Returns True
+bool(x)                 # Returns False
+
+# Slice
+sl = slice(3)           # Assigns a slice object equivalent to the :3 in a[:3] (supports
+                        # same parameters as xrange(), except negative start/stop values
+                        # are counted from end); more under classes
+type(sl)                # Returns type slice
+isinstance(sl, slice)   # Returns True
+print sl                # Prints 'slice(None, 3, None)'
+'hello'[sl]             # Returns 'hel' (same as 'hello'[:3])
+sl.start, sl.stop, sl.step  # Returns (None, 3, None)
+sl.indices(len('hello'))    # Returns (0, 3, 1) (xrange()-style (start, stop, step) args)
+sl.indices(len('hi'))       # Returns (0, 2, 1) (range is reduced to fit given length)
+sl = slice(-2, None, -1)# Assigns a slice object equivalent to the -2::-1 in a[-2::-1]
+'hello'[sl]             # Returns 'lleh' (same as 'hello'[-2::-1])
+sl.indices(len('hello'))# Returns (3, -1, -1) (here, stop == None for slice() maps to
+                        # stop == -1 for xrange())
+
+# Ellipsis
+e = Ellipsis            # Assigns Ellipsis object (intended for extended slice syntax)
+type(e)                 # Returns type with name 'ellipsis'; Ellipsis is the only instance
+                        # of this type
+isinstance(e, type(Ellipsis)) # Returns True
+bool(e)                 # Returns True
+
+# NotImplemented
+n = NotImplemented      # Assigns NotImplemented object (returned by methods such as
+                        # __add__ when they can't handle the provided argument type; the
+                        # interpreter will then try something else such as calling __radd__
+                        # on the other operand)
+type(n)                 # Returns type with name 'NotImplementedType'; NotImplemented is
+                        # the only instance of this class
+isinstance(n, type(NotImplemented)) # Returns True
+bool(n)                 # Returns True
+
+# Object
+o = object()            # Assigns a featureless object; object is the base of all new-style
+                        # classes and built-in types (about classes/types and objects)
+type(o)                 # Returns type object
+isinstance(o, object)   # Returns True
+isinstance(10, object)  # Returns True (int is a subclass of object)
+
+# Type
+T = type('MyT', (), {}) # Assigns a type object; all new-style classes and built-in types
+                        # are instances of type (about classes/types and objects)
+type(T)                 # Returns type type
+isinstance(T, type)     # Returns True
+class T2(object): pass  # Assigns a type object using a class statement (normal approach)
+type(T2)                # Returns type type
+
+ +Notes: + + +

Basic Object Attributes

+ +The following is a list of attributes (properties and methods) provided by instances of the +basic types +int, long, float, complex, bool, slice. +(Some general object attributes and low-level attributes are omitted from this list). +

+ +Show attributes below: + +

+o.__abs__()             # Special method implementing abs(o);
+                        # applies to int,long,float,complex,bool
+o.__add__(o2)           # Special method implementing o + o2;
+                        # applies to int,long,float,complex,bool
+o.__and__(o2)           # Special method implementing o & o2;
+                        # applies to int,long,bool
+o.__cmp__()             # Special method
+                        # applies to int,long,bool,slice
+o.__coerce__()          # Special method
+                        # applies to int,long,float,complex,bool
+o.__div__()             # Special method
+                        # applies to int,long,float,complex,bool
+o.__divmod__()          # Special method
+                        # applies to int,long,float,complex,bool
+o.__eq__()              # Special method
+                        # applies to float,complex
+o.__float__()           # Special method
+                        # applies to int,long,float,complex,bool
+o.__floordiv__()        # Special method
+                        # applies to int,long,float,complex,bool
+o.__ge__()              # Special method
+                        # applies to float,complex
+o.__getformat__()       # TBD
+                        # applies to float
+o.__getnewargs__()      # TBD (pickle protocol)
+                        # applies to int,long,float,complex,bool
+o.__gt__()              # Special method
+                        # applies to float,complex
+o.__hex__()             # Special method
+                        # applies to int,long,bool
+o.__index__()           # Special method
+                        # applies to int,long,bool
+o.__int__()             # Special method
+                        # applies to int,long,float,complex,bool
+o.__invert__()          # Special method
+                        # applies to int,long,bool
+o.__le__()              # Special method
+                        # applies to float,complex
+o.__long__()            # Special method
+                        # applies to int,long,float,complex,bool
+o.__lshift__()          # Special method
+                        # applies to int,long,bool
+o.__lt__()              # Special method
+                        # applies to float,complex
+o.__mod__()             # Special method
+                        # applies to int,long,float,complex,bool
+o.__mul__()             # Special method
+                        # applies to int,long,float,complex,bool
+o.__ne__()              # Special method
+                        # applies to float,complex
+o.__neg__()             # Special method
+                        # applies to int,long,float,complex,bool
+o.__nonzero__()         # Special method
+                        # applies to int,long,float,complex,bool
+o.__oct__()             # Special method
+                        # applies to int,long,bool
+o.__or__()              # Special method
+                        # applies to int,long,bool
+o.__pos__()             # Special method
+                        # applies to int,long,float,complex,bool
+o.__pow__()             # Special method
+                        # applies to int,long,float,complex,bool
+o.__radd__()            # Special method
+                        # applies to int,long,float,complex,bool
+o.__rand__()            # Special method
+                        # applies to int,long,bool
+o.__rdiv__()            # Special method
+                        # applies to int,long,float,complex,bool
+o.__rdivmod__()         # Special method
+                        # applies to int,long,float,complex,bool
+o.__rfloordiv__()       # Special method
+                        # applies to int,long,float,complex,bool
+o.__rlshift__()         # Special method
+                        # applies to int,long,bool
+o.__rmod__()            # Special method
+                        # applies to int,long,float,complex,bool
+o.__rmul__()            # Special method
+                        # applies to int,long,float,complex,bool
+o.__ror__()             # Special method
+                        # applies to int,long,bool
+o.__rpow__()            # Special method
+                        # applies to int,long,float,complex,bool
+o.__rrshift__()         # Special method
+                        # applies to int,long,bool
+o.__rshift__()          # Special method
+                        # applies to int,long,bool
+o.__rsub__()            # Special method
+                        # applies to int,long,float,complex,bool
+o.__rtruediv__()        # Special method
+                        # applies to int,long,float,complex,bool
+o.__rxor__()            # Special method
+                        # applies to int,long,bool
+o.__setformat__()       # TBD
+                        # applies to float
+o.__sub__()             # Special method
+                        # applies to int,long,float,complex,bool
+o.__truediv__()         # Special method
+                        # applies to int,long,float,complex,bool
+o.__trunc__()           # Special method
+                        # applies to int,long,float,bool
+o.__xor__()             # Special method
+                        # applies to int,long,bool
+
+ +
+o.as_integer_ratio()    # Returns 2-tuple of integers whose ratio is equal to o;
+                        # (-1.5).as_integer_ratio() returns (-3,2); 0.1.as_integer_ratio()
+                        # returns (3602879701896397L, 36028797018963968L);
+                        # applies to float
+o.bit_length()          # Returns minimum number of bits (disregarding sign) needed to
+                        # represent o; (10).bit_length() returns 4;
+                        # applies to int,long,bool
+o.conjugate()           # Returns complex conjugate of o; (1+2j).conjugate() returns (1-2j);
+                        # applies to int,long,float,complex,bool
+o.denominator           # Returns 1 (unless o is a fractions.Fraction);
+                        # applies to int,long,bool
+o.fromhex(s)            # Class method; returns float value converted from hex number in
+                        # string s; float.fromhex(' ff.8 ') returns 255.5;
+                        # float.fromhex('0x1p10') returns 1024.0;
+                        # applies to float
+o.hex()                 # Returns hex string representing float o (in '0x#p#' format);
+                        # 255.0.hex() returns '0x1.fe00000000000p+7';
+                        # applies to float
+o.imag                  # Returns imaginary part of o (which is 0 if o is not complex);
+                        # applies to int,long,float,complex,bool
+o.indices(n)            # Returns tuple of integers (start, stop, step) which can be passed
+                        # to range() to get a sequence of indices corresponding to applying
+                        # slice o to a sequence of length n;
+                        # ii = slice(None,None,-1).indices(5) makes ii (4,-1,-1), and
+                        # range(*ii) returns [4,3,2,1,0];
+                        # applies to slice
+o.is_integer()          # Returns True if o is integral; 3.0.is_integer() returns True;
+                        # applies to float
+o.numerator             # Returns int(o) (unless o is a fractions.Fraction);
+                        # applies to int,long,bool
+o.real                  # Returns real part of o (which is o or int(o) if o is not complex);
+                        # applies to int,long,float,complex,bool
+o.start                 # Read-only start value of slice o; slice(2,5).start returns 2;
+                        # applies to slice
+o.step                  # Read-only step value of slice o; slice(5,2,-1).step returns -1;
+                        # applies to slice
+o.stop                  # Read-only stop value of slice o; slice(5).stop returns 5;
+                        # applies to slice
+
+ +

Container Types

+ +
+# Container type detection
+import collections
+isinstance(o, collections.Container)  # Returns True if o is a container object (e.g. 'hi')
+                                      # (except for memoryview)
+
+ +

Sequence Types

+ +
+# Sequence type detection
+import collections
+isinstance(o, collections.Sequence)  # Returns True if o is a sequence object (e.g. 'hi')
+                                     # (except for memoryview)
+
+# String
+s1 = 'Say "hi"\n\'ho\'' # Assigns a string (immutable): Say "hi"(newline)'ho'
+s2 = "Say 'hi'\n\"ho\"" # Same as above, but with swapped single- and double-quotes
+                        # (Single-quotes allow embedded unescaped double-quotes, and vice
+                        # versa, otherwise no difference in behavior)
+s3 = """Say "hi"
+'ho'"""                 # Same as s1 above; triple-quotes allow embedded unescaped newlines
+                        # (usually used for docstrings)
+s4 = '''Say 'hi'
+"ho"'''                 # Same as s2 above (but triple single-quotes are not often used)
+s5 = r'\n\''            # Raw string of length 4; backslashes are taken literally, but
+                        # still escape quotes; often used for regular expressions
+s6 = r"""\\
+"""                     # Raw triple-quoted string of length 3: 2 backslashes and a newline
+                        # (see s3 and s5 above)
+b'hi', br'ho'           # Same as 'hi', r'ho'; Python 2 ignores the b prefix
+s = ('hel'              # Adjacent string literals are concatenated (s = 'hello');
+    "lo")               # useful for splitting string literals and commenting each part
+                        # (see statement boundaries for other ways of breaking strings)
+type(s)                 # Returns type str
+isinstance(s, str)      # Returns True
+len(s)                  # Returns 5
+'e' in s                # Returns True
+s[0]                    # Returns 'h'
+s[0] = 'a'              # ILLEGAL! Raises TypeError exception because string is immutable
+s[-1]                   # Returns 'o'
+s[1:3]                  # Returns 'el' (general slice syntax is [start:stop:step] with
+                        # default values (if omitted) start=0, stop=end, step=1)
+s[-2:]                  # Returns 'lo'
+s[:-1]                  # Returns 'hell'
+s[::-1]                 # Returns 'olleh'
+s + ' there'            # Returns 'hello there'
+s * 2                   # Returns 'hellohello'
+str(4.1)                # Returns '4.1'
+
+# Unicode
+s1 = u'\xC6\u0E01\U0001F60E'   # Assigns a 4-character unicode (UTF-16) string (immutable);
+                        # '\U0001F60E' is stored as the surrogate pair '\uD83D\uDE0E'
+s2 = u"\u0E01"          # Same quote variants as for non-unicode strings (see above)...
+s3 = u"""\u0E01
+\u0E2E"""
+s4 = ur'\u0E01\n'       # (Note: \u escapes are interpreted even in raw string, so s4 has
+                        # 3 chararacters)
+type(s1)                # Returns type unicode
+isinstance(s1, unicode) # Returns True
+len(s1)                 # Returns 4
+len(s3)                 # Returns 3
+len(s4)                 # Returns 3
+s1[-1]                  # Returns u'\ude0e'
+unicode(4.1)            # Returns u'4.1'
+
+# Basestring (abstract superclass for string and unicode types)
+isinstance('hi', basestring)    # Returns True (same as isinstance('hi', (str, unicode)))
+isinstance(u'hi', basestring)   # Returns True
+
+# List
+a1 = [3, 'hello']       # Assigns a list (mutable)
+type(a1)                # Returns type list
+isinstance(a1, list)    # Returns True
+len(a1)                 # Returns 2
+'hello' in a1           # Returns True
+a1[-1]                  # Returns 'hello'
+a1[0] = 4               # Assigns 4 to first item
+a1.append('bye')        # a1 is now [4, 'hello', 'bye']
+a1.extend([10, 11])     # a1 is now [4, 'hello', 'bye', 10, 11]
+a1[-2:] = [9]           # a1 is now [4, 'hello', 'bye', 9]
+del a1[-2:]             # a1 is now [4, 'hello']
+a2 = a1                 # a2 now points to same list as a1
+                        # (changes to a1 items affect a2 items)
+a2 = a1[:]              # a2 is now a shallow copy of a1
+                        # (changes to 1st level of a1 don't affect a2)
+                        # (use a2 = copy.deepcopy(a1) to make a complete copy)
+list('hello')           # Returns ['h', 'e', 'l', 'l', 'o']
+
+# Tuple
+t = (3, 'hello')        # Assigns a tuple (immutable)
+t = 3, 'hello'          # Same as above but using unenclosed expression list
+type(t)                 # Returns type tuple
+()                      # Returns () (empty tuple)
+(4,)                    # Returns (4,) (single-item tuple)
+(4)                     # Returns 4 (int, not tuple)
+isinstance(t, tuple)    # Returns True
+len(t)                  # Returns 2
+'hello' in t            # Returns True
+t[-1]                   # Returns 'hello'
+t[-1] = 'a'             # ILLEGAL! Raises TypeError exception because tuple is immutable
+tuple('hello')          # Returns ('h', 'e', 'l', 'l', 'o')
+t2 = (4, [])            # Although tuples are immutable, they may contain mutable items
+t2[-1].append(5)        # t2 is now (4, [5])
+
+# Namedtuple types
+import collections
+NT = collections.namedtuple('Mynamedtuple', 'x,y,z')    # Assigns a new named tuple type;
+                        # namedtuple itself is not a type but a function that makes a type
+type(NT)                # Returns type type
+nt = NT(4, 5, z=6)      # Assigns a named tuple of type NT (immutable; like tuple, but
+                        # allows items to be accessed by name)
+type(nt)                # Returns class with name 'Mynamedtuple'
+isinstance(nt, NT)      # Returns True
+nt.x                    # Returns 4 (unlike tuple)
+nt[-1]                  # Returns 6 (like tuple)
+5 in nt                 # Returns True (like tuple)
+NT._make([6,7,8])       # Same as NT(6, 7, 8) or NT(*[6, 7, 8])
+
+# Bytearray
+b1 = bytearray(2)               # Assigns a bytearray (mutable) containing 2 null bytes
+b2 = bytearray([65, 66, 67])    # Assigns a bytearray from a list
+                                # (each value must be in the range 0-255)
+b3 = bytearray(u'\u0E01\u0E2E', 'utf_8')  # Assigns a bytearray from a string using the
+                                          # specified encoding
+list(b1)                        # Returns [0, 0]
+list(b2)                        # Returns [65, 66, 67]
+list(b3)                        # Returns [224, 184, 129, 224, 184, 174]
+print b2                        # Prints 'ABC'; bytearray converted to string
+print b2[0]                     # Prints '65'; no conversion of single byte
+type(b1)                        # Returns type bytearray
+isinstance(b1, bytearray)       # Returns True
+len(b1)                         # Returns 2
+b1[0] = 72                      # b1 now contains 72, 0
+b1[1:] = 'ey'                   # b1 now contains 72, 101, 121
+b1 += b2                        # b1 now contains 72, 101, 121, 65, 66, 67
+print b1                        # Prints 'HeyABC'
+
+# Memoryview
+s = 'hello'
+m = memoryview(s)       # Assigns a memoryview referencing object s
+type(m)                 # Returns type memoryview
+isinstance(m, memoryview)   # Returns True
+m.readonly              # Returns True (because the referenced object s is immutable)
+m[-1]                   # Returns 'o'
+m[1:4]                  # Returns a new memoryview referencing s[1:4]
+ba = bytearray('hello') # Assigns a bytearray containing 'hello'
+m2 = memoryview(ba)     # Assigns a memoryview referencing object ba
+m2.readonly             # Returns False (because the referenced object ba is mutable)
+m2[1] = 'u'             # ba is now bytearray('hullo')
+
+# Xrange
+xr = xrange(4)          # Assigns an xrange object (immutable) representing 0, 1, 2, 3
+                        # without actually storing this sequence like range() would
+r = range(4)            # Assigns list [0, 1, 2, 3] returned from standard function
+type(xr)                # Returns type xrange
+type(r)                 # Returns type list
+print xr                # Prints 'xrange(4)'; xr is an unexpanded xrange object
+print r                 # Prints '[0, 1, 2, 3]'; r is an actual list
+print list(xr)          # Prints '[0, 1, 2, 3]'; list(xr) expands xr to a list
+print tuple(xr)         # Prints '(0, 1, 2, 3)'; tuple(xr) expands xr to a tuple
+print tuple(r)          # Prints '(0, 1, 2, 3)'; an actual list can also become a tuple
+isinstance(xr, xrange)  # Returns True
+len(xr)                 # Returns 4
+xr[-1]                  # Returns 3
+xrange(2, 5)            # Returns xrange object representing sequence 2, 3, 4
+xrange(1, -2, -1)       # Returns xrange object representing sequence 1, 0, -1 (from 1 to
+                        # -2 (-2 excluded) with step -1)
+
+# Buffer (no longer recommended; use memoryview instead)
+s = 'hello'
+b = buffer(s)           # Assigns a buffer which is a readonly reference to object s
+type(b)                 # Returns type buffer
+b[-1]                   # Returns 'o'
+ba = bytearray(s)       # Assigns a bytearray containing 'hello'
+b2 = buffer(ba, 1, 3)   # Assigns a buffer referencing ba[1:4], i.e. the 'ell' part of ba
+ba[3] = 'i'             # ba is now bytearray('helio'), and b2 is buffer('eli')
+str(b2)                 # Returns 'eli'
+
+ +

Other Container Types

+ +
+# Set
+u = {3, 'hello'}        # Assigns a set (mutable; unordered unique items)
+type(u)                 # Returns type set
+set()                   # Returns empty set
+{}                      # Returns empty dict, not set!
+isinstance(u, set)      # Returns True
+len(u)                  # Returns 2
+'hello' in u            # Returns True
+u.add(10)               # u is now {10, 3, 'hello'} (undefined order)
+u.remove(10)            # u is now {3, 'hello'}
+u.remove(10)            # Raises KeyError exception (no such item)
+u.discard(3)            # u is now {'hello'}
+u.discard(3)            # u is unchanged (did not contain 3)
+set('hello')            # Returns {'h', 'e', 'l', 'o'} (only one 'l')
+
+# Frozenset
+w = frozenset((3, 'hi'))    # Assigns a frozenset (like a set, but immutable, so can be
+                            # used as a dictionary key or element of a set)
+type(w)                     # Returns type frozenset
+isinstance(w, frozenset)    # Returns True
+
+# Dict
+d = {'a':10, 'b':5}     # Assigns a dictionary (mutable unordered mapping; unique keys)
+type(d)                 # Returns type dict
+{}                      # Returns {} (empty dict, not set)
+isinstance(d, dict)     # Returns True
+len(d)                  # Returns 2
+'a' in d                # Returns True
+d['a'] = 11             # d is now {'a': 11, 'b': 5}
+d.keys()                # Returns ['a', 'b'] (list)
+d.values()              # Returns [11, 5]
+d.items()               # Returns [('a', 11), ('b', 5)] (list of tuples)
+del d['a']              # d is now {'b': 5}
+dict((('a',10),('b',5))) # Returns {'a': 10, 'b': 5}
+dict(a=10, b=5)         # Returns {'a': 10, 'b': 5}
+
+# Defaultdict
+import collections
+dd = collections.defaultdict(int, {'a': 3}) # Assigns a defaultdict (same as dict, but the
+                        # first arg is called with no args to provide the default value for
+                        # nonexistent keys; here, int() returns the default value 0)
+type(dd)                # Returns type collections.defaultdict
+isinstance(dd, collections.defaultdict) # Returns True
+dd['a']                 # Returns 3
+dd['b']                 # Returns 0 (because that's what int() returns);
+                        # dd is now defaultdict(int, {'a': 3, 'b': 0})
+dd['c'] += 1            # dd is now defaultdict(int, {'a': 3, 'b': 0, 'c': 1})
+
+# OrderedDict
+import collections
+od = collections.OrderedDict([('a',10), ('b',11), ('c',12)]) # Assigns an OrderedDict (like
+                            # dict but ordered, e.g. od.keys() lists keys in the order they
+                            # were added)
+type(od)                    # Returns class collections.OrderedDict
+isinstance(od, collections.OrderedDict) # Returns True
+od.popitem()                # Returns ('c',12); od is now OrderedDict([('a',10), ('b',11)])
+od.popitem(last=False)      # Returns ('a',10); od is now OrderedDict([('b',11)])
+
+# Counter
+import collections
+c = collections.Counter('abaab')    # Assigns a Counter (like a dict, but the values are
+                        # counts for the keys, i.e. {'a': 3, 'b': 2})
+type(c)                 # Returns class collections.Counter
+isinstance(c, collections.Counter)  # Returns True
+c['a']                  # Returns 3
+c['x']                  # Returns 0
+c['c'] += 2             # c is now Counter({'a': 3, 'b': 2, 'c': 2})
+c.update(['a', 'c'])    # c is now Counter({'a': 4, 'b': 2, 'c': 3})
+c.update({'a': 5})      # c is now Counter({'a': 9, 'b': 2, 'c': 3})
+c.most_common(2)        # Returns [('a', 9), ('c', 3)] (ordered with most common first);
+                        # if no arg, all items are returned
+
+# Deque (double-ended queue)
+import collections
+q = collections.deque((3, 'hi'))    # Assigns a deque (a bit like list but with faster
+                        # adding/removing of items at both ends and slower indexing in the
+                        # middle)
+type(q)                 # Returns type collections.deque
+isinstance(q, collections.deque)    # Returns True
+q.append('right')       # q is now deque([3, 'hi', 'right'])
+q.appendleft('left')    # q is now deque(['left', 3, 'hi', 'right'])
+if q:                   # If q is not empty...
+    q.pop()             # Returns 'right'; q is now deque(['left', 3, 'hi'])
+q.popleft()             # Returns 'left'; q is now deque([3, 'hi'])
+q.extend([4,5])         # q is now deque([3, 'hi', 4, 5])
+q.extendleft([2,1])     # q is now deque([1, 2, 3, 'hi', 4, 5])
+
+ +

Container Object Attributes

+ +The following is a list of attributes (properties and methods) provided by instances of the +container types +str, unicode, list, tuple, (types produced by) collections.namedtuple, bytearray, memoryview, +xrange, set, frozenset, dict, collections.defaultdict, collections.OrderedDict, collections.Counter, +collections.deque. +(Some general object attributes and low-level attributes are omitted from this list). +

+ +Show attributes below: + +

+o.__add__(o2)           # Special method implementing o + o2 (concatenation); 'hi' + 'ho'
+                        # returns 'hiho'; for Counter the counts of equal keys are added;
+                        # applies to str,unicode,list,tuple,namedtuple,bytearray,Counter
+o.__alloc__()           # Returns number of bytes allocated to o;
+                        # bytearray('hi').__alloc__() returns 3;
+                        # applies to bytearray
+o.__and__(o2)           # Implements o & o2 (intersection); {1,'a',3} & {'a',3,4} returns
+                        # {'a',3}; for Counter the intersection applies to the keys and the
+                        # smallest count is chosen for equal keys;
+                        # applies to set,frozenset,Counter
+o.__cmp__(o2)           # Implements cmp(o, o2) (3-way comparison);
+                        # cmp({1:4},{2:4}) returns -1;
+                        # applies to set,frozenset,dict,defaultdict,OrderedDict,Counter
+o.__contains__(x)       # Implements x in o (membership test); 'b' in 'abc' returns True;
+                        # applies to str,unicode,list,tuple,namedtuple,bytearray,set,
+                        # frozenset,dict,defaultdict,OrderedDict,Counter
+o.__copy__()            # Implements copy.copy(o) (shallow copy);
+                        # applies to defaultdict,deque
+o.__delitem__(x)        # Implements del o[x] (item deletion); if o = [4,5] then del o[0]
+                        # makes o [5]; o.__delitem__(slice(x,y,z)) implements del o[x:y:z];
+                        # applies to list,bytearray,memoryview,dict,defaultdict,
+                        # OrderedDict,Counter,deque
+o.__delslice__(x,y)     # Implements del o[x:y] (obsolete, use __delitem__);
+                        # applies to list
+o.__eq__(o2)            # Implements o == o2;
+                        # applies to str,unicode,list,tuple,namedtuple,bytearray,
+                        # memoryview,set,frozenset,dict,defaultdict,OrderedDict,Counter,
+                        # deque
+o.__ge__(o2)            # Implements o >= o2;
+                        # applies to str,unicode,list,tuple,namedtuple,bytearray,
+                        # memoryview,set,frozenset,dict,defaultdict,OrderedDict,Counter,
+                        # deque
+o.__getitem__(x)        # Implements o[x];
+                        # o.__getitem__(slice(x,y,z)) implements o[x:y:z];
+                        # applies to str,unicode,list,tuple,namedtuple,bytearray,
+                        # memoryview,xrange,dict,defaultdict,OrderedDict,Counter,deque
+o.__getnewargs__()      # TBD (pickle protocol)
+                        # applies to str,unicode,tuple,namedtuple
+o.__getslice__(x,y)     # Implements o[x:y] (obsolete, use __getitem__);
+                        # applies to str,unicode,list,tuple,namedtuple
+o.__getstate__()        # TBD (pickle protocol)
+                        # applies to namedtuple
+o.__gt__(o2)            # Implements o > o2;
+                        # applies to str,unicode,list,tuple,namedtuple,bytearray,
+                        # memoryview,set,frozenset,dict,defaultdict,OrderedDict,Counter,
+                        # deque
+o.__iadd__(o2)          # Implements o += o2 (in-place concatenation); if o = [1,2] then
+                        # o += [3,4] makes o [1,2,3,4];
+                        # applies to list,bytearray,deque
+o.__iand__(o2)          # Implements o &= o2 (in-place intersection);
+                        # applies to set
+o.__imul__(x)           # Implements o *= x (in-place repetition); if o = [1,2] then o *= 3
+                        # makes o [1,2,1,2,1,2];
+                        # applies to list,bytearray
+o.__ior__(o2)           # Implements o |= o2 (in-place union);
+                        # applies to set
+o.__isub__(o2)          # Implements o -= o2 (in-place difference);
+                        # applies to set
+o.__iter__()            # Returns an iterator for iterable o;
+                        # applies to list,tuple,namedtuple,bytearray,xrange,set,frozenset,
+                        # dict,defaultdict,OrderedDict,Counter,deque
+o.__ixor__(o2)          # Implements o ^= o2 (in-place symmetric difference);
+                        # applies to set
+o.__le__(o2)            # Implements o <= o2;
+                        # applies to str,unicode,list,tuple,namedtuple,bytearray,
+                        # memoryview,set,frozenset,dict,defaultdict,OrderedDict,Counter,
+                        # deque
+o.__len__()             # Implements len(o) (item count); len([5,6]) returns 2;
+                        # applies to str,unicode,list,tuple,namedtuple,bytearray,
+                        # memoryview,xrange,set,frozenset,dict,defaultdict,OrderedDict,
+                        # Counter,deque
+o.__lt__(o2)            # Implements o < o2;
+                        # applies to str,unicode,list,tuple,namedtuple,bytearray,
+                        # memoryview,set,frozenset,dict,defaultdict,OrderedDict,Counter,
+                        # deque
+o.__missing__(x)        # Implements o[x] if x is not one of o's keys; returns the default
+                        # value for a missing key;
+                        # applies to defaultdict,Counter
+o.__mod__(x)            # Implements o % x (formatting); '%-3s%03u' % ('hi', 9) returns
+                        # 'hi 009';
+                        # applies to str,unicode
+o.__mul__(x)            # Implements o * x (repetition); [1,2] * 3 returns [1,2,1,2,1,2];
+                        # applies to str,unicode,list,tuple,namedtuple,bytearray
+o.__ne__(o2)            # Implements o != o2;
+                        # applies to str,unicode,list,tuple,namedtuple,bytearray,
+                        # memoryview,set,frozenset,dict,defaultdict,OrderedDict,Counter,
+                        # deque
+o.__or__(o2)            # Implements o | o2 (union); {1,'a',3} | {'a',3,4} returns
+                        # {1,'a',3,4}; for Counter the union applies to the keys and the
+                        # largest count is chosen for equal keys;
+                        # applies to set,frozenset,Counter
+o.__rand__(o2)          # Implements o2 & o (reverse intersection);
+                        # applies to set,frozenset
+o.__reversed__()        # Implements reversed(o); returns a reverse order iterator for o;
+                        # applies to list,xrange,OrderedDict,deque
+o.__rmod__(o2)          # Implements o2 % o (reverse formatting);
+                        # applies to str,unicode
+o.__rmul__(x)           # Implements x * o (reverse repetition); 3 * [1,2] returns
+                        # [1,2,1,2,1,2];
+                        # applies to str,unicode,list,tuple,namedtuple,bytearray
+o.__ror__(o2)           # Implements o2 | o (reverse union);
+                        # applies to set,frozenset
+o.__rsub__(o2)          # Implements o2 - o (reverse difference);
+                        # applies to set,frozenset
+o.__rxor__(o2)          # Implements o2 ^ o (reverse symmetric difference);
+                        # applies to set,frozenset
+o.__setitem__(x, v)     # Implements o[x] = v;
+                        # o.__setitem__(slice(x,y,z), v) implements o[x:y:z] = v;
+                        # applies to list,bytearray,memoryview,dict,defaultdict,
+                        # OrderedDict,Counter,deque
+o.__setslice__(x, y, v) # Implements o[x:y] = v (obsolete, use __setitem__);
+                        # applies to list
+o.__sub__(o2)           # Implements o - o2 (difference); {1,'a',3} - {'a',3,4} returns {1};
+                        # for Counter the counts of equal keys are subtracted and only keys
+                        # with positive counts are retained;
+                        # applies to set,frozenset,Counter
+o.__xor__(o2)           # Implements o ^ o2 (symmetric difference); {1,'a',3} ^ {'a',3,4}
+                        # returns {1,4};
+                        # applies to set,frozenset
+
+ +
+o._asdict()             # TBD
+                        # applies to namedtuple
+o._fields               # TBD
+                        # applies to namedtuple
+o._formatter_field_name_split() # TBD
+                                # applies to str,unicode
+o._formatter_parser()   # TBD
+                        # applies to str,unicode
+o._make()               # TBD
+                        # applies to namedtuple
+o._replace()            # TBD
+                        # applies to namedtuple
+
+ +
+o.add(x)                # Puts x into o; if o = {3} then o.add(5) makes o {3,5};
+                        # applies to set
+o.append(x)             # Inserts x at end of o; if o = [3] then o.append(5) makes o [3,5];
+                        # applies to list,bytearray,deque
+o.appendleft(x)         # Inserts x at start of o; if o = deque([3]) then o.appendleft(5)
+                        # makes o deque([5, 3]);
+                        # applies to deque
+o.capitalize()          # Returns o with first character capitalized; 'hi ho'.capitalize()
+                        # returns 'Hi ho';
+                        # applies to str,unicode,bytearray
+o.center(w,c)           # Returns o centered in a string of length w filled with c (space
+                        # if no c); returns o if len(o) >= w;
+                        # 'hi'.center(5,'*') returns '**hi*';
+                        # applies to str,unicode,bytearray
+o.clear()               # Makes o empty; if o = {3:9,5:25} then o.clear() makes o {};
+                        # applies to set,dict,defaultdict,OrderedDict,Counter,deque
+o.copy()                # Returns a shallow copy of o (similar to copy.copy(o) but doesn't
+                        # call o.__copy__()); if o = {4:[5]} then o.copy() returns a new
+                        # {4:[5]} referencing the same list [5] as o;
+                        # applies to set,frozenset,dict,defaultdict,OrderedDict,Counter
+o.count(x,a,b)          # Returns count of non-overlapping occurrences of x in o[a:b];
+                        # a,b are optional; 'hohohoho'.count('hoho') returns 2;
+                        # applies to str,unicode,list,tuple,namedtuple,bytearray,deque
+o.decode(enc,err)       # Returns string equal to o decoded using encoding enc
+                        # (default 'ascii') and error scheme err (default 'strict')
+                        # 'A\xc7\xbf'.decode('utf-8') returns u'A\u01ff';
+                        # 'A\xc0'.decode('utf-8') raises UnicodeDecodeError;
+                        # 'A\xc0'.decode('utf-8','ignore') returns u'A';
+                        # 'A\xc0'.decode('utf-8','replace') returns u'A\ufffd';
+                        # applies to str,unicode,bytearray
+o.default_factory       # TBD
+                        # applies to defaultdict
+o.difference(o2,...)        # Same as o - set(o2) - ... (doesn't call o.__sub__());
+                            # applies to set,frozenset
+o.difference_update(o2,...) # Same as o -= set(o2) | ... (doesn't call o.__isub__());
+                            # applies to set
+o.discard(x)            # Removes item x from o; does nothing if x is not in o;
+                        # if o = {3,5} then o.discard(5) makes o {3};
+                        # applies to set
+o.elements()            # TBD
+                        # applies to Counter
+o.encode(enc,err)       # Returns o encoded using encoding enc (default 'ascii') and error
+                        # scheme err (default 'strict');
+                        # u'A\u01ff'.encode('utf-8') returns 'A\xc7\xbf';
+                        # u'A\u0080'.encode() raises UnicodeEncodeError;
+                        # u'A\u0080'.encode('ascii','ignore') returns 'A';
+                        # u'A\u0080'.encode('ascii','replace') returns 'A?';
+                        # u'A\u0080'.encode('ascii','xmlcharrefreplace') returns 'A&#128;';
+                        # u'A\u0080'.encode('ascii','backslashreplace') returns 'A\\x80';
+                        # applies to str,unicode
+o.endswith(x,a,b)       # Returns True if o[a:b] ends with x (or with an item in tuple x);
+                        # 'abc'.endswith(('bc','z')) returns True;
+                        # applies to str,unicode,bytearray
+o.expandtabs(n)         # Returns a copy of o with tab characters replaced by up to n
+                        # spaces (enough spaces to reach the next tab column);
+                        # '\ta\tbc\td'.expandtabs(3) returns '   a  bc d';
+                        # applies to str,unicode,bytearray
+o.extend(o2)            # Same as o += o2 (doesn't call o.__iadd__());
+                        # applies to list,bytearray,deque
+o.extendleft()          # TBD
+                        # applies to deque
+o.find(o2,a,b)          # Returns index of first occurrence of substring o2 in o[a:b] (a=0,
+                        # b=-1 if not given), or -1 if none found;
+                        # 'abab'.find('ab') returns 0; 'abab'.find('ab',1,3) returns -1;
+                        # applies to str,unicode,bytearray
+o.format(...)           # Returns a string representing the arguments formatted according
+                        # to the directives in o; See string operations;
+                        # applies to str,unicode,memoryview
+o.fromhex(s)            # Class method; returns object of same class as o containing bytes
+                        # corresponding to pairs of hex digits in string s;
+                        # bytearray.fromhex('4142 43 0a') returns bytearray(b'ABC\n');
+                        # applies to bytearray
+o.fromkeys(o2,x)        # Class method; returns object of same class as o containing all
+                        # items of sequence o2 as keys with all values equal to x (default
+                        # None); dict.fromkeys(('a','b'), 5) returns {'a':5, 'b':5};
+                        # applies to dict,defaultdict,OrderedDict
+o.get()                 # TBD
+                        # applies to dict,defaultdict,OrderedDict,Counter
+o.has_key()             # TBD
+                        # applies to dict,defaultdict,OrderedDict,Counter
+o.index(x,a,b)          # Returns index of first occurrence of item x in o[a:b] (a=0, b=-1
+                        # if not given); raises ValueError if x is not in o[a:b];
+                        # for str,unicode,bytearray: x may be a substring of o;
+                        # [4,5,4].index(4) returns 0; 'abab'.index('ab',1) returns 2;
+                        # applies to str,unicode,list,tuple,namedtuple,bytearray
+o.insert(i,x)           # Inserts item x in o at index i; same as o[i:i] = [x];
+                        # if o = [4,5,6] then o.insert(2,'a') makes o [4,5,'a',6];
+                        # applies to list,bytearray
+o.intersection(o2,...)          # Same as o & set(o2) & ... (doesn't call o.__and__());
+                                # applies to set,frozenset
+o.intersection_update(o2,...)   # Same as o &= set(o2) & ... (doesn't call o.__iand__());
+                                # applies to set
+o.isalnum()             # Returns True if o is not empty and contains only alphanumeric
+                        # characters (alphabetic or numeric characters);
+                        # applies to str,unicode,bytearray
+o.isalpha()             # Returns True if o is not empty and contains only alphabetic
+                        # characters;
+                        # applies to str,unicode,bytearray
+o.isdecimal()           # Returns True if o is not empty and contains only decimal
+                        # characters (a subset of digits (the official doc is wrong));
+                        # for characters '2๒': u'2\u0e52'.isdecimal() returns True;
+                        # for character '²':    u'\u00b2'.isdecimal() returns False;
+                        # for character '½':    u'\u00bd'.isdecimal() returns False;
+                        # applies to unicode
+o.isdigit()             # Returns True if o is not empty and contains only digits
+                        # (a subset of numeric characters);
+                        # for characters '2๒': u'2\u0e52'.isdigit() returns True;
+                        # for character '²':    u'\u00b2'.isdigit() returns True;
+                        # for character '½':    u'\u00bd'.isdigit() returns False;
+                        # applies to str,unicode,bytearray
+o.isdisjoint(o2)        # Returns True if o and o2 have no common items;
+                        # applies to set,frozenset
+o.islower()             # Returns True if o contains at least 1 cased character and all
+                        # cased characters are lowercase; 'ver2.0'.islower() returns True;
+                        # applies to str,unicode,bytearray
+o.isnumeric()           # Returns True if o is not empty and contains only numeric
+                        # characters;
+                        # for characters '2๒': u'2\u0e52'.isnumeric() returns True;
+                        # for character '²':    u'\u00b2'.isnumeric() returns True;
+                        # for character '½':    u'\u00bd'.isnumeric() returns True;
+                        # applies to unicode
+o.isspace()             # Returns True if o is not empty and contains only whitespace
+                        # characters; ' \t\n\r\f\v'.isspace() returns True;
+                        # applies to str,unicode,bytearray
+o.issubset(o2)          # Same as o <= o2 (doesn't call o.__le__());
+                        # applies to set,frozenset
+o.issuperset(o2)        # Same as o >= o2 (doesn't call o.__ge__());
+                        # applies to set,frozenset
+o.istitle()             # Returns True if o contains at least 1 uppercase character, no
+                        # uppercase character follows a cased character, and any lowercase
+                        # character follows a cased character;
+                        # '2B|Not 2B'.istitle() returns True;
+                        # applies to str,unicode,bytearray
+o.isupper()             # Returns True if o contains at least 1 cased character and all
+                        # cased characters are uppercase; 'VER2.0'.isupper() returns True;
+                        # applies to str,unicode,bytearray
+o.items()               # TBD
+                        # applies to dict,defaultdict,OrderedDict,Counter
+o.itemsize              # TBD
+                        # applies to memoryview
+o.iteritems()           # TBD
+                        # applies to dict,defaultdict,OrderedDict,Counter
+o.iterkeys()            # TBD
+                        # applies to dict,defaultdict,OrderedDict,Counter
+o.itervalues()          # TBD
+                        # applies to dict,defaultdict,OrderedDict,Counter
+o.join(o2)              # Returns the string obtained by concatenating all items of o2
+                        # using o as separator; '/'.join('abc') returns 'a/b/c';
+                        # '=='.join(['x','42']) returns 'x==42';
+                        # applies to str,unicode,bytearray
+o.keys()                # TBD
+                        # applies to dict,defaultdict,OrderedDict,Counter
+o.ljust(w,c)            # Returns o left-justified in a string of length w filled with c
+                        # (space if no c); returns o if len(o) >= w;
+                        # 'hi'.ljust(5,'*') returns 'hi***';
+                        # applies to str,unicode,bytearray
+o.lower()               # Returns a copy of o with all uppercase characters converted to
+                        # lowercase; '2B|Not 2B'.lower() returns '2b|not 2b';
+                        # applies to str,unicode,bytearray
+o.lstrip(s)             # Returns a copy of o with first characters removed if present in
+                        # string s (whitespace if no s); 'abcd'.lstrip('dba') returns 'cd';
+                        # applies to str,unicode,bytearray
+o.maxlen                # TBD
+                        # applies to deque
+o.most_common()         # TBD
+                        # applies to Counter
+o.ndim                  # TBD
+                        # applies to memoryview
+o.partition(o2)         # Returns (o[:i],o[i],o[i+1:]) where i is index of first occurrence
+                        # of o2 in o, or (o[:],type(o)(),type(o)()) if o2 is not found in o;
+                        # 'abba'.partition('b') returns ('a','b','ba');
+                        # u'abba'.partition(u'x') returns (u'abba',u'',u'');
+                        # applies to str,unicode,bytearray
+o.pop(i)                # Removes and returns item o[i] (o[-1] if no i);
+                        # for set: removes and returns arbitrary item (no i allowed);
+                        # raises IndexError (list) or KeyError (set, dict) if no item;
+                        # applies to list,bytearray,set,dict,defaultdict,OrderedDict,
+                        # Counter,deque
+o.popitem()             # Removes and returns arbitrary (key, o[key]) pair; raises KeyError
+                        # if o is empty;
+                        # applies to dict,defaultdict,OrderedDict,Counter
+o.popleft()             # TBD
+                        # applies to deque
+o.readonly              # TBD
+                        # applies to memoryview
+o.remove(x)             # Removes item x from o; raises ValueError (KeyError for set) if x
+                        # is not in o; if o = [3,5] then o.remove(5) makes o [3];
+                        # applies to list,bytearray,set,deque
+o.replace(s1,s2,n)      # Returns a copy of o with first n (or all if no n) occurrences of
+                        # s1 replaced with s2; 'boohoo'.replace('oo','*') returns 'b*h*';
+                        # applies to str,unicode,bytearray
+o.reverse()             # Reverses the items of o; same as o[::-1] = o;
+                        # if o = [4,5,6] then o.reverse() makes o [6,5,4];
+                        # applies to list,bytearray,deque
+o.rfind(o2,a,b)         # Same as o.find(), except last occurrence is chosen;
+                        # applies to str,unicode,bytearray
+o.rindex(x,a,b)         # Same as o.index(), except last occurrence is chosen;
+                        # applies to str,unicode,bytearray
+o.rjust(w,c)            # Returns o right-justified in a string of length w filled with c
+                        # (space if no c); returns o if len(o) >= w;
+                        # 'hi'.rjust(5,'*') returns '***hi';
+                        # applies to str,unicode,bytearray
+o.rotate()              # TBD
+                        # applies to deque
+o.rpartition(o2)        # Returns (o[:i],o[i],o[i+1:]) where i is index of last occurrence
+                        # of o2 in o, or (type(o)(),type(o)(),o[:]) if o2 is not found in o;
+                        # 'abba'.rpartition('b') returns ('ab','b','a');
+                        # u'abba'.rpartition(u'x') returns (u'',u'',u'ab');
+                        # applies to str,unicode,bytearray
+o.rsplit()              # TBD
+                        # applies to str,unicode,bytearray
+o.rstrip(s)             # Returns a copy of o with last characters removed if present in
+                        # string s (whitespace if no s); 'abcd'.rstrip('cda') returns 'ab';
+                        # applies to str,unicode,bytearray
+o.setdefault()          # TBD
+                        # applies to dict,defaultdict,OrderedDict,Counter
+o.shape                 # TBD
+                        # applies to memoryview
+o.sort(cf,kf,r)         # Sorts the items of o using comparison and key functions cf and kf
+                        # (cf works like cmp(x,y) and is cmp(x,y) if not given, kf extracts
+                        # a key for cf from each item and is lambda x:x if not given);
+                        # the sort is reversed if r is True (r is False if not given);
+                        # sort(None,kf,r) is usually faster than an equivalent sort(cf);
+                        # if o = [4,5,10] then o.sort(None,None,True) makes o [10,5,4];
+                        # applies to list
+o.split()               # TBD
+                        # applies to str,unicode,bytearray
+o.splitlines()          # TBD
+                        # applies to str,unicode,bytearray
+o.startswith(x,a,b)     # Returns True if o[a:b] starts with x (or with an item in tuple x);
+                        # 'abc'.startswith(('ab','z')) returns True;
+                        # applies to str,unicode,bytearray
+o.strides               # TBD
+                        # applies to memoryview
+o.strip(s)              # Returns a copy of o with characters removed from both ends if
+                        # present in string s (whitespace if no s);
+                        # '0+a+b!'.strip('!+0') returns 'a+b';
+                        # applies to str,unicode,bytearray
+o.suboffsets            # TBD
+                        # applies to memoryview
+o.subtract()            # TBD
+                        # applies to Counter
+o.swapcase()            # TBD
+                        # applies to str,unicode,bytearray
+o.symmetric_difference(o2)          # Same as o ^ o2 (doesn't call o.__xor__());
+                                    # applies to set,frozenset
+o.symmetric_difference_update(o2)   # Same as o ^= o2 (doesn't call o.__ixor__());
+                                    # applies to set
+o.title()               # TBD
+                        # applies to str,unicode,bytearray
+o.tobytes()             # TBD
+                        # applies to memoryview
+o.tolist()              # TBD
+                        # applies to memoryview
+o.translate()           # TBD
+                        # applies to str,unicode,bytearray
+o.union(o2,...)         # Same as o | set(o2) | ... (doesn't call o.__or__());
+                        # applies to set,frozenset
+o.update(o2,...)        # Updates o with items from o2, ...;
+                        # for set: same as o |= set(o2) | ... (doesn't call o.__ior__());
+                        # applies to set,dict,defaultdict,OrderedDict,Counter
+o.upper()               # Returns a copy of o with all lowercase characters converted to
+                        # uppercase; '2B|Not 2B'.upper() returns '2B|NOT 2B';
+                        # applies to str,unicode,bytearray
+o.values()              # TBD
+                        # applies to dict,defaultdict,OrderedDict,Counter
+o.viewitems()           # TBD
+                        # applies to dict,defaultdict,OrderedDict,Counter
+o.viewkeys()            # TBD
+                        # applies to dict,defaultdict,OrderedDict,Counter
+o.viewvalues()          # TBD
+                        # applies to dict,defaultdict,OrderedDict,Counter
+o.zfill()               # TBD
+                        # applies to str,unicode,bytearray
+
+ +

Iterator Types

+ +
+# Iterator and iterable type detection
+import collections
+isinstance(o, collections.Iterator)  # Returns True if o is an iterator object
+isinstance(o, collections.Iterable)  # Returns True if o is an iterable object (e.g.
+                        # container or iterator), in which case iter(o) returns an iterator
+                        # for o
+
+# Iterator types
+si = iter('hello')      # Assigns a string iterator
+type(si)                # Returns type with name 'iterator'
+next(si)                # Returns 'h', i.e. next item; raises StopIteration exception
+                        # when no more items; iterators normally can't be restarted (one
+                        # exception is a file f which can be restarted with f.seek(0))
+next(si, '.')           # Returns 'e'; returns '.' when no more items
+
+li = iter([3, 'hi'])    # Assigns a list iterator
+type(li)                # Returns type with name 'listiterator'
+next(li)                # Returns 3
+
+ti = iter((3, 'hi'))    # Assigns a tuple iterator
+type(ti)                # Returns type with name 'tupleiterator'
+next(ti)                # Returns 3
+
+seti = iter({3, 'hi'})  # Assigns a set iterator (iteration sequence is unpredictable)
+type(seti)              # Returns type with name 'setiterator'
+next(seti)              # Returns 3
+
+d = {'a':10, 'b':5}     # Assigns a dictionary (iteration sequence is unpredictable)
+dki = iter(d)           # Assigns a dictionary key iterator (same as d.iterkeys())
+type(dki)               # Returns type with name 'dictionary-keyiterator'
+next(dki)               # Returns 'a'
+dvi = d.itervalues()    # Assigns a dictionary value iterator
+type(dvi)               # Returns type with name 'dictionary-valueiterator'
+next(dvi)               # Returns 10
+dii = d.iteritems()     # Assigns a dictionary item iterator
+type(dii)               # Returns type with name 'dictionary-itemiterator'
+next(dii)               # Returns ('a', 10)
+
+bi = iter(bytearray([65, 0])) # Assigns a bytearray iterator
+type(bi)                # Returns type with name 'bytearray_iterator'
+next(bi)                # Returns 65
+
+xi = iter(xrange(5))    # Assigns an xrange iterator
+type(xi)                # Returns type with name 'rangeiterator'
+next(xi)                # Returns 0
+
+from random import random   # Imports function random from module random
+ci = iter(random, 0.1)  # Assigns a callable iterator that calls function random until that
+                        # function returns 0.1 (very unlikely); note that iter() with 2
+                        # args is quite different from iter() with 1 arg
+type(ci)                # Returns class with name 'callable-iterator'
+next(ci)                # Returns a random float
+
+se = enumerate('hello') # Assigns an enumerate object (iterator) for a string
+type(se)                # Returns type enumerate
+isinstance(se, enumerate)   # Returns True
+next(se)                # Returns (0, 'h'); first item in this tuple is count
+next(se)                # Returns (1, 'e')
+xe = enumerate(xi, 100) # Assigns an enumerate object for an xrange iterator (see above)
+                        # with count starting at 100; xi already iterated once above, so
+                        # first xe iteration triggers second xi iteration
+next(xe)                # Returns (100, 1)
+next(xe)                # Returns (101, 2)
+next(xi)                # Returns 3; xe uses xi to iterate, so xi is also at item 3
+
+ +Generator objects (see generator expressions +and generator functions) +and files are also iterators. + +

More Types

+ +"Everything is an object", so see these other object types: + + +

Control Flow Manipulation

+ +

Conditional Execution

+ +
+# 'If' statement
+if x == 3:
+    x = y               # Lines at same nesting level must have same indentation
+    if not z:           # (see compound statement format)
+        y += 1
+elif y != 4:
+    pass                # Does nothing (placeholder for empty statement list)
+else:
+    y = x
+    # Single-line 'if'
+    if z: x = 1; y = 2  # Semi-colon binds tighter than colon, so doesn't end the 'if'
+    else: y = 1; x = 2
+
+ +See also conditional expressions. + +

Loops

+ +
+# While loop
+while x < 10:
+    x += 1
+    if x == 5:
+        continue        # Skips rest of loop body and goes back to testing loop condition
+    print x
+    if x == y:
+        break           # Exits loop and skips 'else' part
+else:                   # Optional; does something if loop condition tested false,
+                        # i.e. when no more iterations and no break
+    print 'no break'
+
+# For loop
+for x in alist:         # x becomes each item of alist in turn; alist is evaluated once
+                        # (Note: alist can be any iterable type or iterator)
+    print x
+    for i in range(x):  # Range returns a list of integers from 0 through x - 1
+        print i
+else:                   # Optional; do something when no more iterations and no break
+    pass
+
+ +

Exception Handling

+ +
+# Try (with all parts)
+try:
+    x = 1 / 0           # Raises exception which triggers 1st 'except' & 'finally'
+except ZeroDivisionError as e:  # Executed on specific exception in try part
+    print 'Oops:', e    # Prints 'Oops: integer division or modulo by zero'
+except:                 # Executed on any (not already handled) exception in try part
+    print 'Bad!'
+else:                   # Optional; executed only if no exception in try part; same as
+                        # putting code at end of try part, but exceptions are not handled
+    print 'All OK'
+finally:                # Optional; always executed as last step, even on unhandled
+                        # exception or return/break/continue (in try/except/else parts)
+    print 'Clean up'
+
+# Try (with finally only)
+try:
+    raise RuntimeError  # Raises exception which is not handled here
+finally:                # but finally part is executed
+    print 'Clean up'
+
+ +

Script Termination

+ +
+import sys              # Imports the sys module
+sys.exit()              # Raises a SystemExit exception which terminates the script with
+                        # exit code 0 (usually considered to mean success) -
+                        # unless the exception is caught by a try statement
+sys.exit(2)             # Same as above, but uses the specified exit code
+sys.exit('Oops!')       # Same as above, but prints the specified string and uses
+                        # exit code 1 (usually considered to mean failure)
+sys.exit(obj)           # Same as above, but converts the specified object to a string,
+                        # prints it, and uses exit code 1, unless obj is None, in which
+                        # case nothing is printed and exit code is 0
+exit()                  # Not recommended for use in scripts; intended for use in the
+                        # interactive interpreter where it works like sys.exit()
+
+ +

Input/Output

+ +

Script Arguments

+ +
+import sys              # Imports the sys module
+sys.argv                # Returns a list containing the script name and command line args
+print sys.argv[0]       # Prints script name (possibly full path)
+if len(sys.argv) > 1:   # If there are any command line arguments, then ...
+    print sys.argv[1]   # ... print first one
+
+ +

Standard In/Out/Error

+ +
+# Stdout
+x = 10
+d = {'a': 4, 'b': 5}
+print 'd =', d          # Prints 'd = {'a': 4, 'b': 5}' + newline to stdout;
+                        # args are separated by a space
+print 'x =', x,         # Prints 'x = 10' to stdout; trailing comma prevents newline
+print '(decimal)'       # Prints '(decimal)', so whole line is 'x = 10 (decimal)'
+
+# Stderr
+import sys                          # Imports sys module
+print >> sys.stderr, 'x =', x,      # Prints 'x = 10' to stderr; trailing ',' prevents
+                                    # newline
+print >> sys.stderr, '(decimal)'    # Prints '(decimal)'; whole line: 'x = 10 (decimal)'
+sys.stderr.write('x = %d' % x)      # Prints 'x = 10' to stderr (never automatic newline)
+sys.stderr.write(' (decimal)\n')    # Prints ' (decimal)' + newline;
+                                    # whole line printed to stderr: 'x = 10 (decimal)'
+a1 = ['hi\n', 'ho\n']               # List of strings incl. newlines
+sys.stderr.writelines(a1)           # Prints 'hi' + newline + 'ho' + newline
+
+# Stdin
+q = raw_input('Q: ')    # Prints 'Q: ' to stdout (without newline), then reads a line from
+                        # stdin as a string, strips the newline, and assigns it to q
+s = sys.stdin.read()    # Reads stdin until end of file and assigns the whole thing
+                        # (incl. newlines) as a string to s
+s = sys.stdin.readline()    # Reads one line from stdin as string incl. newline;
+                            # returns empty string if no more lines
+a = sys.stdin.readlines()   # Reads all lines from stdin as list of strings incl. newlines
+
+ +

Files

+ +
+# Creating/truncating + writing file, and misc. file methods
+fname = 'file.txt'
+f = open(fname, 'w')        # Creates/truncates and opens file for writing from position 0
+                            # (use mode 'wb' for binary files - no newline conversion)
+type(f)                     # Returns type file
+isinstance(f, file)         # Returns True
+f.tell()                    # Returns 0 (position of file pointer in bytes)
+x = 10
+print >> f, 'x =', x,       # Writes 'x = 10' to file; trailing ',' prevents newline
+print >> f, '(decimal)'     # Writes '(decimal)'; whole line: 'x = 10 (decimal)'
+f.write('x = %d' % x)       # Writes 'x = 10' to file (never automatic newline)
+f.write(' (decimal)\n')     # Writes ' (decimal)' + newline; whole line: 'x = 10 (decimal)'
+a1 = ['hi\n', 'ho\n']       # List of strings incl. newlines
+f.writelines(a1)            # Writes 'hi\n' + 'ho\n' to file
+f.tell()                    # Returns 44 (position of file pointer in bytes (Windows))
+f.close()                   # Closes file
+
+# Reading file, and misc. file methods
+f = open(fname, 'r')        # Opens existing file for reading from pos 0 ('r' is optional)
+                            # (use mode 'rb' for binary files - no newline conversion)
+f.tell()                    # Returns 0 (position of file pointer in bytes)
+s = f.read()                # Reads entire file as string
+f.tell()                    # Returns 44 (position of file pointer in bytes (Windows))
+f.seek(-10, 2)              # Moves file pointer 10 bytes back from end of file
+f.tell()                    # Returns 34 (position of file pointer in bytes (Windows))
+f.seek(-10, 1)              # Moves file pointer 10 bytes back from current position
+f.tell()                    # Returns 24 (position of file pointer in bytes (Windows))
+f.seek(10)                  # Moves file pointer 10 bytes forward from start of file
+f.tell()                    # Returns 10 (position of file pointer in bytes (Windows))
+f.seek(0)                   # Moves file pointer back to start of file
+f.tell()                    # Returns 0 (position of file pointer in bytes)
+s = f.readline()            # Reads next line from file as string incl. newline;
+                            # returns empty string if no more lines
+f.tell()                    # Returns 18 (position of file pointer in bytes (Windows))
+a = f.readlines()           # Reads all remaining lines from file as list of strings
+                            # incl. newlines
+f.tell()                    # Returns 44 (position of file pointer in bytes (Windows))
+f.seek(0)                   # Moves file pointer back to start of file
+s = next(f)                 # Same as f.readline() but raises StopIteration at end of file,
+                            # and ValueError if mixed with file read methods without an
+                            # intervening call to f.seek()
+                            # (files are iterators with additional control via f.seek())
+for s in f: print s,        # Iterates through remaining lines in file and prints each one
+f.close()
+
+# 'With' statement (good practice)
+with open(fname) as f:      # 'with' ensures that file is closed when the 'with' suite of
+    s = f.read()            # statements ends or raises an exception
+
+# Appending to file (creating it if needed)
+f = open(fname, 'a')        # (Creates and) opens file for appending (writing at end)
+                            # (use mode 'ab' for binary files - no newline conversion)
+f.tell()                    # Returns 0 (position of file pointer - irrelevant for mode 'a')
+print >> f, 'hum'           # Appends 'hum\n' to end of file
+f.tell()                    # Returns 49 (position of file pointer in bytes (Windows))
+f.close()
+
+# Creating/truncating + writing & reading file
+f = open(fname, 'w+')       # Creates/truncates and opens file for writing and reading
+                            # (use mode 'w+b' for binary files - no newline conversion)
+s = f.read()                # Reads entire file as string: '' because file was truncated
+f.seek(0, 1)                # Doesn't move file pointer (but f.seek is necessary on
+                            # Windows when switching from read to write, else exception)
+print >> f, 'hi'            # Writes 'hi\n' to file
+f.tell()                    # Returns 4 (position of file pointer in bytes (Windows))
+f.close()
+
+# Reading & writing file
+f = open(fname, 'r+')       # Opens existing file for reading and writing (no truncating)
+                            # (use mode 'r+b' for binary files - no newline conversion)
+s = f.read()                # Reads entire file as string: 'hi\n'
+f.seek(0)                   # Moves file pointer back to start of file
+                            # (see also f.seek(0, 1) comment above)
+print >> f, 'ho'            # Writes 'ho\n' to file - overwriting previous 'hi\n'
+f.tell()                    # Returns 4 (position of file pointer in bytes (Windows))
+f.close()
+
+# Appending to & reading file (creating it if needed)
+f = open(fname, 'a+')       # (Creates and) opens file for appending and reading
+                            # (use mode 'a+b' for binary files - no newline conversion)
+s = f.read()                # Reads entire file as string: 'ho\n'
+f.tell()                    # Returns 4 (position of file pointer in bytes (Windows))
+f.seek(0)                   # Moves file pointer back to start of file
+                            # (see also f.seek(0, 1) comment above)
+print >> f, 'hum'           # Appends 'hum\n' to end of file; file is now 'ho\nhum\n'
+f.tell()                    # Returns 9 (position of file pointer in bytes (Windows))
+f.close()
+
+ +

Expressions

+ +

Operators

+ +All operators are listed below (highlighted) in precedence groups from highest to lowest.
+Within each group, x op y op z == (x op y) op z, unless otherwise noted. + +
+###########################################################################################
+(2 + 3)                 # Returns 5
+(2, 3, 4)               # Returns tuple (2, 3, 4)
+[2, 3, 4]               # Returns list [2, 3, 4]
+{2: 3, 4: 5}            # Returns dict {2: 3, 4: 5}
+{2, 3, 4}               # Returns set {2, 3, 4}
+`2+3,chr(65)`           # Returns string "(5, 'A')" (same as repr((2+3,chr(65))))
+###########################################################################################
+x[2]                    # Returns item/value with index/key 2 from tuple/list/dict/string x
+                        # (or other object with __getitem__() method)
+x[1:6:2]                # Returns tuple/list/string by extracting slice (indices 1,3,5)
+                        # from x (x can't be a dict)
+x[2, 6:0:-2,            # Returns item(s) from x selected by expression list of indices/
+    slice(6,0,-2), ...] # slices/Ellipsis; built-in types (tuple/list/...) allow only 1
+                        # item between [] (not Ellipsis); numpy module allows any
+f(2, 3, 4)              # Returns result of calling function f with given arguments
+x.y                     # Returns member y of object x
+###########################################################################################
+2**3                    # Returns 8 (exponentiation); 4**3**2 == 4**(3**2) == 262144;
+                        # -2**-2 == -(2**(-2)) == -0.25
+###########################################################################################
++1                      # Returns 1
+-1                      # Returns -1
+~1                      # Returns -2 (bitwise NOT)
+###########################################################################################
+2 * 3                   # Returns 6
+'hi' * 3                # Returns 'hihihi' (sequence repetition)
+-5.0 / 2                # Returns -2.5; for int/long: -5 / 2 == -3 (floor div)
+-5.0 // 2               # Returns -3.0 (floor div); for int/long: -5 // 2 == -3
+-5 % 3                  # Returns 1 (modulo); x == floor(x/y)*y + x%y
+'%0*d %X' % (5, 3, 12)  # Returns '00003 C' (string formatting)
+###########################################################################################
+2 + 3                   # Returns 5
+[1,2] + [3,4]           # Returns [1, 2, 3, 4] (sequence concatenation)
+2 - 3                   # Returns -1
+{1,2,3} - {3,4}         # Returns {1,2} (set difference)
+###########################################################################################
+6 << 2                  # Returns 24 (left shift); x << y == x * 2**y; y >= 0
+-6 >> 2                 # Returns -2 (right shift); x >> y == x // 2**y; y >= 0
+###########################################################################################
+6 & 3                   # Returns 2 (bitwise AND)
+{1,2,3} & {3,4}         # Returns {3} (set intersection)
+###########################################################################################
+6 ^ 3                   # Returns 5 (bitwise XOR)
+{1,2,3} ^ {3,4}         # Returns {1,2,4} (set symmetric difference)
+###########################################################################################
+6 | 3                   # Returns 7 (bitwise OR)
+{1,2,3} | {3,4}         # Returns {1,2,3,4} (set union)
+###########################################################################################
+# Comparisons and tests (chainable, i.e. x < y < z means x < y and y < z (but y is
+# evaluated only once)):
+5 in (3, 5, 8)          # Returns True (membership test)
+'a' not in 'hi'         # Returns True (non-membership test)
+[] is []                # Returns False (identity test); these lists are not same object
+                        # (but immutable objects might be identical, e.g. maybe 5 is 5)
+{} is not {}            # Returns True (non-identity test)
+2 < 3                   # Returns True
+'ab' <= 'abc'           # Returns True (lexicographic ASCII/Unicode comparison)
+[2,3] > [2]             # Returns True (lexicographic comparison of corresponding items)
+(3,) >= (2,5)           # Returns True (lexicographic comparison of corresponding items)
+{2,3} > {3}             # Returns True (proper superset)
+2 <> 3                  # Obsolete (use != instead)
+2 != '2'                # Returns True (different types generally compare unequal)
+2L == 2.0               # Returns True (comparison works across different numeric types)
+###########################################################################################
+not 2                   # Returns False (boolean NOT)
+###########################################################################################
+2 and 3                 # Returns 3 (boolean AND, returns 1st arg if False, else 2nd arg;
+                        # 2nd arg is not evaluated if 1st arg is returned)
+###########################################################################################
+0 or 'a'                # Returns 'a' (boolean OR, returns 1st arg if True, else 2nd arg;
+                        # 2nd arg is not evaluated if 1st arg is returned)
+###########################################################################################
+2 if True else 3        # Returns 2 (conditional expression);
+                        # 3rd arg is not evaluated if 1st arg is returned, and vice versa;
+                        # (x if a else y if b else z) == (x if a else (y if b else z))
+###########################################################################################
+lambda x,y: x + y       # Returns anonymous function which will return sum of its 2 args
+                        # (lambda expression)
+###########################################################################################
+#=========================================================================================#
+# The "operators" below this point are not officially operators, but are included here to #
+# show their effective relative precedence in the special contexts where they are valid   #
+#=========================================================================================#
+###########################################################################################
+f(x=2)                  # Passes named argument to function f, i.e. binds f's formal param
+                        # x to object 2 regardless of x's position in f's parameter list
+f(*[4, 'hi'])           # Passes all items of given iterable as args to function f
+                        # (same as f(4, 'hi'))
+f(**{'x': 2, 'y':3})    # Passes key/value pairs of given dictionary as named args to f
+                        # (same as f(x=2, y=3))
+###########################################################################################
+2, 3                    # Returns tuple (2, 3) or expression list (see enclosing operators
+                        # above and multiple assignments below for uses)
+###########################################################################################
+yield 2                 # Returns 2 to caller of next() or send() on generator produced by
+                        # function containing this yield, suspends generator until next
+                        # call to next()/send(), then returns None or send's argument as
+                        # return value of yield expression
+###########################################################################################
+# Normal assignments (chainable, i.e. x = y = z means x = z, then y = z (but z is
+# evaluated only once); note the counterintuitive left-to-right assignment order!):
+x = 2                   # Binds name x to object 2
+o[0] = 2                # Sets item 0 of mutable object o to object 2
+                        # (by calling o.__setitem__(0, 2))
+o.x = 2                 # Sets attribute x of mutable object o to object 2
+                        # (by calling o.__setattr__('x', 2))
+x = o[x] = o[x]         # Chained assignments; same as tmp = o[x]; x = tmp; o[x] = tmp;
+                        # if x and o are initially 0 and [1, 2], they become 1 and [1, 1]
+                        # (o changes due to left-to-right assignment order)
+x, o[0], o.x = 2, 2, 2  # Multiple assignments using expression lists
+# Augmented assignments (not chainable; supports same targets as above except expression
+# lists):
+x += 2                  # Same as x = x + 2, but x is evaluated only once and updated in
+                        # place if possible
+x -= 2                  # x = x - 2 (but see x += 2)
+x *= 2                  # x = x * 2 (but see x += 2)
+x /= 2                  # x = x / 2 (but see x += 2)
+x //= 2                 # x = x // 2 (but see x += 2)
+x %= 2                  # x = x % 2 (but see x += 2)
+x **= 2                 # x = x ** 2 (but see x += 2)
+x >>= 2                 # x = x >> 2 (but see x += 2)
+x <<= 2                 # x = x << 2 (but see x += 2)
+x &= 2                  # x = x & 2 (but see x += 2)
+x ^= 2                  # x = x ^ 2 (but see x += 2)
+x |= 2                  # x = x | 2 (but see x += 2)
+###########################################################################################
+
+ +

String Operations

+ +
+'hello' + ' there\n'    # Returns 'hello there\n' ('\n' is a single newline)
+'-' * 5                 # Returns '-----'
+ord('A')                # Returns 65
+chr(65)                 # Returns 'A'
+ord(u'\u0E01')          # Returns 3585
+unichr(3585)            # Returns unicode string u'\u0E01' (1 character)
+
+ +

String Formatting

+ +There are several ways in which special codes embedded in a string can be replaced at run-time +with objects converted to strings. The various methods are listed below in order of increasing +flexibility (and decreasing simplicity). + +
+# Misc initializations for use below
+nbr, astr = 1, 'thing'
+alist = [nbr, astr]
+adict = {'nbr':nbr, 'astr':astr}
+class Aclass: nbr = nbr; astr = astr
+
+anobj = Aclass()
+
+# Template class formatting; simple approach similar to Unix shell variables
+from string import Template
+Template('$n $x or ${x}y $$').substitute(x=astr, n=nbr)     # Returns '1 thing or thingy $'
+
+# Old C printf-style formatting; many formatting options
+'%(n)03d %(x).4s %(x)sy %%' % {'x':astr, 'n':nbr}           # Returns '001 thin thingy %'
+'%03d %.4s %sy' % (nbr, astr, astr)                         # Returns '001 thin thingy'
+'%0*d %.*s %sy' % (3, nbr, 4, astr, astr)                   # Returns '001 thin thingy'
+'"%-6s" "%6s"' % ('left', 'right')                          # Returns '"left  " " right"'
+'%4.1f %.0e %c' % (9, 500, ord('A'))                        # Returns ' 9.0 5e+02 A'
+'%#x 0x%02X %#o' % (10, 10, 10)                             # Returns '0xa 0x0A 012'
+
+# New str.format() formatting; more formatting and object access options than printf-style
+'{0:03d} {x:.4} {x}y {{'.format(nbr, x=astr)                # Returns '001 thin thingy {'
+'{0:{1}{2}d} {x:.{n}} {x}y'.format(nbr, 0, 3, x=astr, n=4)  # Returns '001 thin thingy'
+'{:03d} {:.4} {}y'.format(nbr, astr, astr)                  # Returns '001 thin thingy'
+'{0[0]:03d} {0[1]:.4} {0[1]}y'.format(alist)                # Returns '001 thin thingy'
+'{0[nbr]:03d} {0[astr]:.4} {0[astr]}y'.format(adict)        # Returns '001 thin thingy'
+'{0.nbr:03d} {0.astr:.4} {0.astr}y'.format(anobj)           # Returns '001 thin thingy'
+'{:#<6} {:#^6} {:#>6}'.format('left', 'mid', 'right')       # Returns 'left## #mid## #right'
+'{:4.1f} {:.0e} {:c}'.format(9, 500, ord('A'))              # Returns ' 9.0 5e+02 A'
+'{:#x} 0x{:02X} {:#o} {:#b}'.format(10, 10, 10, 7)          # Returns '0xa 0x0A 012 0b111'
+'{:,.2f} {:06,d}'.format(8e3, 1234)                         # Returns '8,000.00 01,234'
+
+ +

Conditional Expressions

+ +
+r = x if a else y       # Assigns x to r if a is True (y is not evaluated),
+                        # otherwise assigns y to r (x is not evaluated)
+r = x if a \
+    else y if b \
+    else z              # (Note: backslashes used to break single line)
+
+ +

Regular Expressions

+ +Compiled regular expression objects are highlighted below for clarity, as many +module functions (re.xxx()) have compiled object method equivalents (myobj.xxx()), +but do not support quite the same parameters (module functions support flags; +compiled object methods support start/end indexes). + +
+import re                   # Imports regular expression module
+
+# Compile and match
+rs1 = r'(\w)(.*?)([0-5](Z)?)'   # Assigns a (raw) string containing a regular expression
+rc1 = re.compile(rs1)       # Compiles regular expr for faster repeated execution
+s1 = 'abc950'               # Some string to search for matches
+m1 = re.match(rs1, s1)      # Finds a match at start of string s1, and returns
+                            # a match object - or None if no match was found
+m1 = rc1.match(s1)          # Same as above, but uses compiled regular expression object
+if m1:                      # If a match was found, then...
+    print m1.group()        # Prints 'abc95' - the part of s1 matched by rs1
+    print m1.group(1)       # Prints 'a' - captured by 1st '()' in rs1
+    print m1.group(3, 2)    # Prints "('5', 'bc9')" - from 3rd & 2nd '()' in rs1
+    print m1.groups()       # Prints "('a', 'bc9', '5', None)" - from all '()' in rs1
+                            # Note: non-matching '()' returns None
+    print m1.start()        # Prints 0 - start index of match in s1
+    print m1.end()          # Prints 5 - end index + 1 of match in s1
+    print m1.span()         # Prints '(0, 5)' - start and end of match
+    print m1.start(2)       # Prints 1 - start index of 2nd '()' capture in s1
+    print m1.end(2)         # Prints 4 - end index + 1 of 2nd '()' capture in s1
+    print m1.span(2)        # Prints '(1, 4)' - start and end of 2nd '()'
+
+# Backreferences
+m1 = re.match(r'(\w+)\1', 'hihi')   # \1 matches same as 1st '()' (can't use \g<1> here)
+print m1.groups()                   # Prints "('hi',)"
+
+# Start/end index parameters
+# (WARNING: ONLY compiled object methods (e.g. rc1.match()) support these!
+# If used with module functions (e.g. re.match()), they may be interpreted
+# as flags and you may not get an error - just strange behavior!)
+m1 = rc1.match(s1, 2)       # Finds a match at start of string s1[2:]
+if m1:                      # If a match was found, then...
+    print m1.groups()       # Prints "('c', '9', '5', None)" - from all '()' in rs1
+print rc1.match(s1, 1, 4)   # Prints 'None' because rs1 does not match s1[1:4] ('bc9')
+
+# Search
+s2 = '.20 391Z'                 # A new string to search for matches
+m2 = rc1.search(s2)             # Finds first match in string s2
+if m2:
+    print m2.groups()           # Prints "('2', '', '0', None)" - from all '()' in rs1
+m2 = rc1.search(s2, m2.end())   # Finds first match in string s2 starting from previous end
+if m2:
+    print m2.groups()           # Prints "('3', '9', '1Z', 'Z')" - from all '()' in rs1
+
+# Finditer
+ri1 = rc1.finditer(s2)          # Returns an iterator
+type(ri1)                       # Returns type with name 'callable-iterator'
+print next(ri1).groups()        # Prints "('2', '', '0', None)"
+print next(ri1).groups()        # Prints "('3', '9', '1Z', 'Z')"
+
+# Findall
+print rc1.findall(s2)           # Prints "[('2', '', '0', ''), ('3', '9', '1Z', 'Z')]"
+                                # Note: non-matching '()' returns '' (not None)
+rs3 = r'\d\d'                   # String containing regular expression with no '()'
+s3 = ' 12.345-6789a'            # A new string to search for matches
+print re.findall(rs3, s3)       # Prints "['12', '34', '67', '89']"
+
+# Split
+print re.split(rs3, s3)         # Prints "[' ', '.', '5-', '', 'a']"
+
+# Sub and subn (substitution)
+print re.sub(rs3, 'xy', s3)         # Prints ' xy.xy5-xyxya'
+print re.subn(rs3, 'xy', s3)        # Prints "(' xy.xy5-xyxya', 4)" (4 substitutions)
+print rc1.sub(r'_\1_\g<1>4_', s1)   # Prints '_a_a4_0' (\1 = \g<1> = 1st captured group)
+print rc1.sub(r'(\g<0>)', s1)       # Prints '(abc95)0' (\g<0> = whole match)
+def f(m): return m.group(1).upper() # Function that returns replacement string for a match
+print rc1.sub(f, s1)                # Prints 'A0' (calls function f for each match)
+
+# Flags
+# (WARNING: ONLY module functions (e.g. re.match()) support these!
+# If used with compiled object methods (e.g. rc1.match()), they may be interpreted
+# as indexes and you may not get an error - just strange behavior!)
+rs4 = r'^hi.\w+$'
+rc4 = re.compile(rs4,
+        re.I|re.S|re.M)     # Flags: re.I: ignore case, re.S: '.' matches also newline,
+                            # re.M: '^' and '$' match start/end of each line within string
+s4 = 'Hi\nHo\nHi\nHUM'
+print rc4.findall(s4)       # Prints "['Hi\nHo', 'Hi\nHUM']"
+
+ +

Comprehensions

+ +For each iteration of the inner (last) 'for' loop, +the expression highlighted below is evaluated +to produce another item in the resulting list +- unless an 'if' condition is false, in which case no item is produced for that iteration. + +
+# List comprehension
+[x * y for x in [1, -1] for y in range(4) if y > x] # Returns list [2, 3, 0, -1, -2, -3]
+
+# Dictionary comprehension
+{x: y for x, y in ((0, 3), (1, 4), (2, 3))}         # Returns dict {0: 3, 1: 4, 2: 3}
+
+# Set comprehension
+{x**2 for x in range(4)}                            # Returns set {0, 1, 4, 9}
+
+# Tuple comprehension - has no dedicated syntax,
+# but a generator expression can be passed to tuple()
+tuple(chr(x) for x in range(65, 67))                # Returns tuple ('A', 'B')
+
+ +

Generator Expressions

+ +
+g = (x for x in 'hello' if x < 'm')     # Assigns a generator object prepared to produce
+                                        # the sequence 'h', 'e', 'l', 'l';
+                                        # generator objects are also iterators
+type(g)                                 # Returns type types.GeneratorType with name
+                                        # 'generator'
+next(g)                                 # Returns 'h', i.e. next (first) item
+next(g)                                 # Returns 'e', i.e. next item
+list(g)                                 # Returns ['l', 'l'], i.e. all remaining items;
+                                        # g is useless now and can't be restarted
+list(g)                                 # Returns []; no more items
+next(g)                                 # Raises StopIteration exception; no more items
+
+g = (x**2 for x in range(5))            # Assigns a new generator object
+for i in g:                             # Assigns each generated item to i in turn
+    if i == 9:                          # If item is 9, then...
+        try:
+            i = next(g)                 # ... skip to next item if any
+        except StopIteration:
+            i = 'end'                   # If no more, set i to 'end' (will not happen)
+    print i                             # Prints '0', '1', '4', '16', one by one
+
+ +See also generator functions. + +

Lambda Expressions

+ +
+f = lambda x, y: x + y  # Assigns a lambda expression (anonymous function) that takes 2
+                        # arguments and returns the sum of these; this is basically the
+                        # same as 'def f(x, y): return x + y', except a lambda doesn't
+                        # need to be bound to a name, and is limited to one expression
+type(f)                 # Returns type types.FunctionType with name 'function'
+f(3,5)                  # Calls lambda expression bound to name f; returns 8
+map(lambda x: x**2, range(4))   # Applies lambda to range and returns [0, 1, 4, 9]
+
+g = lambda x: lambda y: x + y   # Binds g to a function which returns a function
+g(3)                            # Returns a function which adds 3 to stuff
+g(3)(4)                         # Returns 7
+
+ +

Functions

+ +

Function Definitions and Calls

+ +
+# Function definitions
+def f1(x, y=0):         # Arguments may have default values (calculated only once when
+                        # 'def' is executed, so beware if using mutable values, e.g. y=[])
+
+    # Here's a docstring for this function:
+    """This docstring is accessible via f1.__doc__
+    """
+
+    print x, y
+    if x > y:
+        return          # Exits function with return value None
+    if x < y:
+        return y, x     # Exits function with expression list as return value
+                        # Return value is None if function ends without 'return'
+
+def f2(x, *args, **keyargs): # special * and ** syntax explained below
+    print x,            # Prints first argument (comma at end skips newline in output)
+    print args,         # Prints a tuple of all remaining unnamed arguments
+    print keyargs       # Prints a dict of all remaining named arguments
+
+def f3(x):
+    def g(y):           # Defines an inner function (function object) inside f3
+        return x + y    # Function g uses object referenced by f3's local x, so keeps that
+                        # object in existence after f3 returns
+    return g            # Function f3 returns the created function object (in this case a
+                        # 'closure' because it keeps data (x) in an outer scope (f3) alive
+                        # even though that scope has ended when the function is later
+                        # called)
+
+type(f1)                # Returns type types.FunctionType with name 'function' (functions
+                        # are also objects)
+
+# Function calls
+f1(3)                   # Calls f1 which prints '3 0' and returns None
+print f1(3,5)           # Calls f1 which prints '3 5', then prints result '(5, 3)'
+f1(y=5, x=3)            # Passes named arguments to f1 which prints '3 5'
+a1 = [3, 5]
+f1(a1, [4])             # Passes a1 and [4] to f1 which prints '[3, 5] [4]' and returns
+                        # ([4], [3, 5]) because [3,5] is lexicographically smaller than [4]
+f1(*a1)                 # Passes each item of a1 as an argument to f1 which prints '3 5'
+                        # and returns (5, 3)
+d = {'y':5, 'x':3}      # Creates a dictionary
+f1(**d)                 # Passes values of d as named arguments to f1 which prints '3 5'
+f1(*[3], **{'y':5})     # Passes items of list and values of dictionary as arguments
+                        # to f1 which prints '3 5'
+f2(3)                   # Prints '3 () {}'
+f2(3, 4, 5, a=6)        # Prints "3 (4, 5) {'a': 6}"
+
+add10 = f3(10)          # Calls f3 which returns new function that adds 10 to its argument
+print add10(9)          # Calls function add10 and prints return value '19'
+
+f2 = f1                 # (Re-)binds name f2 to same function object as f1
+f2(3)                   # Calls f2 (now same as f1) which prints '3 0' and returns None
+
+ +Notes: + + +

Generator Functions

+ +
+# Using 'yield'
+def f1(m):              # The yield statement in the body of this function causes it to
+                        # return a generator object, which produces a new item whenever
+                        # the yield statement is reached;
+                        # generator objects are also iterators
+    print '1st'         # Prints '1st' when first item is requested from generator (first
+                        # call to next())
+    end = 5 * m + 1
+    for x in xrange(m, end, m):
+        yield x                 # Returns x to caller of next() on generator object, and
+                                # stops execution until next() is called again, whereafter
+                                # execution continues after yield statement
+
+g = f1(3)               # Assigns the generator object returned from function f1
+type(g)                 # Returns type types.GeneratorType with name 'generator'
+next(g)                 # Prints '1st' and returns 3, i.e. next (first) item of generator
+next(g)                 # Returns 6, i.e. next item
+list(g)                 # Returns [9, 12, 15], i.e. all remaining items;
+                        # g is useless now and can't be restarted (but f1 can be called
+                        # again to get a new generator object)
+list(g)                 # Returns []; no more items
+next(g)                 # Raises StopIteration exception; no more items
+
+# Using 'send' and return value from 'yield'
+def f3(m):              # Identical to f1 above, but allows values to be sent into the
+                        # generator at any time (and returned from yield) to modify its
+                        # behavior while iterating over it
+    print '1st'
+    end = 5 * m + 1
+    x = m
+    while x < end:
+        y = yield x     # Returns x to caller of next() or send(), stops execution until
+                        # next() or send() is called again, then returns None (for next())
+                        # or argument to send(), and resumes execution here
+        x = x + m if y is None else y   # Update next item or use value provided by send()
+
+g = f3(3)               # Assigns the generator object returned from function f3
+g.send(4)               # Raises TypeError exception; can't send non-None value to
+                        # just-started generator (no yield to receive it)
+next(g)                 # Prints '1st' and returns 3, i.e. next (first) item of generator
+next(g)                 # Returns 6, i.e. next item
+g.send(4)               # Sends 4 into generator, which sets next item to 4 and returns 4
+next(g)                 # Returns 7, i.e. next item
+list(g)                 # Returns [10, 13], i.e. all remaining items;
+
+ +See also generator expressions. + +

Decorators

+ +
+from functools import wraps # Imports the 'wraps' decorator factory which copies attributes
+                            # (__name__, __doc__, __module__) from the wrapped function to
+                            # the wrapper function to make the wrapping more transparent
+
+def deco1(f):               # Defines a function deco1 which takes another function and
+                            # returns a modified version of it; any function that takes a
+                            # function or class as its sole argument can be used as a
+                            # decorator regardless of what it returns (see how to use deco1
+                            # below)
+    @wraps(f)               # Applies the 'wraps' decorator factory to f_wrapper1
+    def f_wrapper1(*args):                      # Defines the wrapper function which
+        return 2 * f(args[0] * 10, *args[1:])   # calls the wrapped/decorated function
+    return f_wrapper1       # Returns the wrapper function which will later be called
+                            # instead of the wrapped/decorated function
+
+def deco_factory(inscale, outscale):    # Defines a function deco_factory which uses its
+                            # arguments to produce a function that can be used as a
+                            # decorator; any function that does this can be used as a
+                            # decorator factory (see how to use deco_factory below)
+    def deco2(f):           # Defines a function deco2 similar to deco1 above, but this
+                            # one is customized based on the arguments to deco_factory
+        @wraps(f)
+        def f_wrapper2(*args):
+            return outscale * f(args[0] * inscale, *args[1:])
+        return f_wrapper2
+    return deco2            # Returns the deco2 function
+
+# The following line decorates the myadd1 function with the deco1 function;
+# same as doing myadd1 = deco1(myadd1) after defining myadd1,
+# so the name myadd1 will end up referring to f_wrapper1 which, when called,
+# will call the original myadd1 defined below
+@deco1
+def myadd1(x, y):
+    return x + y
+
+# The following line calls deco_factory and uses the returned function (deco2)
+# as a decorator for the myadd2 function;
+# same as doing myadd2 = deco_factory(100, 10)(myadd2) after defining myadd2,
+# so the name myadd2 will end up referring to f_wrapper2 which, when called,
+# will call the original myadd2 defined below
+@deco_factory(100, 10)
+def myadd2(x, y):
+    return x + y
+
+# Any number of decorators can be applied to the same function; they are applied
+# in reverse order;
+# the following is the same as doing myadd3 = deco_factory(100, 10)(deco1(myadd3))
+# after defining myadd3
+@deco_factory(100, 10)
+@deco1
+def myadd3(x, y):
+    return x + y
+
+myadd1(3, 4)                # Calls f_wrapper1 which calls the original myadd1 and returns
+                            # 68 (the result of 2 * (3 * 10 + 4))
+myadd2(3, 4)                # Calls f_wrapper2 which calls the original myadd2 and returns
+                            # 3040 (the result of 10 * (3 * 100 + 4))
+myadd3(3, 4)                # Calls f_wrapper2 which calls f_wrapper1 which calls the
+                            # original myadd3; returns 60080 (10 * (2 * (3 * 100 * 10 + 4)))
+
+ +Examples of standard functions often used as decorators are: +classmethod(), staticmethod(), +property(), functools.total_ordering(). +Most decorators take a function and return a function, but property() takes a function and returns +a property object, and functools.total_ordering() takes a class and returns a class. +Examples of standard functions often used as decorator factories are: functools.wraps(). + +

Built-in Functions

+ +
+__import__()            # TBD
+abs(-3+4j)              # Returns 5.0
+all([True,4,'0'])       # Returns True (Are all items True after conversion to bool? Yes)
+any([False,0,''])       # Returns False (Are any items True after conversion to bool? No)
+apply()                 # TBD
+bin(12)                 # Returns '0b1100' (binary representation of 12)
+bool()                  # Returns a new bool; see basic types
+buffer()                # Returns a new buffer; see sequence types
+bytearray()             # Returns a new bytearray; see sequence types
+bytes()                 # Same as str() (for forward compatibility with Python 3)
+callable(f)             # Returns True if f appears to be callable (i.e. a function, class,
+                        # or other object with a __call__ method); note that some objects
+                        # (e.g. basestring) appear to be callable but will fail when called
+chr(65)                 # Returns 'A' (character with ASCII code 65)
+classmethod(f)          # Returns a class method for function f (usually used as decorator
+                        # @classmethod, see classes)
+cmp(x,y)                # Returns a negative int, 0, or positive int, if x < y, x == y, or
+                        # x > y, respectively
+coerce()                # TBD
+compile('x=3\nprint x', '', 'exec') # Returns a code object which can be executed by exec
+compile('2+5', '', 'eval')          # Returns a code object which can be evaluated by eval()
+complex()               # Returns a new complex; see basic types
+delattr(o, 'x')         # Deletes object o's attribute x; same as del o.x
+dict()                  # Returns a new dict; see other container types
+dir(o)                  # Returns a list of o's attributes, or a list of names in the
+                        # current local scope if no argument is given
+divmod(-5, 3)           # Returns (-2, 1); same as (-5 // 3, -5 % 3)
+enumerate(x)            # Returns a new enumerate; see iterator types
+eval('2+3')             # Returns 5; evaluates any Python expression (or compile() object)
+execfile('myfile')      # Executes Python code in file 'myfile'
+file()                  # Usually only used for isinstance(f, file); see files.
+filter(f, 'hello')      # Returns 'hllo' if f(x) returns True when x > 'g'
+filter(None, [3,0,''])  # Returns [3] (all True items in list)
+float()                 # Returns a new float; see basic types
+format(4, '<03')        # Returns '400' (same as '{:<03}'.format(4), see string operations)
+frozenset()             # Returns a new frozenset; see other container types
+getattr(o, 'x', d)      # Returns the value of object o's attribute x (same as o.x), or, if
+                        # o.x doesn't exist, returns d or raises AttributeError if no d
+globals()               # Returns a dict representing the current global symbol table;
+                        # globals()['x'] = 3 is equivalent to global x; x = 3
+hasattr(o, 'x')         # Returns True if object o has attribute x
+hash(o)                 # Returns a hash value (integer) of immutable object o
+help(o)                 # Prints documentation on object o - or topic o if o is a string
+hex(254)                # Returns '0xfe' (hexadecimal respresentation of 254)
+id(o)                   # Returns the unique id (integer) of object o
+input('Your input: ')   # Same as eval(raw_input('Your input: '))
+int()                   # Returns a new int; see basic types
+intern()                # TBD
+isinstance(o, c)        # Returns True if o is an instance of class c or of a subclass of c
+                        # - or of any item in c if c is a tuple of classes
+issubclass(c1, c2)      # Returns True if c1 is a subclass of, or identical to, c2 - or any
+                        # item in c2 if c2 is a tuple of classes; c1 must be a class
+iter(o)                 # Returns an iterator for iterable o; see iterator types
+iter(f,x)               # Returns an iterator that calls f with no args until return value
+                        # equals x; see iterator types
+len([6,7,8])            # Returns 3 (number of items in list/tuple/set/...)
+list()                  # Returns a new list; see sequence types
+locals()                # Returns a dict representing the current local symbol table (this
+                        # dict should not be modified)
+long()                  # Returns a new long; see basic types
+map(f, [5,2,6], (3,4))  # Returns ['53', '24', '6None'] if f(x,y) returns str(x)+str(y);
+                        # the number of sequences must match the number of arguments to f
+map(None, [5,2,6], (3,4))   # Returns [(5, 3), (2, 4), (6, None)]
+max(3,5,2)              # Returns 5
+max([3,5,2])            # Returns 5
+memoryview()            # Returns a new memoryview; see sequence types
+min(3,5,2)              # Returns 2
+min([3,5,2])            # Returns 2
+next(i,d)               # Returns next item from iterator i, or, if no more items, returns
+                        # d or raises StopIteration if no d; see iterator types
+object()                # Returns a new object; see basic types
+oct(8)                  # Returns '010' (octal representation of 8)
+open('file', 'w')       # Opens 'file' for writing and returns a file object; see files
+ord('A')                # Returns 65 (ASCII code of character 'A')
+ord(u'\u0E01')          # Returns 3585 (Unicode code of character u'\u0E01')
+pow(3.0, 2.0)           # Returns 9.0; same as 3.0**2.0;
+pow(3, 2, 4)            # Returns 1; same as 3**2 % 4 but more efficient; all args must be
+                        # integers
+property()              # Returns a new property
+range(2, 11, 3)         # Returns [2, 5, 8] (from 2 to (and not including) 11 with step 3)
+raw_input('Input: ')    # Prints 'Input: ', reads a line from stdin, and returns the line
+                        # (excluding the final newline)
+reduce(f, [1,2,3,4])    # Returns 10 if f(x,y) returns x + y; same as f(f(f(1,2),3),4)
+reduce(f, [2,3,4], 1)   # Returns 10 if f(x,y) returns x + y; same as f(f(f(1,2),3),4)
+reload(mymodule)        # Reloads previously imported module mymodule
+repr(o)                 # Returns a formal string representation of o, preferably one that
+                        # can be executed by eval() to recreate o
+reversed([1,2,3])       # Returns an iterator for the sequence 3,2,1
+reversed('hello')       # Returns an iterator for the sequence 'o','l','l','e','h'
+round(25.16)            # Returns 25.0 (25.16 rounded to 0 digits after the point)
+round(25.16, 1)         # Returns 25.2 (25.16 rounded to 1 digit after the point)
+round(25.16, -1)        # Returns 30.0 (25.16 rounded to 1 digit before the point)
+set()                   # Returns a new set; see other container types
+setattr(o, 'x', 3)      # Sets object o's attribute x to 3; same as o.x = 3
+slice()                 # Returns a new slice; see basic types
+sorted([10,-1,9])       # Returns [-1, 9, 10] (takes the same additional args as o.sort())
+staticmethod(f)         # Returns a static method for function f (usually used as decorator
+                        # @staticmethod, see classes)
+str()                   # Returns a new str; see sequence types
+sum([1,2,3,4])          # Returns 10 (the sum of all items)
+sum([2,3,4], 1)         # Returns 10 (the sum of all items and the 2nd argument)
+super(C, self).m()      # Calls method m of class C's parent/sibling class (the next class
+                        # after C in the method resolution order of self's class) and
+                        # passes object self to that method; see class inheritance
+tuple()                 # Returns a new tuple; see sequence types
+type()                  # Returns a new type; see basic types
+unichr(3585)            # Returns u'\u0E01' (character with Unicode code 3585)
+unicode()               # Returns a new unicode string; see sequence types
+vars(o)                 # Returns o.__dict__, or same as locals() if no o
+xrange()                # Returns a new xrange; see sequence types
+zip([5,2,6], (3,4))     # Returns [(5, 3), (2, 4)]; any number of collections supported;
+                        # zip can also unzip, because if x is a list of same-length tuples,
+                        # and y = zip(*x), then x = zip(*y)
+
+ +

Classes

+ +

About Classes/Types and Objects

+ +Types and (new-style) classes (we're ignoring old-style classes here) are basically two terms for +the same thing, and they are all instances/objects of type/class type and subclasses of +(i.e. inherit from) type/class object. +Even type and object are instances of type. +

+ +Other objects than types/classes will not be instances of type (their __class__ attribute +will refer to some other type/class) and will not have a superclass tuple (they will not have the +__bases__ attribute). +

+ +The UML diagram below illustrates the relationships between various types of objects +("int:type" means object int is an instance of type/class type, and arrows point +from subclasses to their superclasses/bases). + +

+ + + + + + + + + Objects + + + + Types/Classes + + + + Other Objects + + + + + + + + object:type + + + + type:type + + + + int:type + + + + Myclass:type + + + + Mysubclass:type + + + + 42:int + + + + x:Myclass + + + + y:Mysubclass + + + + o:object + + +
+ +

Class Creation and Instantiation

+ +
+# Class definitions
+class Myclass(object):  # New-style classes must inherit from 'object' or any other class
+                        # inheriting from 'object' (e.g. any built-in Python type)
+
+    # Here's a docstring for this class:
+    """This docstring is accessible via Myclass.__doc__
+    or e.g. o1.__doc__ where o1 is an instance of Myclass.
+    """
+
+    n = 3               # Defines a class variable, shared by all instances of this class
+
+    @staticmethod       # Decorator that defines a static method to be invoked on the class
+    def setn(n):        # itself (or optionally on instances of the class)
+        Myclass.n = n   # Updates the class variable
+
+    @classmethod        # Decorator that defines a class method to be invoked on the class
+    def setn2(cls, n):  # itself (or optionally on instances of the class); first arg is
+                        # the class, conventionally named 'cls'
+        cls.n = n       # Updates the class variable
+
+    def __init__(self, x):  # Defines the instance constructor; first arg is the instance,
+                            # conventionally named 'self' (like 'this' in C++)
+        self.x = x          # Creates an instance variable belonging to the given instance
+
+    def add(self, y):       # Defines an instance method to be invoked on a given instance
+        self.x += (y *      # Updates the previously created instance variable
+            self.n)         # Class variables may be read (not written!) via 'self'
+                            # (if written, a new instance variable is created hiding the
+                            # class variable!)
+
+    def __str__(self):      # Defines informal nicely printable string representation of
+                            # an instance of this class
+        return str(self.x)  # Returns instance variable converted to string
+
+    def __repr__(self):     # Defines formal string representation of an instance of this
+                            # class, preferably executable by eval() to recreate instance
+        return 'Myclass(%d)' % self.x
+
+    def __getitem__(self, item):        # Defines special method for getting indexed item
+        print 'get', item
+        t = item if isinstance(item, tuple) else (item,) # Make item a tuple if not already
+        for i in t:                                      # Step through tuple
+            if isinstance(i, slice):                     # Handle slice by expanding it to
+                print range(*i.indices(self.n)),         # list (self.n sets index limit)
+            elif i == Ellipsis:                          # Handle Ellipsis object by just
+                print '...',                             # printing 3 dots
+            else:
+                print i,
+        print
+        return self.x
+
+    def __setitem__(self, key, val):    # Defines special method for setting indexed item
+        print 'set', key, val
+
+    def __add__(self, other):           # Defines special method overriding '+' operator
+        return self.x + other
+
+    def __radd__(self, other):          # Defines special method overriding '+' operator if
+                                        # this object is 2nd arg and other.__add__()
+                                        # returned NotImplemented
+        return self.x + other + self.n
+
+type(Myclass)               # Returns type type; same as Myclass.__class__
+isinstance(Myclass, type)   # Returns True
+issubclass(Myclass, object) # Returns True
+Myclass.__name__            # Returns 'Myclass'
+Myclass.__bases__           # Returns (object,) (tuple of base classes)
+Myclass.mro()               # Returns [Myclass, object]
+                            # (method resolution order: order in which classes are searched
+                            # for a method definition)
+Myclass.n                   # Returns 3
+type(Myclass.setn)          # Returns type types.FunctionType with name 'function'
+type(Myclass.setn2)         # Returns type types.MethodType with name 'instancemethod'
+type(Myclass.add)           # Returns type types.MethodType with name 'instancemethod'
+                            # (unbound method)
+Myclass.add.__self__        # Returns None (this method is not bound to an instance object)
+Myclass.add.__func__        # Returns underlying 'add' function; calling Myclass.add is
+                            # same as calling Myclass.add.__func__
+
+# Old-style classes (can't do as much as new-style classes, so best not to use them)
+class Myoldclass:       # Old-style classes don't inherit from 'object', even indirectly
+    pass
+type(Myoldclass)        # Returns type with name 'classobj'
+
+# Dynamically defined classes
+type('Mydynclass', (Myclass,), {'n': 4})    # Creates and returns a class with __name__ ==
+                        # 'Mydynclass' but not bound to any name in current namespace;
+                        # this class inherits from Myclass and sets class variable n to 4;
+                        # the class will be lost unless a reference to it is saved, e.g.
+                        # Someclass = type('Mydynclass', ...)
+
+# Instantiation
+o1 = Myclass(10)        # Creates an object as an instance of class 'Myclass' and runs
+                        # the __init__ constructor with parameter x = 10
+type(o1)                # Returns class Myclass; same as o1.__class__
+type(o1.add)            # Returns type types.MethodType with name 'instancemethod'; more
+                        # about method objects below
+o2 = Myclass(20)        # Creates a second instance of the same class using x = 20
+o1.x                    # Returns 10
+o2.x                    # Returns 20
+o1.n                    # Returns 3 (the value of class variable n)
+str(o1)                 # Returns '10' (return value from o1.__str__())
+repr(o1)                # Returns 'Myclass(10)' (return value from o1.__repr__())
+dir(o1)                 # Returns list of all o1's attributes: [..., '__doc__', ...,
+                        # '__init__', ..., 'add', 'n', 'setn', 'setn2', 'x']
+
+o1[4]                   # Calls o1.__getitem__(4)
+o1[::-1] = 2            # Calls o1.__setitem__(slice(None,None,-1),2); see slice
+o1[2,:3,...]            # Calls o1.__getitem__((2,slice(None,3,None),Ellipsis))
+                        # (note: this extended syntax is not supported by built-in types
+                        # such as list and tuple)
+
+o1 + 4                  # Calls o1.__add__(4) which returns 14
+5 + o1                  # Calls o1.__radd__(5) (when (5).__add__(o1) returns NotImplemented)
+                        # which returns 18
+o1.add(2)               # Passes 2 to the 'add' method of o1 which updates o1's x;
+                        # equivalent to Myclass.add(o1, 2)
+o1.x                    # Returns 16 (2 * 3 was added to the previous value 10)
+o2.x                    # Returns 20 (no change)
+
+Myclass.setn(5)         # Changes the class variable n value to 5
+Myclass.setn2(5)        # Same effect as above (Myclass is automatically passed as 1st arg
+                        # to setn2, and 5 becomes 2nd arg)
+Myclass.n = 5           # Same effect as above
+o1.setn(5)              # Same effect as above (o1 is only used to access Myclass)
+o1.setn2(5)             # Same effect as above (o1 is only used to access Myclass)
+                        # (don't do o1.n = 5, it hides the class variable from o1)
+o1.n                    # Returns 5
+o2.n                    # Returns 5 (same class var n is accessed from any instance)
+
+o2.add(-1)
+o1.x                    # Returns 16
+o2.x                    # Returns 15 (-1 * 5 was added to 20)
+
+o1.s = 'hi'             # Creates a new instance variable on o1 only
+Myclass.k = 100         # Creates a new class variable (visible in all existing and new
+                        # instances)
+
+# Bound method objects
+o1a = o1.add            # Assigns a bound method object referencing o1's 'add' method (a
+                        # new object is created every time a user defined method is
+                        # accessed like this, so (o1.add is o1.add) evaluates to False!)
+type(o1a)               # Returns type types.MethodType with name 'instancemethod'
+o1a.__self__            # Returns o1
+o1a.__func__            # Returns Myclass.add.__func__
+o1a(4)                  # Passes 4 to o1's 'add' method, which updates o1's x
+o1.x                    # Returns 36 (4 * 5 was added to 16)
+
+# Built-in function/method objects
+ss = 'abba'.strip       # Assigns a bound method object referencing the built-in strip
+                        # method of string 'abba'
+type(ss)                # Returns type types.BuiltinFunctionType with name
+                        # 'builtin_function_or_method'
+ss.__self__             # Returns 'abba'
+ss.__func__             # ILLEGAL! Built-in methods don't have the __func__ attribute
+ss('a')                 # Returns 'bb' (same as 'abba'.strip('a'))
+type(len)               # Returns type types.BuiltinFunctionType with name
+                        # 'builtin_function_or_method'; built-in functions belong to the
+                        # '__builtin__' module (which is hidden unless explicitly imported),
+                        # but - unlike in Python 3 - they are not bound methods of that
+                        # module
+len.__self__            # Returns None (built-in functions are not bound)
+
+ +

Class Inheritance

+ +
+class A(list):                          # Defines a class A which inherits from list (which
+                                        # inherits from object)
+    def __str__(self):                  # Overrides list's __str__ method in order to...
+        return ('A:' +                  # ... prepend 'A:' to...
+            super(A, self).__str__())   # ... whatever is returned from __str__() of the
+                                        # next classes in the method resolution order (i.e.
+                                        # the previous classes in the inheritance order);
+                                        # the next class is list when self is an instance
+                                        # of A, but B when self is an instance of C!
+
+class B(list):                          # Defines a class B just like A, except...
+    def __str__(self):
+        return ('B:' +                  # ... prepend 'B:' to...
+            super(B, self).__str__())   # ... whatever is returned from __str__() of the
+                                        # next classes in the method resolution order; the
+                                        # next class is list when self is an instance of
+                                        # either B or C
+
+class C(A, B):                          # Defines a class C which inherits primarily from A
+                                        # and secondarily from B
+    def __str__(self):                  # Overrides the __str__ method in order to...
+        return ('C:' +                  # ... prepend 'C:' to...
+            super(C, self).__str__())   # ... whatever is returned from __str__() of the
+                                        # next classes in the method resolution order; the
+                                        # next class is A when self is an instance of C
+
+C.__bases__ # Returns (A, B)
+
+# Method resolution order (MRO) for classes A, B, and C (see notes)
+A.mro()     # Returns [A, list, object]; this means that A().__str__() will first look for
+            # an __str__ method in class A, then in class list, then in class object, until
+            # a class is found which has the method
+B.mro()     # Returns [B, list, object]
+C.mro()     # Returns [C, A, B, list, object]
+
+a = A([0])  # Assigns an instance of class A initialized by calling a.__init__([0]) which
+            # resolves to list.__init__(a,[0]) (list is 1st class with __init__ in A.mro())
+            # which sets the initial value to [0]
+b = B([1])  # Assigns an instance of class B initialized to [1] by list.__init__(b,[1])
+c = C([2])  # Assigns an instance of class C initialized to [2] by list.__init__(c,[2])
+
+print a     # Prints 'A:[0]', because print calls a.__str__()
+            # which resolves to A.__str__(a) (A is a's class and has __str__)
+            # which calls super(A, a).__str__()
+            # which resolves to list.__str__(a) (list follows A in A.mro() and has __str__)
+            # which returns '[0]' to A.__str__
+            # which returns 'A:[0]' to print
+print b     # Prints 'B:[1]', because print calls b.__str__()
+            # which resolves to B.__str__(b) (B is b's class and has __str__)
+            # which calls super(B, b).__str__()
+            # which resolves to list.__str__(b) (list follows B in B.mro() and has __str__)
+            # which returns '[1]' to B.__str__
+            # which returns 'B:[1]' to print
+print c     # Prints 'C:A:B:[2]', because print calls c.__str__()
+            # which resolves to C.__str__(c) (C is c's class and has __str__)
+            # which calls super(C, c).__str__()
+            # which resolves to A.__str__(c) (A follows C in C.mro() and has __str__)
+            # which calls super(A, c).__str__()
+            # which resolves to B.__str__(c) (B follows A in C.mro() and has __str__)
+            # which calls super(B, c).__str__()
+            # which resolves to list.__str__(c) (list follows B in C.mro() and has __str__)
+            # which returns '[2]' to B.__str__
+            # which returns 'B:[2]' to A.__str__
+            # which returns 'A:B:[2]' to C.__str__
+            # which returns 'C:A:B:[2]' to print
+
+ +Notes on method resolution order (MRO): + + +

Property Attributes

+ +The built-in function property(), which creates a property object, can be used as a +decorator to define functions to be called +whenever a certain class attribute is read, written, or deleted. + +
+class C(object):
+    def __init__(self, v):  # Defines the instance constructor
+        self._x = float(v)  # Initializes an instance variable which is not supposed to be
+                            # accessed directly from outside class C
+
+    @property               # Creates a property attribute x whose __get__() method is
+    def x(self):            # this function (function name becomes property name)
+        return self._x
+
+    @x.setter               # Sets the __set__() method of property x to
+    def x(self, v):         # this function (use same name for function and property)
+        self._x = float(v)
+
+    @x.deleter              # Sets the __delete__() method of property x to
+    def x(self):            # this function (use same name for function and property)
+        del self._x
+
+type(C.x)                   # Returns type property
+isinstance(C.x, property)   # Returns True
+
+c = C(1)                    # Assigns a new instance of class C with c._x set to 1.0
+c._x                        # Returns 1.0 (but we're not supposed to access _x directly)
+c.x                         # Returns 1.0 (calls our getter C.x.__get__(c))
+c.x = 2                     # Sets c._x to 2.0 (calls our setter C.x.__set__(c, 2))
+c.x                         # Returns 2.0 (calls our getter C.x.__get__(c))
+del c.x                     # Deletes c._x (calls our deleter C.x.__delete__(c))
+c.x                         # Raises AttributeError exception because c._x doesn't exist
+c.x = 3                     # Sets c._x to 3.0 (calls our setter C.x.__set__(c, 3))
+c.x                         # Returns 3.0 (calls our getter C.x.__get__(c))
+
+ +

Special Methods

+ +Certain special methods - if defined in the class hierarchy of an object (not on the object itself) - are automatically +called when certain built-in Python functions, statements, or syntax are applied to that object, and such calls are +never redirected to the __getattr__ or __getattribute__ methods even if those exist. +Built-in Python classes themselves have many of these special methods. +

+ +In the list below, all methods are instance methods unless specifically stated to be static methods or class methods +(the @staticmethod and @classmethod decorators are unnecessary for special +methods defined within the body of a class definition - the methods are automatically converted to the correct type), +and the methods are assumed to have been defined in a class C of which object o is in instance, like this: + +

+class C(object):
+    def __new__(cls, *args, **kwargs): pass
+    def __init__(self, *args, **kwargs): pass
+    # ...etc...
+
+o = C()
+
+ +List of special methods along with examples of code that causes them to be called: + +
+# Object creation/deletion
+o = C.__new__(C)            # Static method; called by o = C() to create object of class C
+o.__init__()                # Called by o = C() to initialize object created by __new__()
+o.__del__()                 # Called by del o; gc.collect(), i.e. when o is garbage
+                            # collected after last reference to it has been removed
+
+# Object attribute access
+y = o.__getattr__('x')      # Called by y = o.x if o.x and o.__getattribute__ don't exist,
+                            # or if o.__getattribute__('x') raises AttributeError
+y = o.__getattribute__('x') # Called by y = o.x
+o.__setattr__('x', 5)       # Called by o.x = 5
+o.__delattr__('x')          # Called by del o.x
+y = o.__dir__()             # Called by y = dir(o)
+
+# Container object item access
+y = o.__len__()             # Called by y = len(o)
+y = o.__getitem__(3)        # Called by y = o[3]
+o.__setitem__(3, 9)         # Called by o[3] = 9
+o.__delitem__(3)            # Called by del o[3]
+y = o.__getslice__(3, 9)    # Deprecated; TBD
+o.__setslice__(3, 9, o2)    # Deprecated; TBD
+o.__delslice__(3, 9)        # Deprecated; TBD
+y = o.__contains__(3)       # Called by y = 3 in o
+y = o.__iter__()            # Called by y = iter(o)
+y = o.__reversed__()        # Called by y = reversed(o)
+y = o.__missing__(3)        # Called by y = o[3] (from within dict.__getitem__(3)) if o's
+                            # class inherits from dict and o[3] doesn't exist
+
+# Object conversion
+y = o.__repr__()            # Called by y = repr(o)
+y = o.__str__()             # Called by y = str(o)
+y = o.__unicode__()         # Called by y = unicode(o)
+y = o.__format__('^6')      # Called by y = format(o, '^6') or y = '{:^6}'.format(o)
+y = o.__nonzero__()         # Called by y = bool(o)
+y = o.__hash__()            # Called by y = hash(o)
+y = o.__int__()             # Called by y = int(o)
+y = o.__long__()            # Called by y = long(o)
+y = o.__float__()           # Called by y = float(o)
+y = o.__complex__()         # Called by y = complex(o)
+y = o.__coerce__()          # TBD
+
+# Object calling
+y = o.__call__()            # Called by y = o()
+
+# Context management
+y = o.__enter__()           # Called when entering with o as y: pass
+o.__exit__(None, None, None)# Called when exiting with o as y: pass (if no exceptions)
+o.__exit__(excp_type, excp_val, traceback)  # Called when exiting with o as y: raise excp
+
+# Object comparison
+y = o.__lt__(o2)            # Called by y = o < o2, or by y = o2 > o if o's type is
+                            # subclass of o2's type or if o2.__gt__(o) returns
+                            # NotImplemented
+y = o.__le__(o2)            # Called by y = o <= o2, or by y = o2 >= o if o's type is
+                            # subclass of o2's type or if o2.__ge__(o) returns
+                            # NotImplemented
+y = o.__eq__(o2)            # Called by y = o == o2, or by y = o2 == o if o's type is
+                            # subclass of o2's type or if o2.__eq__(o) returns
+                            # NotImplemented
+y = o.__ne__(o2)            # Called by y = o != o2, or by y = o2 != o if o's type is
+                            # subclass of o2's type or if o2.__ne__(o) returns
+                            # NotImplemented
+y = o.__gt__(o2)            # Called by y = o > o2, or by y = o2 < o if o's type is
+                            # subclass of o2's type or if o2.__lt__(o) returns
+                            # NotImplemented
+y = o.__ge__(o2)            # Called by y = o >= o2, or by y = o2 <= o if o's type is
+                            # subclass of o2's type or if o2.__le__(o) returns
+                            # NotImplemented
+y = o.__cmp__(o2)           # TBD
+y = o.__rcmp__(o2)          # TBD
+
+# Unary arithmetic operations
+y = o.__neg__()             # Called by y = -o
+y = o.__pos__()             # Called by y = +o
+y = o.__abs__()             # Called by y = abs(o)
+y = o.__invert__()          # Called by y = ~o
+y = o.__trunc__()           # Called by y = math.trunc(o)
+y = o.__index__()           # Called by y = operator.index(o) or 'hello'[:o] (returns
+                            # 'hello'[:y]) or bin(o) (returns bin(y)) or wherever an exact
+                            # integer is needed
+y = o.__hex__()             # Called by y = hex(o)
+y = o.__oct__()             # Called by y = oct(o)
+
+# Binary arithmetic operations
+y = o.__add__(o2)           # Called by y = o + o2 (but see __radd__)
+y = o.__sub__(o2)           # Called by y = o - o2 (but see __rsub__)
+y = o.__mul__(o2)           # Called by y = o * o2 (but see __rmul__)
+y = o.__div__(o2)           # Called by y = o / o2 (but see __rtruediv__)
+y = o.__floordiv__(o2)      # Called by y = o // o2 (but see __rfloordiv__)
+y = o.__mod__(o2)           # Called by y = o % o2 (but see __rmod__)
+y = o.__divmod__(o2)        # Called by y = divmod(o, o2) (but see __rdivmod__)
+y = o.__pow__(o2)           # Called by y = o ** o2 or y = pow(o, o2) (but see __rpow__)
+y = o.__pow__(o2, 5)        # Called by y = pow(o, o2, 5) (no __rpow__ variant)
+y = o.__lshift__(o2)        # Called by y = o << o2 (but see __rlshift__)
+y = o.__rshift__(o2)        # Called by y = o >> o2 (but see __rrshift__)
+y = o.__and__(o2)           # Called by y = o & o2 (but see __rand__)
+y = o.__or__(o2)            # Called by y = o | o2 (but see __ror__)
+y = o.__xor__(o2)           # Called by y = o ^ o2 (but see __rxor__)
+
+# Reverse binary arithmetic operations
+y = o.__radd__(o2)          # Called by y = o2 + o if o's type is subclass of o2's
+                            # type or if o2.__add__(o) returns NotImplemented
+y = o.__rsub__(o2)          # Called by y = o2 - o if o's type is subclass of o2's
+                            # type or if o2.__sub__(o) returns NotImplemented
+y = o.__rmul__(o2)          # Called by y = o2 * o if o's type is subclass of o2's
+                            # type or if o2.__mul__(o) returns NotImplemented
+y = o.__rdiv__(o2)          # Called by y = o2 / o if o's type is subclass of o2's
+                            # type or if o2.__truediv__(o) returns NotImplemented
+y = o.__rfloordiv__(o2)     # Called by y = o2 // o if o's type is subclass of o2's
+                            # type or if o2.__floordiv__(o) returns NotImplemented
+y = o.__rmod__(o2)          # Called by y = o2 % o if o's type is subclass of o2's
+                            # type or if o2.__mod__(o) returns NotImplemented
+y = o.__rdivmod__(o2)       # Called by y = divmod(o2, o) if o's type is subclass of o2's
+                            # type or if o2.__divmod__(o) returns NotImplemented
+y = o.__rpow__(o2)          # Called by y = o2 ** o or y = pow(o2, o) if o's type is
+                            # subclass of o2's type or if o2.__pow__(o) returns
+                            # NotImplemented
+                            # pow(o2, o, 5) always calls o2.__pow__(o, 5), never __rpow__
+y = o.__rlshift__(o2)       # Called by y = o2 << o if o's type is subclass of o2's
+                            # type or if o2.__lshift__(o) returns NotImplemented
+y = o.__rrshift__(o2)       # Called by y = o2 >> o if o's type is subclass of o2's
+                            # type or if o2.__rshift__(o) returns NotImplemented
+y = o.__rand__(o2)          # Called by y = o2 & o if o's type is subclass of o2's
+                            # type or if o2.__and__(o) returns NotImplemented
+y = o.__ror__(o2)           # Called by y = o2 | o if o's type is subclass of o2's
+                            # type or if o2.__or__(o) returns NotImplemented
+y = o.__rxor__(o2)          # Called by y = o2 ^ o if o's type is subclass of o2's
+                            # type or if o2.__xor__(o) returns NotImplemented
+
+# Augmented arithmetic assignment
+o = o.__iadd__(o2)          # Called by o += o2 (falls back to o = o + o2 if no __iadd__)
+o = o.__isub__(o2)          # Called by o -= o2
+o = o.__imul__(o2)          # Called by o *= o2
+o = o.__idiv__(o2)          # Called by o /= o2
+o = o.__ifloordiv__(o2)     # Called by o //= o2
+o = o.__imod__(o2)          # Called by o %= o2
+o = o.__ipow__(o2)          # Called by o **= o2
+o = o.__ilshift__(o2)       # Called by o <<= o2
+o = o.__irshift__(o2)       # Called by o >>= o2
+o = o.__iand__(o2)          # Called by o &= o2
+o = o.__ior__(o2)           # Called by o |= o2
+o = o.__ixor__(o2)          # Called by o ^= o2
+
+ +

Modules

+ +

Module Creation and Usage

+ +File mymodule.py: +
+# Here's a docstring for this module:
+"""Any Python file can be imported as a module,
+or run as a top level script.
+"""
+
+def f(x):
+    return x * 2
+
+if __name__ == '__main__':      # If this file is run as a script, its module name is
+                                # '__main__',
+    print f(10)                 # in which case call f and print the result '20'
+else:                           # Otherwise, this file is imported as a module,
+    print 'Module:', __name__   # so print 'Module: mymodule'
+
+ +Some other Python file: +
+import mymodule         # Runs mymodule.py; puts all its names into namespace 'mymodule';
+                        # the module prints 'Module: mymodule'
+import os, re           # Imports multiple modules in same statement
+type(mymodule)          # Returns type types.ModuleType with name 'module'
+print mymodule.f(8)     # Calls mymodule's function f, and prints result '16'
+print mymodule.__doc__  # Prints mymodule's docstring: 'Any Python file can be ...'
+print __doc__           # Prints 'None' (this module has no docstring)
+
+ +Some other Python file: +
+import mymodule as m    # Runs mymodule.py; puts all its names into namespace 'm';
+                        # the module prints 'Module: mymodule'
+import os as o, re as r # Imports multiple modules in same statement
+print m.f(8)            # Calls mymodule's function f, and prints result '16'
+
+ +Some other Python file: +
+from mymodule import f  # Runs mymodule.py; puts its name f into our namespace;
+                        # the module prints 'Module: mymodule'
+from re import sub, subn    # Imports multiple names from module in same statement
+print f(8)              # Calls function f (defined in mymodule), and prints result '16'
+
+ +Some other Python file: +
+from mymodule import f as g # Runs mymodule.py; binds name g in our namespace to whatever
+                            # mymodule's name f is bound to;
+                            # the module prints 'Module: mymodule'
+from re import sub as s, subn as sn # Imports multiple names from module in same statement
+print g(8)              # Calls function g (f in mymodule), and prints result '16'
+
+ +Some other Python file: +
+from mymodule import *  # Runs mymodule.py; puts all its names into our namespace;
+                        # the module prints 'Module: mymodule'
+print f(8)              # Calls function f (defined in mymodule), and prints result '16'
+
+ +

Some Standard Modules

+ +Python has a larger number of standard modules. A few are mentioned here. + +
+import sys              # System functionality, e.g. argv, exit(), stdin, stdout, stderr,
+                        # path, version_info
+import os               # Operating system functions, e.g. getcwd(), chdir(), mkdir(),
+                        # makedirs(), rmdir(), remove(), rename(), walk()
+import os.path          # Path manipulation, e.g. exists(), join(), abspath(), dirname(),
+                        # basename()
+import logging
+import atexit
+
+import math             # Math constants and functions, e.g. pi, e, sqrt(), sin()
+import cmath            # Complex math functions, e.g. sqrt
+import decimal          # Class for precise representation of decimal numbers, e.g. 0.1
+import random           # Random number generation
+import functools        # Function manipulation, e.g. partial(), reduce(), @wraps
+
+import re               # See regular expressions
+import collections      # See container types
+import copy             # Object copying functions (deep and shallow copy)
+
+import time
+import datetime
+
+ +

Names

+ +

Binding Names to Objects

+ +Almost everything (values, functions, classes, modules) is an object - mutable or immutable. +Names are not objects themselves - they come into existence when they are bound (assigned) to +objects, and may subsequently be rebound to different objects or deleted. +An object may have multiple names bound to it, and becomes irrelevant (possibly deleted) when +there are no more references to it. +Names are NOT permanent references to fixed storage locations which can be filled with values +as in some other languages (e.g. C). + +
+x = 10                  # (Creates and) binds name x to (immutable) object 10
+y = x                   # Binds name y to same object as name x
+del x                   # Forgets name x; its previously bound object is still bound to y
+z = 10                  # Binds name z to (immutable) object 10 (possibly same object 10
+                        # that y is bound to; mutable objects will never be reused like
+                        # this)
+y = 11                  # Binds name y to a different object than before
+p = q = ['hi']          # Binds names p and q to same (mutable) object (first p, then q!)
+p, z = z, p             # Swaps objects bound to names p and z (so p = 10, z = ['hi'])
+
+def f1(b):              # Binds name f1 to function object defined here, and binds name b
+                        # to object passed as argument to f1
+    b = 3               # Binds name b to different object than was passed to f1 (this
+                        # does not alter the passed object nor rebind whatever name was
+                        # used to refer to that object when calling f1)
+    return b            # Returns object bound to name b (and name b goes out of scope)
+
+x = f1(y)               # Calls function object bound to name f1, and passes object bound
+                        # to name y as argument (name y itself is not passed and can't be
+                        # rebound from within f1);
+                        # also binds name x to object returned by function call
+
+class C1(object):       # Binds name C1 to class object defined here
+    pass
+
+c = C1()                # Binds name c to new instance object created from class object
+                        # bound to name C1
+
+ +

Name Scope

+ +
+def f1(x, y):
+    global d, e             # Allows this function to modify module level names d & e
+    print b, x              # Prints '1 1'; no need for 'global' to read external b, but
+                            # this will fail if b is assigned anywhere within f1
+                            # (UnboundLocalError exception if assigned after this line)
+                            # (except if we cheat and assign to globals()['b'])
+    c, d, e = 10, 11, 12    # Creates local c hiding external c (because no 'global')
+                            # (but we can still cheat and read/write globals()['c']);
+                            # also creates e at module level (did not exist before this!)
+    f[0] = 13               # f refers to mutable object which can be changed even though
+                            # f is not listed as 'global' (but without 'global' external f
+                            # can't be changed to reference another object)
+    x = 14                  # x was same as external b, but is now 14, while b is still 1
+    y[0] = 15               # y refers to same object as external g, and that object can
+                            # be changed via y (but g can't be changed to refer to another
+                            # object)
+    f2()                    # Calls external function f2
+    if x == 14:             # Function definitions may be conditional like any statement
+                            # (the 'if' body does not have its own local name scope)
+        def f3(d):          # f3 is defined within f1, so can read f1's locals
+            print d         # Prints local parameter d which is hiding external d
+            global c        # Gives f3 access to module level c - not local c in f1
+            c = x           # Assigns f1's local x to module level c (now c = 14)
+    f3(30)                  # Calls inner function f3 which prints '30'
+    print b, c, d, e, f, g  # Prints '1 10 11 12 [13] [15]'
+
+def f2():                   # f2 is not defined within f1, so can't read f1's locals
+    pass
+
+b, c, d = 1, 2, 3           # Names read by function f1 must be defined before call to f1
+f, g = [4], [5]             # but not necessarily before definition of f1
+f1(b, g)                    # Calls function f1 and sets parameters x = b and y = g
+print b, c, d, e, f, g      # Prints '1 14 11 12 [13] [15]'; f1 changed d, e, and objects
+                            # referenced by f and g (but didn't change f & g themselves)
+
+ +Notes: + + +
+ +
+ + + diff --git a/puzzle.html b/puzzle.html new file mode 100644 index 0000000..7f4d31e --- /dev/null +++ b/puzzle.html @@ -0,0 +1,523 @@ + + + + + + + +Puzzle + + + + + + + +
+ +

Puzzle

+ +
+
+ +
Game Over!
+
+
+ +
+Your Moves: 0 +

+ + +

+ +
+ + + diff --git a/random_code_gen.html b/random_code_gen.html new file mode 100644 index 0000000..c98368d --- /dev/null +++ b/random_code_gen.html @@ -0,0 +1,221 @@ + + + + + + + +Random Code Generator + + + + + + + +
+ +

Random Code Generator

+ +
+Code format: + + +

+Alphabet: + +Alphabet size: 0 characters (= 0 bits) +

+ +

+Code size: + characters +(= 0 bits) +

+ + + +
+ +
+ + + diff --git a/relativity_theory/doc.html b/relativity_theory/doc.html new file mode 100644 index 0000000..4791b44 --- /dev/null +++ b/relativity_theory/doc.html @@ -0,0 +1,1678 @@ + + + + + + + +Special Relativity Theory + + + + + + + +
+ +

Special Relativity Theory

+ +
+ +

Contents

+ +
+ +

Introduction

+ +

This document describes some of the ideas and consequences of Einstein's Theory of +Special Relativity (or Special Theory of Relativity), which claims that the speed of light in +a vacuum and all laws of physics (but not time and distance) are the same in all +inertial frames of reference in the absence of gravity.

+ +

Special Relativity is a special case of General Relativity, where the latter adds gravity +as a curvature of space and time (so frames in free fall are still considered inertial).

+ +
+ +

General Notes

+ +

In this document, distance and time are measured in seconds +(you might also say that distance is measured in light-seconds, because it is +obtained by dividing by the speed of light c). +Velocity is always relative to the velocity c, so it is unitless.

+ +

Unless otherwise stated, all statements about what observers +"see", ignore the time it takes the light to travel from the observed event to +the observer.

+ +
+ +

Lorentz Transformation

+ +

Let's assume we have two frames with the same orientation. +Each has a single spatial dimension. We'll refer to one frame as the "lab +frame" and the other as the "moving frame". The moving frame is moving with a +constant velocity v relative to the lab frame, and v is considered positive +when the movement is in the direction of plus infinity on the spatial axis of +the lab frame. The time is zero in both frames, when their spatial zero +locations coincide.

+ +

The Lorentz transformation gives the space-time coordinates +(x,t) of an event in the lab frame as a function of the coordinates (x1,t1) +of the same event in the moving frame:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

where the Lorentz factor

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +

is 1 for v = 0, and tends towards infinity as v tends towards +±1.

+ +

The inverse transformation is obtained by simply negating v:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Note that observers in both frames agree that the +coordinates (x,t) in the lab frame and (x1,t1) in the +moving frame represent the same event.

+ +

Time Dilation Derived from the Lorentz Transformation

+ +

Due to the so-called time dilation, a clock at rest in the +moving frame will appear to be slow to an observer at rest in the lab frame. +This is seen by setting x1 = 0 in the Lorentz transformation (to represent +the fixed clock location in the moving frame) and solving for t:

+ + + + + + + + + + + + + + + + + + +

So, for the observer in the lab frame, 1s on the moving +clock corresponds to γ seconds of his time. Hence, the clock appears to +be slow.

+ +

A clock at rest in the lab frame will also appear to be slow +to an observer at rest in the moving frame. This can be seen by setting x = 0 +and solving for t1:

+ + + + + + + + + + + + + + + + + + +

So, both observers see the other's clock as being slow.

+ +

Lorentz Contraction Derived from the Lorentz Transformation

+ +

The so-called Lorentz contraction is the spatial equivalent +of the time dilation described above. A rod (of length Δx1) at +rest in the moving frame will appear to be shorter to an observer at rest in +the lab frame. This is seen by setting t = 0 in the Lorentz transformation (representing +the instant in lab time at which the locations of the two end points of the rod +are simultaneously determined) and solving for Δx:

+ + + + + + + + + + + + + + + + + + + + + + + + +

The opposite is true as well: a rod at rest in the lab frame +will appear to be shorter to an observer at rest in the moving frame.

+ +

Note that the concept of length only makes sense if the end +point locations are determined simultaneously, and two spatially +separate events, which are simultaneous in one frame, are not simultaneous in +the other. So, the Lorentz contraction is actually a direct consequence of the +time dilation.

+ +

Lorentz Transformation in 2-Dimensional Space

+ +

If we add a second spatial dimension y, and still assume +that the velocity v of the moving frame is in the direction of plus infinity on +the x axis, then the Lorentz transformation becomes:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

This is clearly true, because obviously there will be no +effect on the spatial dimension perpendicular to the direction of movement. We'll +call this 3-by-3 matrix L*.

+ +

Now let's consider the more general case where v is not +necessarily parallel to the x axis. We can handle this case by simply +transforming the spatial coordinates to a rotated frame of reference, where v is +parallel to the first spatial axis. Then we can perform the Lorentz transformation +above, and finally rotate the coordinates back again.

+ +

The following transformation will convert coordinates in the +rotated frame to coordinates in the actual frame:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

We'll call this 3-by-3 matrix (including the 1/v factor) R. +Note that the columns of R are simply the base vectors of the rotated frame +expressed in actual coordinates; the first base vector is the v vector +normalized to a length of 1, the second base vector is the same, but rotated 90 +degrees, and the third base vector representing the time axis is the same as +the original time vector.

+ +

The inverse matrix R-1 will rotate the other way, +i.e. convert coordinates in the actual frame to coordinates in the rotated +frame. It is not difficult to see that a rotation in the opposite direction is +equivalent to negating vy in the matrix R (negating the angle of +rotation from the x axis means negating the y coordinate), so we have:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

where the 3-by-3 matrix (including the 1/v factor) is R-1.

+ +

We now have the three matrices we need:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

The total transformation matrix L is the matrix product of +these:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

So, the Lorentz transformation for arbitrary v≠0 in a +2-dimensional space is:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Note that this won't work for v=0, because our rotation +matrix R becomes undefined when v has no direction. However, we already know +the solution to this special case: it is simply the identity transformation +(x,y,t) = (x1,y1,t1).

+ +
+ +

Space-Time Diagrams

+ +

A space-time diagram shows the lab time t vs. the lab +location x. In this diagram we can also draw the t1 and x1 +axes of a frame moving with velocity v relative to the lab frame. The lines +representing the t1 and x1 axes can be found by setting x1 += 0 and t1 = 0, respectively, in the Lorentz transformation. Thus, +we find that the lines x = vt and t = vx represent the t1 and x1 +axes, respectively (see example in Figure 1).

+ +

In a similar way, we can find the lines representing t1 += ..., -2s, -1s, 1s, 2s, ..., and x1 = ..., -2s, -1s, 1s, 2s, +... It turns out that all the t1 = n lines are parallel, and all the +x1 = n lines are parallel. Here's a summary of the characteristics +of these lines:

+ +

t1 = n lines (where n is an integer number of +seconds):

+ + + +

x1 = n lines (where n is an integer number of +seconds):

+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1s×1s + + + + + + + + + + + + + + + + + + + + + + x + t + x1 + t1 + + + + +
+ +

Figure 1: Space-time diagram (v=0.5)

+ +

The area of one of the unit parallelograms in the (x1,t1) +coordinate system is always 1s2 (this area is equal to the +determinant of the x1 and t1 unit vectors, which +according to the information above are (γ, γv) and (γv, γ), +respectively).

+ +

From the above we can make the following observations about how the axes of the moving frame +appear in the space-time diagram:

+ + + +

Note that light (in a vacuum) always travels along a 45° line +towards the upper right or upper left corner (corresponding to v=±1) in all frames.

+ +

Time Dilation Derived from a Space-Time Diagram

+ +

A clock at rest at x1 = 0 in the moving frame +will be moving up the t1 axis in the space-time diagram as time +passes (i.e. the t1 axis is the clock's "world line" - the path it follows +through space and time). +An observer at rest at x = 0 in the lab frame will be moving up the t +axis as time passes (i.e. the t axis is the observer's world line). +From the observer's point of view, the clock and he will +be on the same horizontal line in the diagram at any given moment (because this +line represents the current lab time).

+ +

If both the observer and the clock start out at t = t1 += 0, then they will be at the positions indicated in Figure 2 after 1s of the clock's time. +The clock will of course have moved one unit up the t1 axis +(because this is 1s of its time) corresponding to the lab coordinates +(γv,γ) determined previously +during the construction of the space-time diagram. The observer will be on the +same horizontal line, so his lab coordinates will be (0,γ). This shows us +that 1s of the clock's time corresponds to γ seconds of the observer's +time - in accordance with the time dilation formula derived in +section #!

+ +
+ + + + + +
+ +

Figure 2: Time dilation seen from lab frame
+(black eye is observer in lab frame, blue circle is clock in moving frame)

+ +

Now, let's swap the observer +and the clock and see how this looks in the space-time diagram. The clock is +now at rest in the lab frame and moving up the t axis, while the observer is +moving up the t1 axis. From the observer's point of view, the clock +and he will be on the same line parallel to the x1 axis at any given +moment (because this line represents the current time in the moving frame).

+ +

Again, the observer and the +clock start out at t = t1 = 0, but this time they end up at the new +positions indicated in Figure 3 after 1s of the clock's time. +The clock will have moved one unit up the t axis, and the observer will have moved more than +one unit (γ seconds) up the t1 axis in order to remain at the same t1 +time as the clock (i.e. to remain on the same line parallel to the x1 +axis). So, again the observer sees the predicted time dilation.

+ +
+ + + + + +
+ +

Figure 3: Time dilation seen from moving frame
+(blue eye is observer in moving frame, black circle is clock in lab frame)

+ +

Lorentz Contraction Derived from a Space-Time Diagram

+ +

Let's consider a rod at rest in the moving frame with one +end point at xa1 = 0 and the other at xb1 = 1s. As time +passes, the first end point will move up the t1 axis, and the second +end-point will move up a line parallel to the t1 axis. These two +lines (dashed red in Figure 4) are the world lines of the end points (i.e. +the "tracks" of the end-points as these move through space and time).

+ +

At any given moment, an observer in the moving frame will +measure the spatial distance between the two end points along a line parallel +to the x1 axis (e.g. the green rod in Figure 4), because such a line represents +simultaneity in the moving frame. Thus, this observer will see a rod length of +xb1-xa1 = 1s.

+ +
+ + + + + + + + + + +
+ +

Figure 4: Length of moving rod measured in moving frame
+(green rod indicates moment of measurement)

+ +
+ + + + + + + + + + +
+ +

Figure 5: Length of moving rod measured in lab frame
+(green rod indicates moment of measurement)

+ +

An observer at rest in the lab frame, however, will measure +the spatial distance between the two end points along a line parallel to the x +axis (e.g. the green rod in Figure 5), because that is what he understands +to be a simultaneous measurement of the two end point locations. So, he will see +a shorter rod (of length 1s/γ, to be exact).

+ +

Note that in the situations shown in Figure 4 and Figure 5, the two observers +agree that they are determining the location of the leftmost end point of the rod +at the same moment (because this end-point happens to have the same coordinates +in both figures), although their +clocks do not show the same time at that moment. The observers also agree that +they are not determining the location of the rightmost end point at the +same moment. Each observer believes that he is determining the location of both +end points simultaneously, and that the other observer is not doing so, +so he does not find it surprising that the other observer comes up with a +different length.

+ +
+ +

Time across Space

+ +

The Lorentz transformation (see section #) tells us that +the time in the moving frame at lab coordinates (x,t) is:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

This means that an observer in the lab frame will see the +time in the moving frame at a fixed lab location (e.g. x = 0) as being faster +by a factor of γ than his own time. +In section # we determined that he will +see the time at a fixed location in the moving frame as being slower +by a factor of γ than his own time. In other words, if he observes +a row of clocks at rest and synchronized +in the moving frame, and shifts his attention from clock to clock as each of +them passes him, their time will appear to be faster than his +(e.g. the vertical instances of clocks B, C, and D in Figure 6 show times -2s, 0s, and 2s +when they pass lab location x=0 at lab times -1.73s, 0s, and 1.73s, respectively), but if he only +looks at a single clock all the time, then its time will be slower than his +(as illustrated in Figure 2 in section #).

+ +
+ + + + + + + + + + + + + + + + + A + B + C + B + D + + +
+ +

Figure 6: Row of moving clocks seen from lab frame
+(blue circles are clocks, dashed red lines are their world lines)

+ +

The reason for this apparent paradox is that the moving +clocks - due to their spatial separation - show different times in the lab frame, +even though they are perfectly synchronized in the moving frame. +If we fix the lab time t in the formula above, we see that at any given lab moment (t), +the leading clock (with largest x if v>0) will show the earliest time, +and each successive clock will show later and later times +(e.g. the horizontal instances of clocks A, B, and C in Figure 6 show times +-1s, -0.5s, and 0s, respectively, when they are observed simultaneously in the lab frame at +lab time t=0s). The difference between the times shown on two clocks is equal to +their lab distance multiplied by their velocity multiplied by γ.

+ +

Twin Paradox

+ +

The above observations help explain +the well-known twin paradox, which asks what happens if one twin travels out +into space and back again (with the dashed red world line in Figure 7), +while the other twin remains at home (with the black t axis as world line). Since the twins +are moving relative to each other, each twin should see the other one ageing +more slowly than himself due to time dilation. So, when the traveling twin +returns home, the two would supposedly disagree about which one is now the youngest. +This is the paradox.

+ +

However, if we place synchronized clocks +throughout the lab frame and let the traveling twin shift his attention from +clock to clock as he passes them, then it is clear from our previous +observations that he will see the lab time on these clocks as being faster +than his own time, even though each individual clock (as well as the clock at +home) will be ticking slower than his. Since the traveling twin sees the lab +time at his own location to be consistently faster throughout his travel, he +will not be surprised to find that the other twin is older than himself when he +returns home. So, the twins agree that the one at home is the oldest.

+ +

But what if the traveling twin keeps his attention on the clock at home? +Due to time dilation that clock will appear to be ticking slower during the outbound journey +(where the blue coordinate system in Figure 7 represents the moving frame) - +and also slower during the homebound journey (where the green coordinate system in Figure 7 +represents the moving frame). So how does the twin at home end up being older? As +previously shown, the clocks ahead of the traveling twin in his direction of +movement will show later and later times, so when he reverses his direction of +travel to move homeward, the clocks he passed on his outbound journey +(including the one at home) will immediately jump from an earlier to a later +time in order to fulfill the requirement that clocks ahead of him show later +and later times (the clock at home jumps from the lower to the upper black circle in Figure 7). +In other words, the twin at home will appear to age very fast +during the short period of time while the traveling twin is reversing +his direction of movement. Thus, there is no paradox.

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + x + t + + x1 + t1 + + + + + x'1 + t'1 + + + + + +
+ +

Figure 7: Traveling twin's world line (dashed red) in lab frame.
+Twin at home appears to age instantaneously from lower to upper black circle

+ +

Note that if the traveling twin were initially approaching the twin at home +(along the green t'1 axis in Figure 7), and then reversed his direction to move away +(along the blue t1 axis), he would see the twin at home jump back in time +(from the upper to the lower black circle).

+ +
+ +

Space-Time Interval, Proper Time, Proper Distance

+ +

As demonstrated earlier, the measured time and distance between two events depends on the +observer's velocity relative to the events. However, the so-called "space-time interval" +(Δs)2 between two events is independent of the observer (i.e. universally +invariant) and is determined as follows for 1 and 3 spatial dimensions, respectively:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

There are 3 cases:

+ + + +

For one event to be the cause of another, the space-time interval between them must be timelike +or lightlike (and the time difference must be non-negative).

+ +
+ +

Acceleration

+ +

An acceleration is defined as constant if co-moving +observers see it as constant, i.e. if the instantaneous acceleration is the +same in all inertial frames at the moment when the accelerating object is at +rest in each of these frames.

+ +

The world line (in an inertial frame with a single spatial dimension) of an object with the +constant acceleration a0 is a hyperbola described by the following +equation:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

where t0 is the time at which the object is at +rest in the inertial frame, and xc is the x-coordinate where the hyperbola's +2 asymptotes intersect (see Figure 8). The distance from xc to x(t0) +(i.e. the distance between the 2 black dots in Figure 8) +is 1/a0. The left and right branches of the hyperbola correspond to a negative and +positive a0, respectively.

+ +
+ + + + + + + + + + (xc,t0) + + + 1/a0 + + + + + x + t + + +
+ +

Figure 8: World lines (dashed red) of objects with constant acceleration +a0=1s-1 (right) and a0=-1s-1 (left), +both with (xc,t0)=(0,0)

+ +

Note that this constant acceleration hyperbola consists of all the space-time points whose +"proper distance" to (xc,t0) is 1/a0 (see +section #). +

+ +
+ +

Traveling Faster than Light

+ +

As stated in section #, the Lorentz factor γ +becomes infinite as the velocity v approaches 1 (the speed of light), so this is an upper +limit on v, which cannot be exceeded. How does this affect space travel?

+ +

Well, if an observer in the lab +frame determines the traveler's velocity v by measuring the traveled (lab +frame) distance and dividing that by the (lab frame) duration of the travel, +then it is true that this velocity v has an upper limit of 1. So, from the point +of view of the observer in the lab frame, the traveler cannot travel faster +than light.

+ +

Likewise, if the traveler himself +determines his own velocity v by measuring the relative movement of some +reference point at rest in the lab frame, and he makes sure that both distance +and time are measured in his own moving frame, then this velocity will be the +same as the one determined by the observer in the lab frame, and it will also +have an upper limit of 1. So, if the traveler defines his velocity as the +velocity at which objects at rest in the lab frame move past him, then also he +will agree that he cannot travel faster than light.

+ +

However, one might argue that a +different definition of velocity would be more appropriate for the traveler. A +traveler going from location A to B (both locations being at rest in the lab +frame) will probably be more interested in knowing how long (measured in his +own time) it will take him to travel the (lab frame) distance from A to B. So +he might define his effective velocity as the traveled lab frame +distance divided by the duration of the travel measured in his own time. +Using the Lorentz transformation, we find that the relationship between this +effective velocity veff and the real velocity v is given by:

+ + + + + + + + + + + + + + + + + + + + + +

There is clearly no theoretical upper bound on veff, and it becomes greater than 1 +("faster than light") when v is greater than 1/√2 +(approx. 71% of the speed of light). +This means that a traveler can in fact (theoretically) +travel as far as he wants in as short time as he wants. To him it appears that the +Lorentz contraction is reducing the distance he has to travel, so he can do it +in a shorter time without exceeding the speed of light.

+ +

The disadvantage of traveling with a +high veff is that the lab time (at the traveler's moving location) +will speed up as demonstrated in section #, +so the interesting distant star that was the target of the travel, might be long gone +when the traveler gets there an hour later, and the folks at home will be long dead +when he returns after another hour of his own time.

+ +
+ +
+ + + diff --git a/robots.txt b/robots.txt new file mode 100644 index 0000000..f8e89e8 --- /dev/null +++ b/robots.txt @@ -0,0 +1,3 @@ +User-agent: * +Disallow: +Sitemap: https://pewscorner.github.io/sitemap.txt diff --git a/screen_size_converter.html b/screen_size_converter.html new file mode 100644 index 0000000..cc9742d --- /dev/null +++ b/screen_size_converter.html @@ -0,0 +1,270 @@ + + + + + + + +Screen Size Converter + + + + + + + +
+ +

Screen Size Converter

+ +
+ + + + + + + + + + + +
Diagonal size (inches): + + +
Ratio (width:height): + + +
+ +
Width (cm): + + +
Height (cm): + + +
+ +
+ +

+Green fields are calculated from yellow ones; select a field to make it yellow. + +

+ + + diff --git a/sitemap.txt b/sitemap.txt new file mode 100644 index 0000000..64857c8 --- /dev/null +++ b/sitemap.txt @@ -0,0 +1,63 @@ +https://pewscorner.github.io/ +https://pewscorner.github.io/anaclock.html +https://pewscorner.github.io/calendar.html +https://pewscorner.github.io/chinese_year.html +https://pewscorner.github.io/dancing_snowman.html +https://pewscorner.github.io/date_converter.html +https://pewscorner.github.io/digiclock.html +https://pewscorner.github.io/doppler_calc.html +https://pewscorner.github.io/event_logger.html +https://pewscorner.github.io/feedback.html +https://pewscorner.github.io/fullscreencolor.html +https://pewscorner.github.io/GiantKangaroo.html +https://pewscorner.github.io/holidays.html +https://pewscorner.github.io/iq_mismatch_calc.html +https://pewscorner.github.io/mouse_button_test.html +https://pewscorner.github.io/music_synth.html +https://pewscorner.github.io/necktie.html +https://pewscorner.github.io/number_converter.html +https://pewscorner.github.io/platonic_solids.html +https://pewscorner.github.io/programmers_converter.html +https://pewscorner.github.io/puzzle.html +https://pewscorner.github.io/random_code_gen.html +https://pewscorner.github.io/RollingStone.html +https://pewscorner.github.io/screen_size_converter.html +https://pewscorner.github.io/terms.html +https://pewscorner.github.io/text_input_converter.html +https://pewscorner.github.io/waveforms.html +https://pewscorner.github.io/barcodes/ +https://pewscorner.github.io/barcodes/code128_barcode_generator.html +https://pewscorner.github.io/barcodes/ean_barcode_generator.html +https://pewscorner.github.io/barcodes/qrcode_generator.html +https://pewscorner.github.io/doppler_theory/doc.html +https://pewscorner.github.io/eyes/ +https://pewscorner.github.io/iq_mismatch_theory/doc.html +https://pewscorner.github.io/japanese/ +https://pewscorner.github.io/japanese/hiragana.html +https://pewscorner.github.io/japanese/katakana.html +https://pewscorner.github.io/japanese/pronunciation.html +https://pewscorner.github.io/japanese/relative_positions.html +https://pewscorner.github.io/japanese/test_adjs.html +https://pewscorner.github.io/japanese/test_dates.html +https://pewscorner.github.io/japanese/test_hiragana.html +https://pewscorner.github.io/japanese/test_katakana.html +https://pewscorner.github.io/japanese/test_nouns.html +https://pewscorner.github.io/japanese/test_numbers.html +https://pewscorner.github.io/japanese/test_rel_time.html +https://pewscorner.github.io/japanese/test_time.html +https://pewscorner.github.io/japanese/test_verbs.html +https://pewscorner.github.io/LTE/ +https://pewscorner.github.io/LTE/dci_decoder.html +https://pewscorner.github.io/LTE/lte_resource_grid.html +https://pewscorner.github.io/LTE/pdsch_calc.html +https://pewscorner.github.io/programming/ +https://pewscorner.github.io/programming/python3_quick_ref.html +https://pewscorner.github.io/programming/python_quick_ref.html +https://pewscorner.github.io/relativity_theory/doc.html +https://pewscorner.github.io/thai/ +https://pewscorner.github.io/thai/consonants.html +https://pewscorner.github.io/thai/flash_cards.html +https://pewscorner.github.io/thai/time_date.html +https://pewscorner.github.io/thai/tone_rules.html +https://pewscorner.github.io/thai/translit_scheme.html +https://pewscorner.github.io/thai/vowels.html diff --git a/style2.css b/style2.css new file mode 100644 index 0000000..2358fae --- /dev/null +++ b/style2.css @@ -0,0 +1,362 @@ +:root { + --style-version: 2; +} + +body { + background-color: #EEEEEE; + color: #3366AA; + padding: 0px; + margin: 0px; + border: 0px; + text-align: center; + font-family: Arial, sans-serif; +} + +header { + position: fixed; + z-index: 1000; + box-sizing: border-box; + width: 100%; + padding: 0px; + margin: 0px; + top: 0px; + transition: top 0.2s ease-in-out; +} + +header.hidden { + top: -4em; /* <= -height of header */ +} + +header div.header_bar { + display: -webkit-flex; + display: flex; + -webkit-justify-content: space-between; + justify-content: space-between; + -webkit-align-items: baseline; + align-items: baseline; + position: relative; + box-sizing: border-box; + width: 100%; + max-width: 50em; + margin: auto; + padding: 0em 0.5em; + border: 1px solid #999999; + border-radius: 0.6em; + background-color: #E0E0E0; + box-shadow: 0.2em 0.3em 0.1em rgba(0, 0, 0, 0.5); +} + +.footer { + margin: 0.5em; + font-size: 0.7em; +} + +div.menu_bg { + display: none; + position: fixed; + z-index: 1001; + box-sizing: border-box; + top: 0px; + left: 0px; + width: 100%; + height: 100%; + margin: 0px; + padding: 0px; + border: none; + box-shadow: none; + border-radius: 0px; + background-color: rgba(0, 0, 0, 0.6); +} + +div.menu_container { + position: relative; + box-sizing: border-box; + width: 100%; + height: 0px; + max-width: 50em; + border: none; + margin: auto; +} + +div.menu { + position: absolute; + box-sizing: border-box; + top: 0.5em; + right: 0.5em; + width: auto; + max-width: calc(100% - 1em); + padding: 0em 0.5em; + border: 1px solid #999999; + border-radius: 0.2em; + background-color: #E0E0E0; + box-shadow: 0.2em 0.3em 0.1em rgba(0, 0, 0, 0.5); +} + +body > div.hcontainer { + max-width: 50em; + padding: 3em 0px 0px 0px; /* top >= height of header */ + margin: auto; + border: 1px solid #BBBBBB; + border-radius: 1em; + background-color: #F4FFF0; +} + +div.hcontainer { + display: -webkit-flex; + display: flex; + -webkit-flex-flow: row wrap; + flex-flow: row wrap; + -webkit-justify-content: center; + justify-content: center; + box-sizing: border-box; +} + +div.vcontainer { + display: -webkit-flex; + display: flex; + -webkit-flex-flow: column nowrap; + flex-flow: column nowrap; + -webkit-justify-content: space-between; + justify-content: space-between; + margin: 0px; + padding: 0px; +} + +.vcenter { + -webkit-align-items: center; + align-items: center; +} + +div.box { + box-sizing: border-box; + text-align: left; + padding: 0.5em 1em; + margin: 0px; + max-width: 100%; + overflow: auto; +} + +div.toc { + overflow: auto; +} + +div.imgbox { + width: 100%; /* Hack to make IE shrink child images to fit div (images seem to ignore container's max-width). */ +} + +div.hcontainer > div { + -webkit-flex: 1 1 auto; + flex: 1 1 auto; +} + +div.vcontainer > div { + -webkit-flex: 0 1 auto; + flex: 0 1 auto; +} + +a[href]:link, a[href]:visited { + color: #50A0D0; +} + +a[href]:hover, a[href]:active { + color: #80C8FF; +} + +a[href].navbut, button, select { + padding: 0.5em; + margin: 0.5em 0em; + border: 1px solid #BBBBBB; + border-radius: 0.5em; + text-align: center; + text-decoration: none; + box-sizing: border-box; + font-family: Arial, sans-serif; +} + +button.hdrnavbut { + padding: 0.1em 0.5em 0em 0.5em; + margin: 0.1em 0em; +} + +button + button { + margin-left: 1em; +} + +button::-moz-focus-inner { + padding: 0px; + border: 0px; +} + +a[href].navbut { + display: block; + width: 100%; + max-width: 25em; + margin-left: auto; + margin-right: auto; +} + +.menu .menuitembut { + display: block; + width: 100%; + margin: 0.5em 0em; +} + +/* TODO: Remove this a while after page.js has stopped using BR elements as menu item separators */ +.menu br { + display: none; +} + +.hdrnavbut, .menu .menuitembut { + background: linear-gradient(#F8F8F8, #A8A8A8); + color: #333333; + font-size: 1rem; +} + +.hdrnavbut:hover, .hdrnavbut:hover, .menu .menuitembut:hover { + background: linear-gradient(#FFFFFF, #CCCCCC); + color: #333333; +} + +.hdrnavbut:active, .hdrnavbut:active, .menu .menuitembut:active { + background: linear-gradient(#CCCCCC, #FFFFFF); + color: #333333; +} + +a[href].navbut, button, select { + background: linear-gradient(#FFFAF4, #DDBB99); + color: #550000; +} + +a[href].navbut:hover, button:hover, select:hover { + background: linear-gradient(#FFFFFF, #EEEEAA); + color: #554400; +} + +a[href].navbut:active, button:active, select:active { + background: linear-gradient(#A4CC99, #E8FFDD); + color: #000000; +} + +button:disabled { + background: linear-gradient(#FAFAFA, #BBBBBB); + color: #888888; +} + +option { + background-color: #B4DDAA; + color: #000000; +} + +option:disabled { + color: #999999; +} + +a[href].hdrhomebut { + padding: 0.2em 0em; + margin: 0.1em; + border-width: 0px; + text-decoration: none; + font-weight: bold; + font-size: 1.1em; + color: #999999; + text-align: left; +} + +a[href].hdrhomebut:hover, a.hdrhomebut:active { + color: #000000; +} + +br.clear { + clear: both; +} + +h1 { + display: block; + width: 100%; + font-weight: bold; + font-size: 2em; + text-align: center; + margin-top: 1.3rem; + margin-bottom: 1.3rem; +} + +h2 { + font-weight: bold; + font-size: 1.2em; + text-align: left; + margin-top: 1.8rem; + margin-bottom: 1.2rem; +} + +h3, h4, h5, h6 { + font-weight: bold; + font-size: 1em; + text-align: left; + margin-top: 1.5rem; + margin-bottom: 1rem; +} + +.page_subtitle { + display: block; + width: 100%; + font-weight: bold; + font-size: 1em; + text-align: center; + margin-top: -0.5rem; + margin-bottom: 1.3rem; +} + +ul { + list-style: circle; + margin: 0.2em 0em; + padding: 0em 0em 0em 1em; +} + +li { + padding: 0em 0em 0.2em 0em; +} + +img { + display: block; + max-width: 100%; + margin-left: auto; + margin-right: auto; +} + +img.noshrink { + max-width: none; +} + +svg.equation { + display: block; + max-width: 100%; + margin-left: auto; + margin-right: auto; + fill: #3366AA; +} + +.fig_caption { + text-align: center; + margin-top: 0.5em; +} + +canvas { + display: block; + max-width: 100%; + margin-left: auto; + margin-right: auto; +} + +input[type="text"], input[type="number"], textarea { + font-family: Arial, sans-serif; + background-color: #FFFFEE; + padding: 0.3rem; +} + +span.words { + display: inline-block; +} + +span.overline { + border-top: 1px solid currentColor; +} diff --git a/terms.html b/terms.html new file mode 100644 index 0000000..11f2b6d --- /dev/null +++ b/terms.html @@ -0,0 +1,53 @@ + + + + + + + +Terms of Use + + + + + +
+ +

Terms of Use

+ +
+ +The following applies to the "PEW's Corner" website (currently located at https://pewscorner.github.io) and everything +on it. + +

General Disclaimer

+ +Everything on this site is provided "AS IS" without any warranty of any kind, but every effort has been made to ensure +that the content is accurate. Users may use the feedback form (in the menu) to report errors. + +

Privacy

+ +This site does not use ads, cookies, or any form of visitor tracking (but see the disclaimer about third party services +below). No personal data is collected or stored (except if the user chooses to provide such data via the feedback form). + +

+All user-provided data is processed on the client side only (i.e. in the user's browser) and is not sent to the server +(again, the feedback form is the obvious exception). + +

Third Party Services

+ +This site is hosted on Github, and the feedback form functionality is provided by Google Forms. Those services bear no +responsibility for the content of this site, nor do the policies described on this page apply to those services +(for example, those services might implement some form of visitor tracking for their own purposes). + +

Software License

+ +All software available on this site (e.g. embedded javascript and associated HTML elements) is provided under +this extremely permissive license. + +
+ +
+ + + diff --git a/text_input_converter.html b/text_input_converter.html new file mode 100644 index 0000000..740045f --- /dev/null +++ b/text_input_converter.html @@ -0,0 +1,1919 @@ + + + + + + + +Text Input Assistant and Converter + + + + + + + +
+ +

Text Input Assistant and Converter

+ +
+Key pad: + +
+
+ +
+
+
+ +
+ +
+ + + +
+ +
+ + +
+ +
+Help: + +
+ +
+ + + diff --git a/thai/consonants.html b/thai/consonants.html new file mode 100644 index 0000000..e242f66 --- /dev/null +++ b/thai/consonants.html @@ -0,0 +1,123 @@ + + + + + + + +Thai Consonants + + + + + + +
+ +

Thai Consonants

+ +
+ + + +

Notes:

+
    +
  1. ฃ, ฅ, and ฦ are considered obsolete. +
  2. ฤ and ฦ are usually not classified as constants but as special vowels which include a consonant sound. +However, they behave like consonants with respect to tones and dictionary ordering when they provide the first consonant +sound in a syllable. +
  3. Sources disagree on whether ซ and ฌ may end a syllable. +
+ +
+ +
+ + + diff --git a/thai/flash_cards.html b/thai/flash_cards.html new file mode 100644 index 0000000..6f56bd9 --- /dev/null +++ b/thai/flash_cards.html @@ -0,0 +1,346 @@ + + + + + + + +Thai Flash Cards + + + + + + + +
+ +

Thai Flash Cards

+ +
+ +
+ + + +
+ +
+ +
+
+ +
+ + + + + + +
+ +
+ +
ThaiTransliterationEnglish + +
+
+ +
+ + + diff --git a/thai/index.html b/thai/index.html new file mode 100644 index 0000000..9403110 --- /dev/null +++ b/thai/index.html @@ -0,0 +1,31 @@ + + + + + + + +Thai Language + + + + + +
+ +

Thai Language

+ +
+Text input assistant and converter +Transliteration scheme +Consonants +Vowels +Tone rules +Flash cards +Time and date +
+ +
+ + + diff --git a/thai/time_date.html b/thai/time_date.html new file mode 100644 index 0000000..ba08390 --- /dev/null +++ b/thai/time_date.html @@ -0,0 +1,206 @@ + + + + + + + +Thai Time and Date + + + + + + + +
+ +

Thai Time & Date

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
6-hour time system +
00:00 +เที่ยงคืน /
+สองยาม +
12:00 +เที่ยงวัน +
01:00 +ตีหนึ่ง +13:00 +บ่ายโมง +
02:00 +ตีสอง +14:00 +บ่ายสองโมง +
03:00 +ตีสาม +15:00 +บ่ายสามโมง +
04:00 +ตีสี่ +16:00 +บ่ายสี่โมง /
+สี่โมงเย็น +
05:00 +ตีห้า +17:00 +ห้าโมงเย็น +
06:00 +หกโมงเช้า +18:00 +หกโมงเย็น +
07:00 +โมงเช้า /
+เจ็ดโมงเช้า +
19:00 +หนึ่งทุ่ม /
+ทุ่มหนึ่ง +
08:00 +สองโมงเช้า /
+แปดโมงเช้า +
20:00 +สองทุ่ม +
09:00 +สามโมงเช้า /
+เก้าโมงเช้า +
21:00 +สามทุ่ม +
10:00 +สี่โมงเช้า /
+สิบโมงเช้า +
22:00 +สี่ทุ่ม +
11:00 +ห้าโมงเช้า /
+สิบเอ็ดโมงเช้า +
23:00 +ห้าทุ่ม +
6-hour and 24-hour examples +
01:05 + +ตีหนึ่งห้านาที /
+หนึ่งนาฬิกาห้านาที +
17:30 + +ห้าโมงครึ่งตอนเย็น /
+สิบเจ็ดนาฬิกาสามสิบนาที +
21:45 + +อีกสิบห้านาทีสี่ทุ่ม /
+ยี่สิบเอ็ดนาฬิกาสี่สิบห้านาที +
Days of the week +
Sunday +วันอาทิตย์ +Thursday +วันพฤหัสฯ +
Monday +วันจันทร์ +Friday +วันศุกร์ +
Tuesday +วันอังคาร +Saturday +วันเสาร์ +
Wednesday +วันพุธ +weekend +เสาร์-อาทิตย์ +
Months +
January +มกราคม +July +กรกฎาคม +
February +กุมภาพันธ์ +August +สิงหาคม +
March +มีนาคม +September +กันยายน +
April +เมษายน +October +ตุลาคม +
May +พฤษภาคม +November +พฤศจิกายน +
June +มิถุนายน +December +ธันวาคม +
Examples of dates +
January 31 + +วันที่สามสิบเอ็ดมกราคม /
+วันที่สามสิบเอ็ดเดือนมกรา /
+วันที่สามสิบเอ็ดเดือนที่หนึ่ง +
Buddhist calendar +
+Buddhist year = Christian year + 543 +

+ +

+ +
+ +
+ + + diff --git a/thai/tone_rules.html b/thai/tone_rules.html new file mode 100644 index 0000000..2d71bcd --- /dev/null +++ b/thai/tone_rules.html @@ -0,0 +1,75 @@ + + + + + + + +Thai Tone Rules + + + + + + + +
+ +

Thai Tone Rules

+ +
+ + + + + + + + + +
Class of initial consonant in syllable +Class 1
("mid")
กจฎฏดตบปอ
(unaspirated stops)
+
Class 2
("high")
ขฃฉฐถผ
ฝศษสห
(aspirated stops and
unvoiced fricatives)
+
Class 3
("low")
คฅฆงชซฌญ
ฑฒณทธนพฟ
ภมยรฤลฦวฬฮ
(sonorants,
aspirated stops, and
unvoiced fricatives)
+
No tone
mark +
Live syllable
(long vowel at end or
any vowel + sonorant)
Examples: มา, คน
+
Mid +Rising +Mid +
Dead syllable
(short vowel at end or
any vowel + non-sonorant)
Examples: และ, บอก
+
Low +Falling/High
(for long/short
vowel)
+
Tone
mark +
อ่ (ไม้เอก) +Low +Falling +
อ้ (ไม้โท) +Falling +High +
อ๊ (ไม้ตรี) +High +  +
อ๋ (ไม้จัตวา) +Rising +
+ +
+ +
+ + + diff --git a/thai/translit_scheme.html b/thai/translit_scheme.html new file mode 100644 index 0000000..2473ead --- /dev/null +++ b/thai/translit_scheme.html @@ -0,0 +1,68 @@ + + + + + + + +Thai Transliteration Scheme + + + + + + + +
+ +

Thai Transliteration Scheme

+

(Used on this site)

+ +
+ + +
Tones Consonants +
a mid tone b like English +
à low tone ch like English +
á high tone d like English +
â falling tone f like English +
ǎ rising tone h like English +
Vowels (short / long) j like English +
a / aa between can and car k like g in get +
e / ee like first part of a in shake kh like c in cat +
i / ii like in him or see l like English +
o / oo like first part of o in show m like English +
u / uu like in boot n like English +
ae / aeebetween tan and ten ng like in ring +
oe / oeelike in her p between bat and pat +
ue / ueelike in put ph like p in park +
or / oorbetween car and core r like English +
Notes s like English +
+Syllables are separated by a '-' (but an initial +consonant followed by an implicit 'a' sound is +not considered a separate syllable).
+The consonant อ is not transliterated.
+Final consonants are always one of:
+k,p,t,m,n,ng,w,y. +
t between den and ten +
th like t in tape +
w like English +
y like in yellow +
+ +
+ +
+ + + diff --git a/thai/vowels.html b/thai/vowels.html new file mode 100644 index 0000000..41e86e8 --- /dev/null +++ b/thai/vowels.html @@ -0,0 +1,164 @@ + + + + + + + +Thai Vowels + + + + + + + +
+ +

Thai Vowels

+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
Short +Long +
Open +Closed +Translit. +Open +Closed +Translit. +
ะ +อั +a +า +aa +
อิ +i +อี +ii +
อึ +ue +อือ +อื +uee +
อุ +u +อู +uu +
ะ +อ็ +e + +ee +
ะ +อ็ +ae + +aee +
ะ +ออ +o + +oo +
อะ +(เอิ) +oe +อ +อิ +oee +
าะ +อ็ +or +อ +oor +
Diphtongs +
+  +ai +  +  +
+  +ai +(ไ) +  +aai +
อำ +  +am +(อำ) +  +aam +
า +  +aw +  +  +
อียะ +  +ia +อีย +ia +
อือะ +  +uea +อือ +uea +
อัวะ +  +ua +อัว + +ua +
  +  +ย +  +oey +
  +  +ฤๅ +  +ruee +
+ +
+ +
+ + + diff --git a/thai_digits.gif b/thai_digits.gif new file mode 100644 index 0000000..8c5a1a9 Binary files /dev/null and b/thai_digits.gif differ diff --git a/vscode_stuff/showflags/images/capture1.png b/vscode_stuff/showflags/images/capture1.png new file mode 100644 index 0000000..370e81a Binary files /dev/null and b/vscode_stuff/showflags/images/capture1.png differ diff --git a/vscode_stuff/showflags/images/capture2.png b/vscode_stuff/showflags/images/capture2.png new file mode 100644 index 0000000..2171a22 Binary files /dev/null and b/vscode_stuff/showflags/images/capture2.png differ diff --git a/vscode_stuff/showflags/images/capture3.png b/vscode_stuff/showflags/images/capture3.png new file mode 100644 index 0000000..f466340 Binary files /dev/null and b/vscode_stuff/showflags/images/capture3.png differ diff --git a/vscode_stuff/showflags/images/capture4.png b/vscode_stuff/showflags/images/capture4.png new file mode 100644 index 0000000..0ebce8e Binary files /dev/null and b/vscode_stuff/showflags/images/capture4.png differ diff --git a/waveforms.html b/waveforms.html new file mode 100644 index 0000000..c146449 --- /dev/null +++ b/waveforms.html @@ -0,0 +1,1839 @@ + + + + + + + +Waveforms + + + + + + + +
+ +

Waveforms

+

(Fourier Series)

+ +
+ +

Introduction

+ +

If we have a fundamental sine wave (1st harmonic) of the following form +(for time-domain waves, x may be replaced by ft, where f is the fundamental frequency and t is the time point):

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

and add nth harmonics of the form:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(where A1 = 1 and B1 = 0 for the fundamental) then the waveform resulting from summing the +first N harmonics (including the fundamental) can be expressed as:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

We define w to be the limiting case when an infinite number of harmonics are added:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Examples

+ +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+Harmonics (N): + +
+ +
+ +
+ +
+ +
+
+

Figure 1: Harmonic sum wN(x) compared to limiting case w(x).

+ +
+

Figure 2: Individual harmonics hn(x) which form wN(x) in figure 1.

+ +

Notes

+ + +
+ +
+ + +