summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichele Simionato <michele.simionato@gmail.com>2016-02-11 09:37:10 +0100
committerMichele Simionato <michele.simionato@gmail.com>2016-02-11 09:37:10 +0100
commit57656f186561145e5193d1865f9adadb647a94a8 (patch)
treee7426ba130f11563f14276ed10caaab44e319359
parent245eb3cfb319a090dc577d6ad0c09b9d8a419faf (diff)
downloadpython-decorator-git-57656f186561145e5193d1865f9adadb647a94a8.tar.gz
Refined the documentation
-rw-r--r--documentation.pdf903
-rw-r--r--src/decorator.py1
-rw-r--r--src/tests/documentation.py142
3 files changed, 550 insertions, 496 deletions
diff --git a/documentation.pdf b/documentation.pdf
index 3cb6096..f0699db 100644
--- a/documentation.pdf
+++ b/documentation.pdf
@@ -17,7 +17,7 @@ endobj
<< /A << /S /URI /Type /Action /URI (mailto:michele.simionato@gmail.com) >> /Border [ 0 0 0 ] /Rect [ 153.7323 704.0236 289.4623 716.0236 ] /Subtype /Link /Type /Annot >>
endobj
6 0 obj
-<< /A << /S /URI /Type /Action /URI (http://pypi.python.org/pypi/decorator/4.0.5) >> /Border [ 0 0 0 ] /Rect [ 153.7323 659.7736 338.2823 671.7736 ] /Subtype /Link /Type /Annot >>
+<< /A << /S /URI /Type /Action /URI (http://pypi.python.org/pypi/decorator/4.0.10) >> /Border [ 0 0 0 ] /Rect [ 153.7323 659.7736 343.8423 671.7736 ] /Subtype /Link /Type /Annot >>
endobj
7 0 obj
<< /Border [ 0 0 0 ] /Contents () /Dest [ 52 0 R /XYZ 62.69291 765.0236 0 ] /Rect [ 62.69291 560.0236 121.0229 572.0236 ] /Subtype /Link /Type /Annot >>
@@ -26,34 +26,34 @@ endobj
<< /Border [ 0 0 0 ] /Contents () /Dest [ 52 0 R /XYZ 62.69291 765.0236 0 ] /Rect [ 527.0227 560.7736 532.5827 572.7736 ] /Subtype /Link /Type /Annot >>
endobj
9 0 obj
-<< /Border [ 0 0 0 ] /Contents () /Dest [ 52 0 R /XYZ 62.69291 594.0236 0 ] /Rect [ 62.69291 542.0236 118.4129 554.0236 ] /Subtype /Link /Type /Annot >>
+<< /Border [ 0 0 0 ] /Contents () /Dest [ 52 0 R /XYZ 62.69291 582.0236 0 ] /Rect [ 62.69291 542.0236 118.4129 554.0236 ] /Subtype /Link /Type /Annot >>
endobj
10 0 obj
-<< /Border [ 0 0 0 ] /Contents () /Dest [ 52 0 R /XYZ 62.69291 594.0236 0 ] /Rect [ 527.0227 542.7736 532.5827 554.7736 ] /Subtype /Link /Type /Annot >>
+<< /Border [ 0 0 0 ] /Contents () /Dest [ 52 0 R /XYZ 62.69291 582.0236 0 ] /Rect [ 527.0227 542.7736 532.5827 554.7736 ] /Subtype /Link /Type /Annot >>
endobj
11 0 obj
-<< /Border [ 0 0 0 ] /Contents () /Dest [ 52 0 R /XYZ 62.69291 339.0236 0 ] /Rect [ 62.69291 524.0236 182.7229 536.0236 ] /Subtype /Link /Type /Annot >>
+<< /Border [ 0 0 0 ] /Contents () /Dest [ 52 0 R /XYZ 62.69291 315.0236 0 ] /Rect [ 62.69291 524.0236 182.7229 536.0236 ] /Subtype /Link /Type /Annot >>
endobj
12 0 obj
-<< /Border [ 0 0 0 ] /Contents () /Dest [ 52 0 R /XYZ 62.69291 339.0236 0 ] /Rect [ 527.0227 524.7736 532.5827 536.7736 ] /Subtype /Link /Type /Annot >>
+<< /Border [ 0 0 0 ] /Contents () /Dest [ 52 0 R /XYZ 62.69291 315.0236 0 ] /Rect [ 527.0227 524.7736 532.5827 536.7736 ] /Subtype /Link /Type /Annot >>
endobj
13 0 obj
-<< /Border [ 0 0 0 ] /Contents () /Dest [ 58 0 R /XYZ 62.69291 729.0236 0 ] /Rect [ 62.69291 506.0236 114.3629 518.0236 ] /Subtype /Link /Type /Annot >>
+<< /Border [ 0 0 0 ] /Contents () /Dest [ 58 0 R /XYZ 62.69291 699.0236 0 ] /Rect [ 62.69291 506.0236 114.3629 518.0236 ] /Subtype /Link /Type /Annot >>
endobj
14 0 obj
-<< /Border [ 0 0 0 ] /Contents () /Dest [ 58 0 R /XYZ 62.69291 729.0236 0 ] /Rect [ 527.0227 506.7736 532.5827 518.7736 ] /Subtype /Link /Type /Annot >>
+<< /Border [ 0 0 0 ] /Contents () /Dest [ 58 0 R /XYZ 62.69291 699.0236 0 ] /Rect [ 527.0227 506.7736 532.5827 518.7736 ] /Subtype /Link /Type /Annot >>
endobj
15 0 obj
-<< /Border [ 0 0 0 ] /Contents () /Dest [ 58 0 R /XYZ 62.69291 478.0236 0 ] /Rect [ 62.69291 488.0236 183.2629 500.0236 ] /Subtype /Link /Type /Annot >>
+<< /Border [ 0 0 0 ] /Contents () /Dest [ 58 0 R /XYZ 62.69291 436.0236 0 ] /Rect [ 62.69291 488.0236 183.2629 500.0236 ] /Subtype /Link /Type /Annot >>
endobj
16 0 obj
-<< /Border [ 0 0 0 ] /Contents () /Dest [ 58 0 R /XYZ 62.69291 478.0236 0 ] /Rect [ 527.0227 488.7736 532.5827 500.7736 ] /Subtype /Link /Type /Annot >>
+<< /Border [ 0 0 0 ] /Contents () /Dest [ 58 0 R /XYZ 62.69291 436.0236 0 ] /Rect [ 527.0227 488.7736 532.5827 500.7736 ] /Subtype /Link /Type /Annot >>
endobj
17 0 obj
-<< /Border [ 0 0 0 ] /Contents () /Dest [ 59 0 R /XYZ 62.69291 302.2236 0 ] /Rect [ 62.69291 470.0236 122.1429 482.0236 ] /Subtype /Link /Type /Annot >>
+<< /Border [ 0 0 0 ] /Contents () /Dest [ 59 0 R /XYZ 62.69291 282.2236 0 ] /Rect [ 62.69291 470.0236 122.1429 482.0236 ] /Subtype /Link /Type /Annot >>
endobj
18 0 obj
-<< /Border [ 0 0 0 ] /Contents () /Dest [ 59 0 R /XYZ 62.69291 302.2236 0 ] /Rect [ 527.0227 470.7736 532.5827 482.7736 ] /Subtype /Link /Type /Annot >>
+<< /Border [ 0 0 0 ] /Contents () /Dest [ 59 0 R /XYZ 62.69291 282.2236 0 ] /Rect [ 527.0227 470.7736 532.5827 482.7736 ] /Subtype /Link /Type /Annot >>
endobj
19 0 obj
<< /Border [ 0 0 0 ] /Contents () /Dest [ 60 0 R /XYZ 62.69291 226.2236 0 ] /Rect [ 62.69291 452.0236 69.91291 464.0236 ] /Subtype /Link /Type /Annot >>
@@ -92,28 +92,28 @@ endobj
<< /Border [ 0 0 0 ] /Contents () /Dest [ 64 0 R /XYZ 62.69291 170.4236 0 ] /Rect [ 527.0227 380.7736 532.5827 392.7736 ] /Subtype /Link /Type /Annot >>
endobj
31 0 obj
-<< /Border [ 0 0 0 ] /Contents () /Dest [ 65 0 R /XYZ 62.69291 276.6236 0 ] /Rect [ 62.69291 362.0236 139.9329 374.0236 ] /Subtype /Link /Type /Annot >>
+<< /Border [ 0 0 0 ] /Contents () /Dest [ 65 0 R /XYZ 62.69291 288.6236 0 ] /Rect [ 62.69291 362.0236 139.9329 374.0236 ] /Subtype /Link /Type /Annot >>
endobj
32 0 obj
-<< /Border [ 0 0 0 ] /Contents () /Dest [ 65 0 R /XYZ 62.69291 276.6236 0 ] /Rect [ 527.0227 362.7736 532.5827 374.7736 ] /Subtype /Link /Type /Annot >>
+<< /Border [ 0 0 0 ] /Contents () /Dest [ 65 0 R /XYZ 62.69291 288.6236 0 ] /Rect [ 527.0227 362.7736 532.5827 374.7736 ] /Subtype /Link /Type /Annot >>
endobj
33 0 obj
-<< /Border [ 0 0 0 ] /Contents () /Dest [ 66 0 R /XYZ 62.69291 312.6236 0 ] /Rect [ 62.69291 344.0236 80.47291 356.0236 ] /Subtype /Link /Type /Annot >>
+<< /Border [ 0 0 0 ] /Contents () /Dest [ 66 0 R /XYZ 62.69291 300.6236 0 ] /Rect [ 62.69291 344.0236 80.47291 356.0236 ] /Subtype /Link /Type /Annot >>
endobj
34 0 obj
-<< /Border [ 0 0 0 ] /Contents () /Dest [ 66 0 R /XYZ 62.69291 312.6236 0 ] /Rect [ 83.25291 344.0236 161.2529 356.0236 ] /Subtype /Link /Type /Annot >>
+<< /Border [ 0 0 0 ] /Contents () /Dest [ 66 0 R /XYZ 62.69291 300.6236 0 ] /Rect [ 83.25291 344.0236 161.2529 356.0236 ] /Subtype /Link /Type /Annot >>
endobj
35 0 obj
-<< /Border [ 0 0 0 ] /Contents () /Dest [ 66 0 R /XYZ 62.69291 312.6236 0 ] /Rect [ 167.2529 344.0236 192.2729 356.0236 ] /Subtype /Link /Type /Annot >>
+<< /Border [ 0 0 0 ] /Contents () /Dest [ 66 0 R /XYZ 62.69291 300.6236 0 ] /Rect [ 167.2529 344.0236 192.2729 356.0236 ] /Subtype /Link /Type /Annot >>
endobj
36 0 obj
-<< /Border [ 0 0 0 ] /Contents () /Dest [ 66 0 R /XYZ 62.69291 312.6236 0 ] /Rect [ 521.4627 344.7736 532.5827 356.7736 ] /Subtype /Link /Type /Annot >>
+<< /Border [ 0 0 0 ] /Contents () /Dest [ 66 0 R /XYZ 62.69291 300.6236 0 ] /Rect [ 521.4627 344.7736 532.5827 356.7736 ] /Subtype /Link /Type /Annot >>
endobj
37 0 obj
-<< /Border [ 0 0 0 ] /Contents () /Dest [ 67 0 R /XYZ 62.69291 225.4236 0 ] /Rect [ 62.69291 326.0236 177.1629 338.0236 ] /Subtype /Link /Type /Annot >>
+<< /Border [ 0 0 0 ] /Contents () /Dest [ 67 0 R /XYZ 62.69291 213.4236 0 ] /Rect [ 62.69291 326.0236 177.1629 338.0236 ] /Subtype /Link /Type /Annot >>
endobj
38 0 obj
-<< /Border [ 0 0 0 ] /Contents () /Dest [ 67 0 R /XYZ 62.69291 225.4236 0 ] /Rect [ 521.4627 326.7736 532.5827 338.7736 ] /Subtype /Link /Type /Annot >>
+<< /Border [ 0 0 0 ] /Contents () /Dest [ 67 0 R /XYZ 62.69291 213.4236 0 ] /Rect [ 521.4627 326.7736 532.5827 338.7736 ] /Subtype /Link /Type /Annot >>
endobj
39 0 obj
<< /Border [ 0 0 0 ] /Contents () /Dest [ 69 0 R /XYZ 62.69291 374.2236 0 ] /Rect [ 62.69291 308.0236 228.8329 320.0236 ] /Subtype /Link /Type /Annot >>
@@ -167,7 +167,7 @@ endobj
<< /BaseFont /Helvetica-BoldOblique /Encoding /WinAnsiEncoding /Name /F5 /Subtype /Type1 /Type /Font >>
endobj
54 0 obj
-<< /A << /S /URI /Type /Action /URI (http://www.python.org/moin/PythonDecoratorLibrary) >> /Border [ 0 0 0 ] /Rect [ 283.3077 397.0236 512.8377 409.0236 ] /Subtype /Link /Type /Annot >>
+<< /A << /S /URI /Type /Action /URI (http://www.python.org/moin/PythonDecoratorLibrary) >> /Border [ 0 0 0 ] /Rect [ 283.3077 355.0236 512.8377 367.0236 ] /Subtype /Link /Type /Annot >>
endobj
55 0 obj
<< /BaseFont /Courier-Bold /Encoding /WinAnsiEncoding /Name /F6 /Subtype /Type1 /Type /Font >>
@@ -176,7 +176,7 @@ endobj
<< /BaseFont /Courier-Oblique /Encoding /WinAnsiEncoding /Name /F7 /Subtype /Type1 /Type /Font >>
endobj
57 0 obj
-<< /A << /S /URI /Type /Action /URI (https://docs.python.org/3/library/functools.html#functools.update_wrapper) >> /Border [ 0 0 0 ] /Rect [ 135.8454 157.8236 251.406 169.8236 ] /Subtype /Link /Type /Annot >>
+<< /A << /S /URI /Type /Action /URI (https://docs.python.org/3/library/functools.html#functools.update_wrapper) >> /Border [ 0 0 0 ] /Rect [ 135.8454 115.8236 251.406 127.8236 ] /Subtype /Link /Type /Annot >>
endobj
58 0 obj
<< /Annots [ 54 0 R 57 0 R ] /Contents 108 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 105 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0
@@ -277,7 +277,7 @@ endobj
<< /Outlines 85 0 R /PageLabels 128 0 R /PageMode /UseNone /Pages 105 0 R /Type /Catalog >>
endobj
84 0 obj
-<< /Author (Michele Simionato) /CreationDate (D:20160211054253-01'00') /Creator (\(unspecified\)) /Keywords () /Producer (ReportLab PDF Library - www.reportlab.com) /Subject (\(unspecified\))
+<< /Author (Michele Simionato) /CreationDate (D:20160211093653-01'00') /Creator (\(unspecified\)) /Keywords () /Producer (ReportLab PDF Library - www.reportlab.com) /Subject (\(unspecified\))
/Title (The decorator module) >>
endobj
85 0 obj
@@ -287,19 +287,19 @@ endobj
<< /Dest [ 52 0 R /XYZ 62.69291 765.0236 0 ] /Next 87 0 R /Parent 85 0 R /Title (Introduction) >>
endobj
87 0 obj
-<< /Dest [ 52 0 R /XYZ 62.69291 594.0236 0 ] /Next 88 0 R /Parent 85 0 R /Prev 86 0 R /Title (What's New) >>
+<< /Dest [ 52 0 R /XYZ 62.69291 582.0236 0 ] /Next 88 0 R /Parent 85 0 R /Prev 86 0 R /Title (What's New) >>
endobj
88 0 obj
-<< /Dest [ 52 0 R /XYZ 62.69291 339.0236 0 ] /Next 89 0 R /Parent 85 0 R /Prev 87 0 R /Title (Usefulness of decorators) >>
+<< /Dest [ 52 0 R /XYZ 62.69291 315.0236 0 ] /Next 89 0 R /Parent 85 0 R /Prev 87 0 R /Title (Usefulness of decorators) >>
endobj
89 0 obj
-<< /Dest [ 58 0 R /XYZ 62.69291 729.0236 0 ] /Next 90 0 R /Parent 85 0 R /Prev 88 0 R /Title (Definitions) >>
+<< /Dest [ 58 0 R /XYZ 62.69291 699.0236 0 ] /Next 90 0 R /Parent 85 0 R /Prev 88 0 R /Title (Definitions) >>
endobj
90 0 obj
-<< /Dest [ 58 0 R /XYZ 62.69291 478.0236 0 ] /Next 91 0 R /Parent 85 0 R /Prev 89 0 R /Title (Statement of the problem) >>
+<< /Dest [ 58 0 R /XYZ 62.69291 436.0236 0 ] /Next 91 0 R /Parent 85 0 R /Prev 89 0 R /Title (Statement of the problem) >>
endobj
91 0 obj
-<< /Dest [ 59 0 R /XYZ 62.69291 302.2236 0 ] /Next 92 0 R /Parent 85 0 R /Prev 90 0 R /Title (The solution) >>
+<< /Dest [ 59 0 R /XYZ 62.69291 282.2236 0 ] /Next 92 0 R /Parent 85 0 R /Prev 90 0 R /Title (The solution) >>
endobj
92 0 obj
<< /Dest [ 60 0 R /XYZ 62.69291 226.2236 0 ] /Next 93 0 R /Parent 85 0 R /Prev 91 0 R /Title (A trace decorator) >>
@@ -317,13 +317,13 @@ endobj
<< /Dest [ 64 0 R /XYZ 62.69291 170.4236 0 ] /Next 97 0 R /Parent 85 0 R /Prev 95 0 R /Title (decorator\(cls\)) >>
endobj
97 0 obj
-<< /Dest [ 65 0 R /XYZ 62.69291 276.6236 0 ] /Next 98 0 R /Parent 85 0 R /Prev 96 0 R /Title (contextmanager) >>
+<< /Dest [ 65 0 R /XYZ 62.69291 288.6236 0 ] /Next 98 0 R /Parent 85 0 R /Prev 96 0 R /Title (contextmanager) >>
endobj
98 0 obj
-<< /Dest [ 66 0 R /XYZ 62.69291 312.6236 0 ] /Next 99 0 R /Parent 85 0 R /Prev 97 0 R /Title (The FunctionMaker class) >>
+<< /Dest [ 66 0 R /XYZ 62.69291 300.6236 0 ] /Next 99 0 R /Parent 85 0 R /Prev 97 0 R /Title (The FunctionMaker class) >>
endobj
99 0 obj
-<< /Dest [ 67 0 R /XYZ 62.69291 225.4236 0 ] /Next 100 0 R /Parent 85 0 R /Prev 98 0 R /Title (Getting the source code) >>
+<< /Dest [ 67 0 R /XYZ 62.69291 213.4236 0 ] /Next 100 0 R /Parent 85 0 R /Prev 98 0 R /Title (Getting the source code) >>
endobj
100 0 obj
<< /Dest [ 69 0 R /XYZ 62.69291 374.2236 0 ] /Next 101 0 R /Parent 85 0 R /Prev 99 0 R /Title (Dealing with third-party decorators) >>
@@ -346,7 +346,7 @@ endobj
81 0 R 82 0 R ] /Type /Pages >>
endobj
106 0 obj
-<< /Length 7563 >>
+<< /Length 7565 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
@@ -411,7 +411,7 @@ q
1 0 0 1 91.03937 3 cm
q
0 0 0 rg
-BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (4.0.5 \(2016-02-11\)) Tj T* ET
+BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (4.0.10 \(2016-02-11\)) Tj T* ET
Q
Q
q
@@ -454,7 +454,7 @@ q
q
0 0 .501961 rg
0 0 .501961 RG
-BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (http://pypi.python.org/pypi/decorator/4.0.5) Tj T* ET
+BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (http://pypi.python.org/pypi/decorator/4.0.10) Tj T* ET
Q
Q
q
@@ -784,7 +784,7 @@ Q
endstream
endobj
107 0 obj
-<< /Length 8275 >>
+<< /Length 8201 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
@@ -794,25 +794,25 @@ BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Introduction) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 606.0236 cm
+1 0 0 1 62.69291 594.0236 cm
q
-BT 1 0 0 1 0 122 Tm 1.033876 Tw 12 TL /F1 10 Tf 0 0 0 rg (The decorator module is over ten years old, but still alive and kicking. It is used by several frameworks) Tj T* 0 Tw 1.401098 Tw (\(IPython, scipy, authkit, pylons, pycuda, sugar, ...\) and has been stable for a ) Tj /F4 10 Tf (long ) Tj /F1 10 Tf (time. It is your best) Tj T* 0 Tw 1.50686 Tw (option if you want to preserve the signature of decorated functions in a consistent way across Python) Tj T* 0 Tw .103876 Tw (releases. Version 4.0 is fully compatible with the past, except for one thing: support for Python 2.4 and 2.5) Tj T* 0 Tw 1.399431 Tw (has been dropped. That decision made it possible to use a single code base both for Python 2.X and) Tj T* 0 Tw 6.201984 Tw (Python 3.X. This is a ) Tj /F4 10 Tf (huge ) Tj /F1 10 Tf (bonus, since I could remove over 2,000 lines of duplicated) Tj T* 0 Tw .485366 Tw (documentation/doctests. Having to maintain separate docs for Python 2 and Python 3 effectively stopped) Tj T* 0 Tw .075542 Tw (any development on the module for several years. Moreover, it is now trivial to distribute the module as an) Tj T* 0 Tw .999987 Tw (universal ) Tj 0 0 .501961 rg (wheel ) Tj 0 0 0 rg (since 2to3 is no more required. Since Python 2.5 has been released 9 years ago, I felt) Tj T* 0 Tw .829461 Tw (that it was reasonable to drop the support for it. If you need to support ancient versions of Python, stick) Tj T* 0 Tw (with the decorator module version 3.4.2. This version supports all Python releases from 2.6 up to 3.5.) Tj T* ET
+BT 1 0 0 1 0 134 Tm .201654 Tw 12 TL /F1 10 Tf 0 0 0 rg (The ) Tj /F3 10 Tf 0 0 0 rg (decorator ) Tj /F1 10 Tf 0 0 0 rg (module is over ten years old, but still alive and kicking. It is used by several frameworks) Tj T* 0 Tw 1.401098 Tw (\(IPython, scipy, authkit, pylons, pycuda, sugar, ...\) and has been stable for a ) Tj /F4 10 Tf (long ) Tj /F1 10 Tf (time. It is your best) Tj T* 0 Tw 1.50686 Tw (option if you want to preserve the signature of decorated functions in a consistent way across Python) Tj T* 0 Tw .103876 Tw (releases. Version 4.0 is fully compatible with the past, except for one thing: support for Python 2.4 and 2.5) Tj T* 0 Tw 1.399431 Tw (has been dropped. That decision made it possible to use a single code base both for Python 2.X and) Tj T* 0 Tw 6.201984 Tw (Python 3.X. This is a ) Tj /F4 10 Tf (huge ) Tj /F1 10 Tf (bonus, since I could remove over 2,000 lines of duplicated) Tj T* 0 Tw .485366 Tw (documentation/doctests. Having to maintain separate docs for Python 2 and Python 3 effectively stopped) Tj T* 0 Tw .075542 Tw (any development on the module for several years. Moreover, it is now trivial to distribute the module as an) Tj T* 0 Tw .999987 Tw (universal ) Tj 0 0 .501961 rg (wheel ) Tj 0 0 0 rg (since 2to3 is no more required. Since Python 2.5 has been released 9 years ago, I felt) Tj T* 0 Tw .829461 Tw (that it was reasonable to drop the support for it. If you need to support ancient versions of Python, stick) Tj T* 0 Tw .639985 Tw (with the decorator module version 3.4.2. The current version supports all Python releases from 2.6 up to) Tj T* 0 Tw (3.5.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 573.0236 cm
+1 0 0 1 62.69291 561.0236 cm
q
BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (What's New) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 561.0236 cm
+1 0 0 1 62.69291 549.0236 cm
Q
q
-1 0 0 1 62.69291 561.0236 cm
+1 0 0 1 62.69291 549.0236 cm
Q
q
-1 0 0 1 62.69291 525.0236 cm
+1 0 0 1 62.69291 513.0236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
q
@@ -832,14 +832,14 @@ q
Q
Q
q
-1 0 0 1 62.69291 519.0236 cm
+1 0 0 1 62.69291 507.0236 cm
Q
q
-1 0 0 1 62.69291 495.0236 cm
+1 0 0 1 62.69291 471.0236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
q
-1 0 0 1 6 9 cm
+1 0 0 1 6 21 cm
q
0 0 0 rg
BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL 10.5 0 Td (\177) Tj T* -10.5 0 Td ET
@@ -848,17 +848,17 @@ Q
q
1 0 0 1 23 -3 cm
q
-BT 1 0 0 1 0 14 Tm 3.56998 Tw 12 TL /F2 10 Tf 0 0 0 rg (Packaging improvements ) Tj /F1 10 Tf (The code is now also available in wheel format. Integration with) Tj T* 0 Tw (setuptools is also improved: you can now run tests with the command ) Tj /F3 10 Tf 0 0 0 rg (python) Tj ( ) Tj (setup.py) Tj ( ) Tj (test) Tj /F1 10 Tf 0 0 0 rg (.) Tj T* ET
+BT 1 0 0 1 0 26 Tm 3.56998 Tw 12 TL /F2 10 Tf 0 0 0 rg (Packaging improvements ) Tj /F1 10 Tf (The code is now also available in wheel format. Integration with) Tj T* 0 Tw .965697 Tw (setuptools has improved and you can run the tests with the command ) Tj /F3 10 Tf 0 0 0 rg (python) Tj ( ) Tj (setup.py) Tj ( ) Tj (test) Tj T* 0 Tw /F1 10 Tf 0 0 0 rg (too.) Tj T* ET
Q
Q
q
Q
Q
q
-1 0 0 1 62.69291 489.0236 cm
+1 0 0 1 62.69291 465.0236 cm
Q
q
-1 0 0 1 62.69291 453.0236 cm
+1 0 0 1 62.69291 429.0236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
q
@@ -878,10 +878,10 @@ q
Q
Q
q
-1 0 0 1 62.69291 447.0236 cm
+1 0 0 1 62.69291 423.0236 cm
Q
q
-1 0 0 1 62.69291 351.0236 cm
+1 0 0 1 62.69291 327.0236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
q
@@ -894,36 +894,36 @@ Q
q
1 0 0 1 23 -3 cm
q
-BT 1 0 0 1 0 86 Tm 3.035433 Tw 12 TL /F2 10 Tf 0 0 0 rg (New experimental feature ) Tj /F1 10 Tf (The decorator module now includes an implementation of generic) Tj T* 0 Tw 5.271797 Tw (functions \(sometimes called "multiple dispatch functions"\). The API is designed to mimic) Tj T* 0 Tw 2.276976 Tw /F3 10 Tf 0 0 0 rg (functools.singledispatch ) Tj /F1 10 Tf 0 0 0 rg (\(added in Python 3.4\), but the implementation is much simpler.) Tj T* 0 Tw 1.284597 Tw (Moreover, all decorators involved preserve the signature of the decorated functions. For now, this) Tj T* 0 Tw .518651 Tw (exists mostly to demonstrate the power of the module. In the future it could be enhanced/optimized;) Tj T* 0 Tw .246654 Tw (however, both it and its API could change. \(Such is the fate of experimental features!\) In any case, it) Tj T* 0 Tw 1.029988 Tw (is very short and compact \(less then 100 lines\), so you can extract it for your own use. Take it as) Tj T* 0 Tw (food for thought.) Tj T* ET
+BT 1 0 0 1 0 86 Tm 3.035433 Tw 12 TL /F2 10 Tf 0 0 0 rg (New experimental feature ) Tj /F1 10 Tf (The decorator module now includes an implementation of generic) Tj T* 0 Tw 5.271797 Tw (functions \(sometimes called "multiple dispatch functions"\). The API is designed to mimic) Tj T* 0 Tw 2.276976 Tw /F3 10 Tf 0 0 0 rg (functools.singledispatch ) Tj /F1 10 Tf 0 0 0 rg (\(added in Python 3.4\), but the implementation is much simpler.) Tj T* 0 Tw 1.284597 Tw (Moreover, all decorators involved preserve the signature of the decorated functions. For now, this) Tj T* 0 Tw .518651 Tw (exists mostly to demonstrate the power of the module. In the future it could be enhanced/optimized;) Tj T* 0 Tw 1.30881 Tw (however, its API could change. \(Such is the fate of experimental features!\) In any case, it is very) Tj T* 0 Tw .778988 Tw (short and compact \(less then 100 lines\), so you can extract it for your own use. Take it as food for) Tj T* 0 Tw (thought.) Tj T* ET
Q
Q
q
Q
Q
q
-1 0 0 1 62.69291 351.0236 cm
+1 0 0 1 62.69291 327.0236 cm
Q
q
-1 0 0 1 62.69291 318.0236 cm
+1 0 0 1 62.69291 294.0236 cm
q
BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Usefulness of decorators) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 252.0236 cm
+1 0 0 1 62.69291 228.0236 cm
q
0 0 0 rg
-BT 1 0 0 1 0 50 Tm /F1 10 Tf 12 TL 3.995366 Tw (Python decorators are an interesting example of why syntactic sugar matters. In principle, their) Tj T* 0 Tw .151235 Tw (introduction in Python 2.4 changed nothing, since they do not provide any new functionality which was not) Tj T* 0 Tw 2.238555 Tw (already present in the language. In practice, their introduction has significantly changed the way we) Tj T* 0 Tw .098409 Tw (structure our programs in Python. I believe the change is for the best, and that decorators are a great idea) Tj T* 0 Tw (since:) Tj T* ET
+BT 1 0 0 1 0 50 Tm /F1 10 Tf 12 TL 3.995366 Tw (Python decorators are an interesting example of why syntactic sugar matters. In principle, their) Tj T* 0 Tw .012485 Tw (introduction in Python 2.4 changed nothing, since they did not provide any new functionality which was not) Tj T* 0 Tw 2.238555 Tw (already present in the language. In practice, their introduction has significantly changed the way we) Tj T* 0 Tw .098409 Tw (structure our programs in Python. I believe the change is for the best, and that decorators are a great idea) Tj T* 0 Tw (since:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 246.0236 cm
+1 0 0 1 62.69291 222.0236 cm
Q
q
-1 0 0 1 62.69291 246.0236 cm
+1 0 0 1 62.69291 222.0236 cm
Q
q
-1 0 0 1 62.69291 234.0236 cm
+1 0 0 1 62.69291 210.0236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
q
@@ -944,10 +944,10 @@ q
Q
Q
q
-1 0 0 1 62.69291 228.0236 cm
+1 0 0 1 62.69291 204.0236 cm
Q
q
-1 0 0 1 62.69291 216.0236 cm
+1 0 0 1 62.69291 192.0236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
q
@@ -968,10 +968,10 @@ q
Q
Q
q
-1 0 0 1 62.69291 210.0236 cm
+1 0 0 1 62.69291 186.0236 cm
Q
q
-1 0 0 1 62.69291 198.0236 cm
+1 0 0 1 62.69291 174.0236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
q
@@ -992,10 +992,10 @@ q
Q
Q
q
-1 0 0 1 62.69291 192.0236 cm
+1 0 0 1 62.69291 168.0236 cm
Q
q
-1 0 0 1 62.69291 180.0236 cm
+1 0 0 1 62.69291 156.0236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
q
@@ -1016,10 +1016,10 @@ q
Q
Q
q
-1 0 0 1 62.69291 180.0236 cm
+1 0 0 1 62.69291 156.0236 cm
Q
q
-1 0 0 1 62.69291 138.0236 cm
+1 0 0 1 62.69291 114.0236 cm
q
0 0 0 rg
BT 1 0 0 1 0 26 Tm /F1 10 Tf 12 TL .848876 Tw (Still, as of now, writing custom decorators correctly requires some experience and it is not as easy as it) Tj T* 0 Tw 1.049269 Tw (could be. For instance, typical implementations of decorators involve nested functions, and we all know) Tj T* 0 Tw (that flat is better than nested.) Tj T* ET
@@ -1028,63 +1028,69 @@ Q
q
1 0 0 1 62.69291 84.02362 cm
q
-BT 1 0 0 1 0 38 Tm 1.093735 Tw 12 TL /F1 10 Tf 0 0 0 rg (The aim of the ) Tj /F3 10 Tf 0 0 0 rg (decorator ) Tj /F1 10 Tf 0 0 0 rg (module it to simplify the usage of decorators for the average programmer,) Tj T* 0 Tw 2.456136 Tw (and to popularize decorators by showing various non-trivial examples. Of course, as all techniques,) Tj T* 0 Tw 2.234987 Tw (decorators can be abused \(I have seen that\) and you should not try to solve every problem with a) Tj T* 0 Tw (decorator, just because you can.) Tj T* ET
+BT 1 0 0 1 0 14 Tm 1.093735 Tw 12 TL /F1 10 Tf 0 0 0 rg (The aim of the ) Tj /F3 10 Tf 0 0 0 rg (decorator ) Tj /F1 10 Tf 0 0 0 rg (module it to simplify the usage of decorators for the average programmer, ) Tj T* 0 Tw 2.456136 Tw (and to popularize decorators by showing various non-trivial examples. Of course, as all techniques,) Tj T* 0 Tw ET
Q
Q
endstream
endobj
108 0 obj
-<< /Length 11703 >>
+<< /Length 11857 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
1 0 0 1 62.69291 741.0236 cm
q
+BT 1 0 0 1 0 14 Tm 2.234987 Tw 12 TL /F1 10 Tf 0 0 0 rg (decorators can be abused \(I have seen that\) and you should not try to solve every problem with a) Tj T* 0 Tw (decorator, just because you can.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 711.0236 cm
+q
BT 1 0 0 1 0 14 Tm .13561 Tw 12 TL /F1 10 Tf 0 0 0 rg (You may find the source code for all the examples discussed here in the ) Tj /F3 10 Tf 0 0 0 rg (documentation.py ) Tj /F1 10 Tf 0 0 0 rg (file, which) Tj T* 0 Tw (contains the documentation you are reading in the form of doctests.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 708.0236 cm
+1 0 0 1 62.69291 678.0236 cm
q
BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Definitions) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 666.0236 cm
+1 0 0 1 62.69291 636.0236 cm
q
0 0 0 rg
BT 1 0 0 1 0 26 Tm /F1 10 Tf 12 TL 2.37561 Tw (Technically speaking, any Python object which can be called with one argument can be used as a) Tj T* 0 Tw .472339 Tw (decorator. However, this definition is somewhat too large to be really useful. It is more convenient to split) Tj T* 0 Tw (the generic class of decorators in two subclasses:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 650.0236 cm
+1 0 0 1 62.69291 620.0236 cm
q
-BT 1 0 0 1 0 2 Tm 12 TL /F5 10 Tf 0 0 0 rg (signature-preserving ) Tj /F2 10 Tf (decorators :) Tj T* ET
+BT 1 0 0 1 0 2 Tm 12 TL /F5 10 Tf 0 0 0 rg (signature-preserving ) Tj /F2 10 Tf (decorators:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 635.0236 cm
+1 0 0 1 62.69291 593.0236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
-BT 1 0 0 1 0 2 Tm T* ET
+BT 1 0 0 1 0 14 Tm T* ET
q
1 0 0 1 20 0 cm
q
-BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (Callable objects which accept a function as input and return a function ) Tj /F4 10 Tf (with the same signature) Tj /F1 10 Tf (.) Tj T* ET
+BT 1 0 0 1 0 14 Tm 1.819985 Tw 12 TL /F1 10 Tf 0 0 0 rg (Callable objects which accept a function as input and return a function as output, ) Tj /F4 10 Tf (with the same) Tj T* 0 Tw (signature) Tj /F1 10 Tf (.) Tj T* ET
Q
Q
q
Q
Q
q
-1 0 0 1 62.69291 619.0236 cm
+1 0 0 1 62.69291 577.0236 cm
q
-BT 1 0 0 1 0 2 Tm 12 TL /F5 10 Tf 0 0 0 rg (signature-changing ) Tj /F2 10 Tf (decorators :) Tj T* ET
+BT 1 0 0 1 0 2 Tm 12 TL /F5 10 Tf 0 0 0 rg (signature-changing ) Tj /F2 10 Tf (decorators:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 592.0236 cm
+1 0 0 1 62.69291 550.0236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
BT 1 0 0 1 0 14 Tm T* ET
@@ -1099,50 +1105,50 @@ q
Q
Q
q
-1 0 0 1 62.69291 550.0236 cm
+1 0 0 1 62.69291 508.0236 cm
q
BT 1 0 0 1 0 26 Tm 1.926342 Tw 12 TL /F2 10 Tf 0 0 0 rg (Signature-changing ) Tj /F1 10 Tf (decorators have their use: for instance, the builtin classes ) Tj /F3 10 Tf 0 0 0 rg (staticmethod ) Tj /F1 10 Tf 0 0 0 rg (and) Tj T* 0 Tw 2.051412 Tw /F3 10 Tf 0 0 0 rg (classmethod ) Tj /F1 10 Tf 0 0 0 rg (are in this group. They take functions and return descriptor objects which are neither) Tj T* 0 Tw (functions, nor callables.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 520.0236 cm
+1 0 0 1 62.69291 478.0236 cm
q
BT 1 0 0 1 0 14 Tm .618443 Tw 12 TL /F1 10 Tf 0 0 0 rg (Still, ) Tj /F2 10 Tf (signature-preserving ) Tj /F1 10 Tf (decorators are more common, and easier to reason about. In particular, they) Tj T* 0 Tw (can be composed together, whereas other decorators generally cannot.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 490.0236 cm
+1 0 0 1 62.69291 448.0236 cm
q
0 0 0 rg
BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL .494983 Tw (Writing signature-preserving decorators from scratch is not that obvious, especially if one wants to define) Tj T* 0 Tw (proper decorators that can accept functions with any signature. A simple example will clarify the issue.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 457.0236 cm
+1 0 0 1 62.69291 415.0236 cm
q
BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Statement of the problem) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 415.0236 cm
+1 0 0 1 62.69291 373.0236 cm
q
BT 1 0 0 1 0 26 Tm .351235 Tw 12 TL /F1 10 Tf 0 0 0 rg (A very common use case for decorators is the memoization of functions. A ) Tj /F3 10 Tf 0 0 0 rg (memoize ) Tj /F1 10 Tf 0 0 0 rg (decorator works by) Tj T* 0 Tw .871988 Tw (caching the result of the function call in a dictionary, so that the next time the function is called with the) Tj T* 0 Tw (same input parameters the result is retrieved from the cache and not recomputed.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 373.0236 cm
+1 0 0 1 62.69291 331.0236 cm
q
BT 1 0 0 1 0 26 Tm .28497 Tw 12 TL /F1 10 Tf 0 0 0 rg (There are many implementations of ) Tj /F3 10 Tf 0 0 0 rg (memoize ) Tj /F1 10 Tf 0 0 0 rg (in ) Tj 0 0 .501961 rg (http://www.python.org/moin/PythonDecoratorLibrary) Tj 0 0 0 rg (, but) Tj T* 0 Tw .15311 Tw (they do not preserve the signature. In recent versions of Python you can find a sophisticated ) Tj /F3 10 Tf 0 0 0 rg (lru_cache) Tj T* 0 Tw /F1 10 Tf 0 0 0 rg (decorator in the standard library's ) Tj /F3 10 Tf 0 0 0 rg (functools) Tj /F1 10 Tf 0 0 0 rg (. Here I am just interested in giving an example.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 343.0236 cm
+1 0 0 1 62.69291 301.0236 cm
q
-BT 1 0 0 1 0 14 Tm 1.390751 Tw 12 TL /F1 10 Tf 0 0 0 rg (Consider the following simple implementation \(note that it is generally impossible to ) Tj /F4 10 Tf (correctly ) Tj /F1 10 Tf (memoize) Tj T* 0 Tw (correctly something that depends on non-hashable arguments\):) Tj T* ET
+BT 1 0 0 1 0 14 Tm 1.390751 Tw 12 TL /F1 10 Tf 0 0 0 rg (Consider the following simple implementation \(note that it is generally impossible to ) Tj /F4 10 Tf (correctly ) Tj /F1 10 Tf (memoize) Tj T* 0 Tw (something that depends on non-hashable arguments\):) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 177.8236 cm
+1 0 0 1 62.69291 135.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -1316,27 +1322,27 @@ Q
Q
Q
q
-1 0 0 1 62.69291 133.8236 cm
+1 0 0 1 62.69291 91.82362 cm
q
BT 1 0 0 1 0 26 Tm .50061 Tw 12 TL /F1 10 Tf 0 0 0 rg (Here I used the ) Tj 0 0 .501961 rg (functools.update_wrapper ) Tj 0 0 0 rg (utility, which was added in Python 2.5 to simplify the writing of) Tj T* 0 Tw 2.954524 Tw (decorators. \(Previously, you needed to manually copy the function attributes ) Tj /F3 10 Tf 0 0 0 rg (__name__) Tj /F1 10 Tf 0 0 0 rg (, ) Tj /F3 10 Tf 0 0 0 rg (__doc__) Tj /F1 10 Tf 0 0 0 rg (,) Tj T* 0 Tw /F3 10 Tf 0 0 0 rg (__module__) Tj /F1 10 Tf 0 0 0 rg (, and ) Tj /F3 10 Tf 0 0 0 rg (__dict__ ) Tj /F1 10 Tf 0 0 0 rg (to the decorated function by hand.\)) Tj T* ET
Q
Q
-q
-1 0 0 1 62.69291 115.8236 cm
-q
-0 0 0 rg
-BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Here is an example of usage:) Tj T* ET
-Q
-Q
endstream
endobj
109 0 obj
-<< /Length 12877 >>
+<< /Length 13392 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 691.8236 cm
+1 0 0 1 62.69291 753.0236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Here is an example of usage:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 671.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -1386,20 +1392,20 @@ Q
Q
Q
q
-1 0 0 1 62.69291 647.8236 cm
+1 0 0 1 62.69291 627.8236 cm
q
BT 1 0 0 1 0 26 Tm 1.239318 Tw 12 TL /F1 10 Tf 0 0 0 rg (This works insofar as the decorator accepts functions with generic signatures. Unfortunately, it is ) Tj /F4 10 Tf (not ) Tj /F1 10 Tf (a) Tj T* 0 Tw .33816 Tw (signature-preserving decorator, since ) Tj /F3 10 Tf 0 0 0 rg (memoize_uw ) Tj /F1 10 Tf 0 0 0 rg (generally returns a function with a ) Tj /F4 10 Tf (different signature) Tj T* 0 Tw /F1 10 Tf (from the original.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 629.8236 cm
+1 0 0 1 62.69291 609.8236 cm
q
0 0 0 rg
BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Consider for instance the following case:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 548.6236 cm
+1 0 0 1 62.69291 528.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -1449,13 +1455,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 516.6236 cm
+1 0 0 1 62.69291 496.6236 cm
q
BT 1 0 0 1 0 14 Tm .08936 Tw 12 TL /F1 10 Tf 0 0 0 rg (Here, the original function takes a single argument named ) Tj /F3 10 Tf 0 0 0 rg (x) Tj /F1 10 Tf 0 0 0 rg (, but the decorated function takes any number) Tj T* 0 Tw (of arguments and keyword arguments:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 459.4236 cm
+1 0 0 1 62.69291 439.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -1543,13 +1549,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 415.4236 cm
+1 0 0 1 62.69291 395.4236 cm
q
-BT 1 0 0 1 0 26 Tm 1.781984 Tw 12 TL /F1 10 Tf 0 0 0 rg (This means that introspection tools \(like ) Tj /F3 10 Tf 0 0 0 rg (pydoc) Tj /F1 10 Tf 0 0 0 rg (\) will give false information about the signature of ) Tj /F3 10 Tf 0 0 0 rg (f1) Tj T* 0 Tw 1.192765 Tw /F1 10 Tf 0 0 0 rg (\(unless you are using Python 3.5\)! This is pretty bad: ) Tj /F3 10 Tf 0 0 0 rg (pydoc ) Tj /F1 10 Tf 0 0 0 rg (will tell you that the function accepts the) Tj T* 0 Tw (generic signature ) Tj /F3 10 Tf 0 0 0 rg (*args,) Tj ( ) Tj (**kw) Tj /F1 10 Tf 0 0 0 rg (, but calling the function with more than one argument raises an error:) Tj T* ET
+BT 1 0 0 1 0 26 Tm 1.08061 Tw 12 TL /F1 10 Tf 0 0 0 rg (This means that introspection tools \(like ) Tj /F3 10 Tf 0 0 0 rg (pydoc) Tj /F1 10 Tf 0 0 0 rg (\) will give false information about the signature of ) Tj /F3 10 Tf 0 0 0 rg (f1 ) Tj /F1 10 Tf 0 0 0 rg (--) Tj T* 0 Tw 1.562765 Tw (unless you are using Python 3.5. This is pretty bad: ) Tj /F3 10 Tf 0 0 0 rg (pydoc ) Tj /F1 10 Tf 0 0 0 rg (will tell you that the function accepts the) Tj T* 0 Tw (generic signature ) Tj /F3 10 Tf 0 0 0 rg (*args,) Tj ( ) Tj (**kw) Tj /F1 10 Tf 0 0 0 rg (, but calling the function with more than one argument raises an error:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 346.2236 cm
+1 0 0 1 62.69291 326.2236 cm
q
q
1 0 0 1 0 0 cm
@@ -1629,25 +1635,25 @@ Q
Q
Q
q
-1 0 0 1 62.69291 314.2236 cm
+1 0 0 1 62.69291 294.2236 cm
q
-BT 1 0 0 1 0 14 Tm 2.163307 Tw 12 TL /F1 10 Tf 0 0 0 rg (Notice that ) Tj /F3 10 Tf 0 0 0 rg (inspect.getargspec ) Tj /F1 10 Tf 0 0 0 rg (and ) Tj /F3 10 Tf 0 0 0 rg (inspect.getfullargspec ) Tj /F1 10 Tf 0 0 0 rg (will give the wrong signature.) Tj T* 0 Tw (This even occurs in Python 3.5 \(although both functions were deprecated in that release\).) Tj T* ET
+BT 1 0 0 1 0 14 Tm 2.163307 Tw 12 TL /F1 10 Tf 0 0 0 rg (Notice that ) Tj /F3 10 Tf 0 0 0 rg (inspect.getargspec ) Tj /F1 10 Tf 0 0 0 rg (and ) Tj /F3 10 Tf 0 0 0 rg (inspect.getfullargspec ) Tj /F1 10 Tf 0 0 0 rg (will give the wrong signature.) Tj T* 0 Tw (This even occurs in Python 3.5, although both functions were deprecated in that release.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 281.2236 cm
+1 0 0 1 62.69291 261.2236 cm
q
BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (The solution) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 239.2236 cm
+1 0 0 1 62.69291 219.2236 cm
q
BT 1 0 0 1 0 26 Tm 3.313984 Tw 12 TL /F1 10 Tf 0 0 0 rg (The solution is to provide a generic factory of generators, which hides the complexity of making) Tj T* 0 Tw 3.962976 Tw (signature-preserving decorators from the application programmer. The ) Tj /F3 10 Tf 0 0 0 rg (decorate ) Tj /F1 10 Tf 0 0 0 rg (function in the) Tj T* 0 Tw /F3 10 Tf 0 0 0 rg (decorator ) Tj /F1 10 Tf 0 0 0 rg (module is such a factory:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 206.0236 cm
+1 0 0 1 62.69291 186.0236 cm
q
q
1 0 0 1 0 0 cm
@@ -1681,26 +1687,67 @@ Q
Q
Q
q
-1 0 0 1 62.69291 186.0236 cm
+1 0 0 1 62.69291 166.0236 cm
q
BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 0 rg (decorate ) Tj /F1 10 Tf 0 0 0 rg (takes two arguments:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 168.0236 cm
+1 0 0 1 62.69291 160.0236 cm
+Q
+q
+1 0 0 1 62.69291 160.0236 cm
+Q
+q
+1 0 0 1 62.69291 148.0236 cm
+0 0 0 rg
+BT /F1 10 Tf 12 TL ET
+q
+1 0 0 1 6 -3 cm
q
0 0 0 rg
-BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (1. a caller function describing the functionality of the decorator, and 1. a function to be decorated) Tj T* ET
+BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL 5.66 0 Td (1.) Tj T* -5.66 0 Td ET
Q
Q
q
-1 0 0 1 62.69291 150.0236 cm
+1 0 0 1 23 -3 cm
q
-BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (Then, ) Tj /F3 10 Tf 0 0 0 rg (decorate ) Tj /F1 10 Tf 0 0 0 rg (returns the decorated function.) Tj T* ET
+0 0 0 rg
+BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (a caller function describing the functionality of the decorator, and) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 120.0236 cm
+Q
+Q
+q
+1 0 0 1 62.69291 142.0236 cm
+Q
+q
+1 0 0 1 62.69291 130.0236 cm
+0 0 0 rg
+BT /F1 10 Tf 12 TL ET
+q
+1 0 0 1 6 -3 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL 5.66 0 Td (2.) Tj T* -5.66 0 Td ET
+Q
+Q
+q
+1 0 0 1 23 -3 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (a function to be decorated.) Tj T* ET
+Q
+Q
+q
+Q
+Q
+q
+1 0 0 1 62.69291 130.0236 cm
+Q
+q
+1 0 0 1 62.69291 100.0236 cm
q
BT 1 0 0 1 0 14 Tm .134692 Tw 12 TL /F1 10 Tf 0 0 0 rg (The caller function must have signature ) Tj /F3 10 Tf 0 0 0 rg (\(f,) Tj ( ) Tj (*args,) Tj ( ) Tj (**kw\)) Tj /F1 10 Tf 0 0 0 rg (, and it must call the original function ) Tj /F3 10 Tf 0 0 0 rg (f ) Tj /F1 10 Tf 0 0 0 rg (with) Tj T* 0 Tw (arguments ) Tj /F3 10 Tf 0 0 0 rg (args ) Tj /F1 10 Tf 0 0 0 rg (and ) Tj /F3 10 Tf 0 0 0 rg (kw) Tj /F1 10 Tf 0 0 0 rg (, implementing the wanted capability \(in this case, memoization\):) Tj T* ET
Q
@@ -1709,7 +1756,7 @@ Q
endstream
endobj
110 0 obj
-<< /Length 19363 >>
+<< /Length 19366 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
@@ -2115,7 +2162,7 @@ Q
q
1 0 0 1 62.69291 175.2236 cm
q
-BT 1 0 0 1 0 14 Tm 1.65561 Tw 12 TL /F1 10 Tf 0 0 0 rg (Here an example of how to define a simple ) Tj /F3 10 Tf 0 0 0 rg (trace ) Tj /F1 10 Tf 0 0 0 rg (decorator, which prints a message whenever the) Tj T* 0 Tw (traced function is called:) Tj T* ET
+BT 1 0 0 1 0 14 Tm .969986 Tw 12 TL /F1 10 Tf 0 0 0 rg (Here is an example of how to define a simple ) Tj /F3 10 Tf 0 0 0 rg (trace ) Tj /F1 10 Tf 0 0 0 rg (decorator, which prints a message whenever the) Tj T* 0 Tw (traced function is called:) Tj T* ET
Q
Q
q
@@ -2272,7 +2319,7 @@ Q
endstream
endobj
111 0 obj
-<< /Length 19910 >>
+<< /Length 19970 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
@@ -2709,7 +2756,7 @@ Q
q
1 0 0 1 62.69291 296.0236 cm
q
-BT 1 0 0 1 0 26 Tm .287485 Tw 12 TL /F1 10 Tf 0 0 0 rg (Python 3 introduced the concept of ) Tj 0 0 .501961 rg (function annotations) Tj 0 0 0 rg (: the ability to annotate the signature of a function) Tj T* 0 Tw .85748 Tw (with additional information, stored in a dictionary named ) Tj /F3 10 Tf 0 0 0 rg (__annotations__) Tj /F1 10 Tf 0 0 0 rg (. The decorator module \(as) Tj T* 0 Tw (of release 3.3\) will understand and preserve these annotations.) Tj T* ET
+BT 1 0 0 1 0 26 Tm .287485 Tw 12 TL /F1 10 Tf 0 0 0 rg (Python 3 introduced the concept of ) Tj 0 0 .501961 rg (function annotations) Tj 0 0 0 rg (: the ability to annotate the signature of a function) Tj T* 0 Tw 1.089069 Tw (with additional information, stored in a dictionary named ) Tj /F3 10 Tf 0 0 0 rg (__annotations__) Tj /F1 10 Tf 0 0 0 rg (. The ) Tj /F3 10 Tf 0 0 0 rg (decorator ) Tj /F1 10 Tf 0 0 0 rg (module) Tj T* 0 Tw (\(starting from release 3.3\) will understand and preserve these annotations.) Tj T* ET
Q
Q
q
@@ -3910,7 +3957,7 @@ Q
endstream
endobj
114 0 obj
-<< /Length 18710 >>
+<< /Length 18239 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
@@ -4179,7 +4226,7 @@ BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Here is the minimalistic usage:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 288.6236 cm
+1 0 0 1 62.69291 300.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -4189,35 +4236,23 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 132 re B*
+n -6 -6 468.6898 120 re B*
Q
q
.960784 .960784 .862745 rg
-n 0 108 6 12 re f*
-.960784 .960784 .862745 rg
-n 6 108 6 12 re f*
-.960784 .960784 .862745 rg
-n 12 108 6 12 re f*
-.960784 .960784 .862745 rg
-n 24 108 78 12 re f*
-.960784 .960784 .862745 rg
-n 108 108 6 12 re f*
-.960784 .960784 .862745 rg
-n 120 108 54 12 re f*
-.960784 .960784 .862745 rg
-n 174 108 6 12 re f*
-.960784 .960784 .862745 rg
-n 180 108 36 12 re f*
-.960784 .960784 .862745 rg
-n 216 108 6 12 re f*
-.960784 .960784 .862745 rg
n 0 96 6 12 re f*
.960784 .960784 .862745 rg
n 6 96 6 12 re f*
.960784 .960784 .862745 rg
n 12 96 6 12 re f*
.960784 .960784 .862745 rg
-n 24 96 84 12 re f*
+n 24 96 60 12 re f*
+.960784 .960784 .862745 rg
+n 84 96 6 12 re f*
+.960784 .960784 .862745 rg
+n 90 96 36 12 re f*
+.960784 .960784 .862745 rg
+n 126 96 6 12 re f*
.960784 .960784 .862745 rg
n 0 84 18 12 re f*
.960784 .960784 .862745 rg
@@ -4314,26 +4349,26 @@ n 150 12 36 12 re f*
n 186 12 12 12 re f*
.960784 .960784 .862745 rg
n 0 0 6 12 re f*
-BT 1 0 0 1 0 110 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (futurefactory) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (decorator) Tj 0 0 0 rg (\() Tj 0 0 0 rg (Future) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj .666667 .133333 1 rg (@futurefactory) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F6 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (long_running) Tj 0 0 0 rg (\() Tj 0 0 0 rg (x) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (time) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (sleep) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (.) Tj .4 .4 .4 rg (5) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F6 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (x) Tj 0 0 0 rg T* T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (fut1) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (long_running) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (fut2) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (long_running) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (2) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (fut1) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (result) Tj 0 0 0 rg (\(\)) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (+) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (fut2) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (result) Tj 0 0 0 rg (\(\)) Tj 0 0 0 rg T* .4 .4 .4 rg (3) Tj T* ET
+BT 1 0 0 1 0 98 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj .666667 .133333 1 rg (@decorator) Tj 0 0 0 rg (\() Tj 0 0 0 rg (Future) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F6 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (long_running) Tj 0 0 0 rg (\() Tj 0 0 0 rg (x) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (time) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (sleep) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (.) Tj .4 .4 .4 rg (5) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F6 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (x) Tj 0 0 0 rg T* T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (fut1) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (long_running) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (fut2) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (long_running) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (2) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (fut1) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (result) Tj 0 0 0 rg (\(\)) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (+) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (fut2) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (result) Tj 0 0 0 rg (\(\)) Tj 0 0 0 rg T* .4 .4 .4 rg (3) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 255.6236 cm
+1 0 0 1 62.69291 267.6236 cm
q
BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (contextmanager) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 225.6236 cm
+1 0 0 1 62.69291 237.6236 cm
q
BT 1 0 0 1 0 14 Tm .604147 Tw 12 TL /F1 10 Tf 0 0 0 rg (Python's standard library has the ) Tj /F3 10 Tf 0 0 0 rg (contextmanager ) Tj /F1 10 Tf 0 0 0 rg (decorator, which converts a generator function into) Tj T* 0 Tw (a ) Tj /F3 10 Tf 0 0 0 rg (GeneratorContextManager ) Tj /F1 10 Tf 0 0 0 rg (factory. For instance, if you write this...) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 132.4236 cm
+1 0 0 1 62.69291 144.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -4415,7 +4450,7 @@ Q
Q
Q
q
-1 0 0 1 62.69291 100.4236 cm
+1 0 0 1 62.69291 112.4236 cm
q
BT 1 0 0 1 0 14 Tm 1.221976 Tw 12 TL /F1 10 Tf 0 0 0 rg (...then ) Tj /F3 10 Tf 0 0 0 rg (before_after ) Tj /F1 10 Tf 0 0 0 rg (is a factory function that returns ) Tj /F3 10 Tf 0 0 0 rg (GeneratorContextManager ) Tj /F1 10 Tf 0 0 0 rg (objects, which) Tj T* 0 Tw (provide the use of the ) Tj /F3 10 Tf 0 0 0 rg (with ) Tj /F1 10 Tf 0 0 0 rg (statement:) Tj T* ET
Q
@@ -4424,7 +4459,7 @@ Q
endstream
endobj
115 0 obj
-<< /Length 12198 >>
+<< /Length 10880 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
@@ -4615,7 +4650,7 @@ Q
q
1 0 0 1 23 -3 cm
q
-BT 1 0 0 1 0 26 Tm .085433 Tw 12 TL /F3 10 Tf 0 0 0 rg (GeneratorContextManager ) Tj /F1 10 Tf 0 0 0 rg (objects do not preserve the signature of the decorated functions! The) Tj T* 0 Tw .643615 Tw (decorated ) Tj /F3 10 Tf 0 0 0 rg (hello ) Tj /F1 10 Tf 0 0 0 rg (function above will have the generic signature ) Tj /F3 10 Tf 0 0 0 rg (hello\(*args,) Tj ( ) Tj (**kwargs\)) Tj /F1 10 Tf 0 0 0 rg (, but) Tj T* 0 Tw (fails if called with more than zero arguments.) Tj T* ET
+BT 1 0 0 1 0 26 Tm .085433 Tw 12 TL /F3 10 Tf 0 0 0 rg (GeneratorContextManager ) Tj /F1 10 Tf 0 0 0 rg (objects do not preserve the signature of the decorated functions. The) Tj T* 0 Tw .643615 Tw (decorated ) Tj /F3 10 Tf 0 0 0 rg (hello ) Tj /F1 10 Tf 0 0 0 rg (function above will have the generic signature ) Tj /F3 10 Tf 0 0 0 rg (hello\(*args,) Tj ( ) Tj (**kwargs\)) Tj /F1 10 Tf 0 0 0 rg (, but) Tj T* 0 Tw (fails if called with more than zero arguments.) Tj T* ET
Q
Q
q
@@ -4625,37 +4660,37 @@ q
1 0 0 1 62.69291 390.6236 cm
Q
q
-1 0 0 1 62.69291 324.6236 cm
+1 0 0 1 62.69291 312.6236 cm
q
-BT 1 0 0 1 0 50 Tm 3.311797 Tw 12 TL /F1 10 Tf 0 0 0 rg (For these reasons, decorator module \(as of release 3.4\) offers a ) Tj /F3 10 Tf 0 0 0 rg (decorator.contextmanager) Tj T* 0 Tw 1.127318 Tw /F1 10 Tf 0 0 0 rg (decorator that solves both problems, ) Tj /F4 10 Tf (and ) Tj /F1 10 Tf (works in all supported Python versions. Its usage is identical,) Tj T* 0 Tw .39664 Tw (and factories decorated with ) Tj /F3 10 Tf 0 0 0 rg (decorator.contextmanager ) Tj /F1 10 Tf 0 0 0 rg (will return instances of ) Tj /F3 10 Tf 0 0 0 rg (ContextManager) Tj /F1 10 Tf 0 0 0 rg (,) Tj T* 0 Tw 1.802196 Tw (a subclass of the standard library's ) Tj /F3 10 Tf 0 0 0 rg (contextlib.GeneratorContextManager ) Tj /F1 10 Tf 0 0 0 rg (class. The subclass) Tj T* 0 Tw (includes an improved ) Tj /F3 10 Tf 0 0 0 rg (__call__ ) Tj /F1 10 Tf 0 0 0 rg (method, which acts as a signature-preserving decorator.) Tj T* ET
+BT 1 0 0 1 0 62 Tm 12.45089 Tw 12 TL /F1 10 Tf 0 0 0 rg (For these reasons, the ) Tj /F4 10 Tf 0 0 0 rg (decorator ) Tj /F1 10 Tf 0 0 0 rg (module, starting from release 3.4, offers a) Tj T* 0 Tw .774524 Tw /F3 10 Tf 0 0 0 rg (decorator.contextmanager ) Tj /F1 10 Tf 0 0 0 rg (decorator that solves both problems, ) Tj /F4 10 Tf (and ) Tj /F1 10 Tf (works in all supported Python) Tj T* 0 Tw .989069 Tw (versions. Its usage is identical, and factories decorated with ) Tj /F3 10 Tf 0 0 0 rg (decorator.contextmanager ) Tj /F1 10 Tf 0 0 0 rg (will return) Tj T* 0 Tw 21.31872 Tw (instances of ) Tj /F3 10 Tf 0 0 0 rg (ContextManager) Tj /F1 10 Tf 0 0 0 rg (, a subclass of the standard library's) Tj T* 0 Tw 3.514252 Tw /F3 10 Tf 0 0 0 rg (contextlib.GeneratorContextManager ) Tj /F1 10 Tf 0 0 0 rg (class. The subclass includes an improved ) Tj /F3 10 Tf 0 0 0 rg (__call__) Tj T* 0 Tw /F1 10 Tf 0 0 0 rg (method, which acts as a signature-preserving decorator.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 291.6236 cm
+1 0 0 1 62.69291 279.6236 cm
q
BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (The ) Tj /F3 17.5 Tf 0 0 0 rg (FunctionMaker ) Tj /F2 17.5 Tf 0 0 0 rg (class) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 249.6236 cm
+1 0 0 1 62.69291 237.6236 cm
q
BT 1 0 0 1 0 26 Tm 1.567126 Tw 12 TL /F1 10 Tf 0 0 0 rg (You may wonder how the functionality of the ) Tj /F3 10 Tf 0 0 0 rg (decorator ) Tj /F1 10 Tf 0 0 0 rg (module is implemented. The basic building) Tj T* 0 Tw .233318 Tw (block is a ) Tj /F3 10 Tf 0 0 0 rg (FunctionMaker ) Tj /F1 10 Tf 0 0 0 rg (class. It generates on-the-fly functions with a given name and signature from) Tj T* 0 Tw (a function template passed as a string.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 207.6236 cm
+1 0 0 1 62.69291 195.6236 cm
q
BT 1 0 0 1 0 26 Tm .612126 Tw 12 TL /F1 10 Tf 0 0 0 rg (If you're just writing ordinary decorators, then you probably won't need to use ) Tj /F3 10 Tf 0 0 0 rg (FunctionMaker ) Tj /F1 10 Tf 0 0 0 rg (directly.) Tj T* 0 Tw .603516 Tw (But in some circumstances, it can be handy. You will see an example shortly--in the implementation of a) Tj T* 0 Tw (cool decorator utility \() Tj /F3 10 Tf 0 0 0 rg (decorator_apply) Tj /F1 10 Tf 0 0 0 rg (\).) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 165.6236 cm
+1 0 0 1 62.69291 153.6236 cm
q
BT 1 0 0 1 0 26 Tm .865814 Tw 12 TL /F3 10 Tf 0 0 0 rg (FunctionMaker ) Tj /F1 10 Tf 0 0 0 rg (provides the ) Tj /F3 10 Tf 0 0 0 rg (.create ) Tj /F1 10 Tf 0 0 0 rg (classmethod, which accepts the ) Tj /F4 10 Tf (name) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (signature) Tj /F1 10 Tf (, and ) Tj /F4 10 Tf (body ) Tj /F1 10 Tf (of) Tj T* 0 Tw .637485 Tw (the function you want to generate, as well as the execution environment where the function is generated) Tj T* 0 Tw (by ) Tj /F3 10 Tf 0 0 0 rg (exec) Tj /F1 10 Tf 0 0 0 rg (.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 147.6236 cm
+1 0 0 1 62.69291 135.6236 cm
q
0 0 0 rg
BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Here's an example:) Tj T* ET
@@ -4672,88 +4707,50 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 60 re B*
+n -6 -6 468.6898 48 re B*
Q
q
.960784 .960784 .862745 rg
-n 0 36 6 12 re f*
-.960784 .960784 .862745 rg
-n 6 36 6 12 re f*
-.960784 .960784 .862745 rg
-n 12 36 6 12 re f*
-.960784 .960784 .862745 rg
-n 24 36 18 12 re f*
-.960784 .960784 .862745 rg
-n 48 36 6 12 re f*
-.960784 .960784 .862745 rg
-n 54 36 6 12 re f*
-.960784 .960784 .862745 rg
-n 60 36 6 12 re f*
-.960784 .960784 .862745 rg
-n 66 36 24 12 re f*
-.960784 .960784 .862745 rg
-n 90 36 6 12 re f*
-.960784 .960784 .862745 rg
-n 102 36 12 12 re f*
-.960784 .960784 .862745 rg
-n 114 36 12 12 re f*
-.960784 .960784 .862745 rg
-n 126 36 12 12 re f*
-.960784 .960784 .862745 rg
-n 144 36 222 12 re f*
-.960784 .960784 .862745 rg
-n 0 24 18 12 re f*
-.960784 .960784 .862745 rg
-n 48 24 30 12 re f*
-.960784 .960784 .862745 rg
-n 78 24 6 12 re f*
-.960784 .960784 .862745 rg
-n 84 24 24 12 re f*
-.960784 .960784 .862745 rg
-n 108 24 6 12 re f*
-.960784 .960784 .862745 rg
-n 120 24 12 12 re f*
-.960784 .960784 .862745 rg
-n 132 24 6 12 re f*
+n 0 24 6 12 re f*
.960784 .960784 .862745 rg
-n 0 0 6 12 re f*
+n 6 24 6 12 re f*
.960784 .960784 .862745 rg
-n 6 0 6 12 re f*
+n 12 24 6 12 re f*
.960784 .960784 .862745 rg
-n 12 0 6 12 re f*
+n 24 24 18 12 re f*
.960784 .960784 .862745 rg
-n 24 0 12 12 re f*
+n 48 24 6 12 re f*
.960784 .960784 .862745 rg
-n 42 0 6 12 re f*
+n 54 24 6 12 re f*
.960784 .960784 .862745 rg
-n 54 0 78 12 re f*
+n 60 24 6 12 re f*
.960784 .960784 .862745 rg
-n 132 0 6 12 re f*
+n 66 24 24 12 re f*
.960784 .960784 .862745 rg
-n 138 0 36 12 re f*
+n 90 24 6 12 re f*
.960784 .960784 .862745 rg
-n 174 0 6 12 re f*
+n 102 24 12 12 re f*
.960784 .960784 .862745 rg
-n 180 0 60 12 re f*
+n 114 24 12 12 re f*
.960784 .960784 .862745 rg
-n 240 0 6 12 re f*
+n 126 24 12 12 re f*
.960784 .960784 .862745 rg
-n 252 0 54 12 re f*
+n 144 24 222 12 re f*
.960784 .960784 .862745 rg
-n 306 0 6 12 re f*
+n 0 12 18 12 re f*
.960784 .960784 .862745 rg
-n 318 0 24 12 re f*
+n 48 12 30 12 re f*
.960784 .960784 .862745 rg
-n 342 0 6 12 re f*
+n 78 12 6 12 re f*
.960784 .960784 .862745 rg
-n 348 0 6 12 re f*
+n 84 12 24 12 re f*
.960784 .960784 .862745 rg
-n 354 0 6 12 re f*
+n 108 12 6 12 re f*
.960784 .960784 .862745 rg
-n 360 0 6 12 re f*
+n 120 12 12 12 re f*
.960784 .960784 .862745 rg
-n 366 0 12 12 re f*
-BT 1 0 0 1 0 38 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F6 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (f) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\):) Tj 0 0 0 rg ( ) Tj /F7 10 Tf .25098 .501961 .501961 rg (# a function with a generic signature) Tj /F3 10 Tf 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F6 10 Tf 0 .501961 0 rg (print) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (f1) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (FunctionMaker) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (create) Tj 0 0 0 rg (\() Tj .729412 .129412 .129412 rg ('f1\(a, b\)') Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ('f\(a, b\)') Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (dict) Tj 0 0 0 rg (\() Tj 0 0 0 rg (f) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg (f) Tj 0 0 0 rg (\)\)) Tj 0 0 0 rg T* ET
+n 132 12 6 12 re f*
+BT 1 0 0 1 0 26 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F6 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (f) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\):) Tj 0 0 0 rg ( ) Tj /F7 10 Tf .25098 .501961 .501961 rg (# a function with a generic signature) Tj /F3 10 Tf 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F6 10 Tf 0 .501961 0 rg (print) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* T* ET
Q
Q
Q
@@ -4763,11 +4760,11 @@ Q
endstream
endobj
116 0 obj
-<< /Length 16035 >>
+<< /Length 17445 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 727.8236 cm
+1 0 0 1 62.69291 715.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -4777,10 +4774,48 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 36 re B*
+n -6 -6 468.6898 48 re B*
Q
q
.960784 .960784 .862745 rg
+n 0 24 6 12 re f*
+.960784 .960784 .862745 rg
+n 6 24 6 12 re f*
+.960784 .960784 .862745 rg
+n 12 24 6 12 re f*
+.960784 .960784 .862745 rg
+n 24 24 12 12 re f*
+.960784 .960784 .862745 rg
+n 42 24 6 12 re f*
+.960784 .960784 .862745 rg
+n 54 24 78 12 re f*
+.960784 .960784 .862745 rg
+n 132 24 6 12 re f*
+.960784 .960784 .862745 rg
+n 138 24 36 12 re f*
+.960784 .960784 .862745 rg
+n 174 24 6 12 re f*
+.960784 .960784 .862745 rg
+n 180 24 60 12 re f*
+.960784 .960784 .862745 rg
+n 240 24 6 12 re f*
+.960784 .960784 .862745 rg
+n 252 24 54 12 re f*
+.960784 .960784 .862745 rg
+n 306 24 6 12 re f*
+.960784 .960784 .862745 rg
+n 318 24 24 12 re f*
+.960784 .960784 .862745 rg
+n 342 24 6 12 re f*
+.960784 .960784 .862745 rg
+n 348 24 6 12 re f*
+.960784 .960784 .862745 rg
+n 354 24 6 12 re f*
+.960784 .960784 .862745 rg
+n 360 24 6 12 re f*
+.960784 .960784 .862745 rg
+n 366 24 12 12 re f*
+.960784 .960784 .862745 rg
n 0 12 6 12 re f*
.960784 .960784 .862745 rg
n 6 12 6 12 re f*
@@ -4810,32 +4845,32 @@ n 24 0 6 12 re f*
n 30 0 6 12 re f*
.960784 .960784 .862745 rg
n 42 0 12 12 re f*
-BT 1 0 0 1 0 14 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (f1) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (,) Tj .4 .4 .4 rg (2) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* 0 0 0 rg (\() Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (2) Tj 0 0 0 rg (\)) Tj 0 0 0 rg ( ) Tj 0 0 0 rg ({}) Tj T* ET
+BT 1 0 0 1 0 26 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (f1) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (FunctionMaker) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (create) Tj 0 0 0 rg (\() Tj .729412 .129412 .129412 rg ('f1\(a, b\)') Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ('f\(a, b\)') Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (dict) Tj 0 0 0 rg (\() Tj 0 0 0 rg (f) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg (f) Tj 0 0 0 rg (\)\)) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (f1) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (,) Tj .4 .4 .4 rg (2) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* 0 0 0 rg (\() Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (2) Tj 0 0 0 rg (\)) Tj 0 0 0 rg ( ) Tj 0 0 0 rg ({}) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 695.8236 cm
+1 0 0 1 62.69291 683.8236 cm
q
BT 1 0 0 1 0 14 Tm .116098 Tw 12 TL /F1 10 Tf 0 0 0 rg (It is important to notice that the function body is interpolated before being executed; ) Tj /F2 10 Tf (be careful ) Tj /F1 10 Tf (with the ) Tj /F3 10 Tf 0 0 0 rg (%) Tj T* 0 Tw /F1 10 Tf 0 0 0 rg (sign!) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 653.8236 cm
+1 0 0 1 62.69291 641.8236 cm
q
BT 1 0 0 1 0 26 Tm .22816 Tw 12 TL /F3 10 Tf 0 0 0 rg (FunctionMaker.create ) Tj /F1 10 Tf 0 0 0 rg (also accepts keyword arguments. The keyword arguments are attached to the) Tj T* 0 Tw 3.385984 Tw (generated function. This is useful if you want to set some function attributes \(e.g., the docstring) Tj T* 0 Tw /F3 10 Tf 0 0 0 rg (__doc__) Tj /F1 10 Tf 0 0 0 rg (\).) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 623.8236 cm
+1 0 0 1 62.69291 611.8236 cm
q
BT 1 0 0 1 0 14 Tm .419984 Tw 12 TL /F1 10 Tf 0 0 0 rg (For debugging/introspection purposes, it may be useful to see the source code of the generated function.) Tj T* 0 Tw (To do this, just pass ) Tj /F3 10 Tf 0 0 0 rg (addsource=True) Tj /F1 10 Tf 0 0 0 rg (, and the generated function will get a ) Tj /F3 10 Tf 0 0 0 rg (__source__ ) Tj /F1 10 Tf 0 0 0 rg (attribute:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 530.6236 cm
+1 0 0 1 62.69291 518.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -4953,31 +4988,31 @@ Q
Q
Q
q
-1 0 0 1 62.69291 498.6236 cm
+1 0 0 1 62.69291 486.6236 cm
q
BT 1 0 0 1 0 14 Tm 1.344985 Tw 12 TL /F1 10 Tf 0 0 0 rg (The first argument to ) Tj /F3 10 Tf 0 0 0 rg (FunctionMaker.create ) Tj /F1 10 Tf 0 0 0 rg (can be a string \(as above\), or a function. This is the) Tj T* 0 Tw (most common usage, since you typically decorate pre-existing functions.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 468.6236 cm
+1 0 0 1 62.69291 456.6236 cm
q
BT 1 0 0 1 0 14 Tm .955366 Tw 12 TL /F1 10 Tf 0 0 0 rg (If you're writing a framework, however, you may want to use ) Tj /F3 10 Tf 0 0 0 rg (FunctionMaker.create ) Tj /F1 10 Tf 0 0 0 rg (directly, rather) Tj T* 0 Tw (than ) Tj /F3 10 Tf 0 0 0 rg (decorator) Tj /F1 10 Tf 0 0 0 rg (, because it gives you direct access to the body of the generated function.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 426.6236 cm
+1 0 0 1 62.69291 414.6236 cm
q
BT 1 0 0 1 0 26 Tm .494985 Tw 12 TL /F1 10 Tf 0 0 0 rg (For instance, suppose you want to instrument the ) Tj /F3 10 Tf 0 0 0 rg (__init__ ) Tj /F1 10 Tf 0 0 0 rg (methods of a set of classes, by preserving) Tj T* 0 Tw .66881 Tw (their signature. \(This use case is not made up. This is done by SQAlchemy, and other frameworks, too.\)) Tj T* 0 Tw (Here is what happens:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 420.6236 cm
+1 0 0 1 62.69291 408.6236 cm
Q
q
-1 0 0 1 62.69291 420.6236 cm
+1 0 0 1 62.69291 408.6236 cm
Q
q
-1 0 0 1 62.69291 384.6236 cm
+1 0 0 1 62.69291 372.6236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
q
@@ -4997,10 +5032,10 @@ q
Q
Q
q
-1 0 0 1 62.69291 378.6236 cm
+1 0 0 1 62.69291 366.6236 cm
Q
q
-1 0 0 1 62.69291 354.6236 cm
+1 0 0 1 62.69291 342.6236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
q
@@ -5020,10 +5055,10 @@ q
Q
Q
q
-1 0 0 1 62.69291 348.6236 cm
+1 0 0 1 62.69291 336.6236 cm
Q
q
-1 0 0 1 62.69291 336.6236 cm
+1 0 0 1 62.69291 324.6236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
q
@@ -5043,16 +5078,16 @@ q
Q
Q
q
-1 0 0 1 62.69291 336.6236 cm
+1 0 0 1 62.69291 324.6236 cm
Q
q
-1 0 0 1 62.69291 306.6236 cm
+1 0 0 1 62.69291 294.6236 cm
q
BT 1 0 0 1 0 14 Tm 6.134147 Tw 12 TL /F2 10 Tf 0 0 0 rg (NOTE: ) Tj /F1 10 Tf (You should not pass signature strings with default arguments \(e.g., something like) Tj T* 0 Tw /F3 10 Tf 0 0 0 rg ('f1\(a,) Tj ( ) Tj (b=None\)') Tj /F1 10 Tf 0 0 0 rg (\). Just pass ) Tj /F3 10 Tf 0 0 0 rg ('f1\(a,) Tj ( ) Tj (b\)') Tj /F1 10 Tf 0 0 0 rg (, followed by a tuple of defaults:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 237.4236 cm
+1 0 0 1 62.69291 225.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -5192,19 +5227,19 @@ Q
Q
Q
q
-1 0 0 1 62.69291 204.4236 cm
+1 0 0 1 62.69291 192.4236 cm
q
BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Getting the source code) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 150.4236 cm
+1 0 0 1 62.69291 138.4236 cm
q
BT 1 0 0 1 0 38 Tm 4.73664 Tw 12 TL /F1 10 Tf 0 0 0 rg (Internally, ) Tj /F3 10 Tf 0 0 0 rg (FunctionMaker.create ) Tj /F1 10 Tf 0 0 0 rg (uses ) Tj /F3 10 Tf 0 0 0 rg (exec ) Tj /F1 10 Tf 0 0 0 rg (to generate the decorated function. Therefore) Tj T* 0 Tw 1.488555 Tw /F3 10 Tf 0 0 0 rg (inspect.getsource ) Tj /F1 10 Tf 0 0 0 rg (will not work for decorated functions. In IPython, this means that the usual ) Tj /F3 10 Tf 0 0 0 rg (??) Tj T* 0 Tw 11.06361 Tw /F1 10 Tf 0 0 0 rg (trick will give you the \(right on the spot\) message ) Tj /F3 10 Tf 0 0 0 rg (Dynamically) Tj ( ) Tj (generated) Tj T* 0 Tw (function.) Tj ( ) Tj (No) Tj ( ) Tj (source) Tj ( ) Tj (code) Tj ( ) Tj (available) Tj /F1 10 Tf 0 0 0 rg (.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 108.4236 cm
+1 0 0 1 62.69291 96.42362 cm
q
BT 1 0 0 1 0 26 Tm 1.43284 Tw 12 TL /F1 10 Tf 0 0 0 rg (In the past, I have considered this acceptable, since ) Tj /F3 10 Tf 0 0 0 rg (inspect.getsource ) Tj /F1 10 Tf 0 0 0 rg (does not really work with) Tj T* 0 Tw .143059 Tw ("regular" decorators. In those cases, ) Tj /F3 10 Tf 0 0 0 rg (inspect.getsource ) Tj /F1 10 Tf 0 0 0 rg (gives you the wrapper source code, which is) Tj T* 0 Tw (probably not what you want:) Tj T* ET
Q
@@ -6130,7 +6165,7 @@ Q
endstream
endobj
119 0 obj
-<< /Length 12134 >>
+<< /Length 12130 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
@@ -6278,7 +6313,7 @@ Q
q
1 0 0 1 62.69291 522.8236 cm
q
-BT 1 0 0 1 0 26 Tm 1.494983 Tw 12 TL /F1 10 Tf 0 0 0 rg (There has been talk of implementing multiple dispatch functions \(i.e. "generic functions"\) in Python for) Tj T* 0 Tw .475542 Tw (over ten years. Last year, something concrete was done for the first time--and as of Python 3.4, we have) Tj T* 0 Tw (the decorator ) Tj /F3 10 Tf 0 0 0 rg (functools.singledispatch ) Tj /F1 10 Tf 0 0 0 rg (to implement generic functions!) Tj T* ET
+BT 1 0 0 1 0 26 Tm 1.494983 Tw 12 TL /F1 10 Tf 0 0 0 rg (There has been talk of implementing multiple dispatch functions \(i.e. "generic functions"\) in Python for) Tj T* 0 Tw .596303 Tw (over ten years. Last year, something concrete was done for the first time. As of Python 3.4, we have the) Tj T* 0 Tw (decorator ) Tj /F3 10 Tf 0 0 0 rg (functools.singledispatch ) Tj /F1 10 Tf 0 0 0 rg (to implement generic functions!) Tj T* ET
Q
Q
q
@@ -7433,7 +7468,7 @@ Q
endstream
endobj
122 0 obj
-<< /Length 13209 >>
+<< /Length 13212 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
@@ -7711,7 +7746,7 @@ Q
q
1 0 0 1 62.69291 297.0236 cm
q
-BT 1 0 0 1 0 26 Tm .001567 Tw 12 TL /F1 10 Tf 0 0 0 rg (Since in Python it is possible to consider any instance of ) Tj /F3 10 Tf 0 0 0 rg (ABCMeta ) Tj /F1 10 Tf 0 0 0 rg (as a virtual ancestor of any other class) Tj T* 0 Tw .21152 Tw (\(it is enough to register it as ) Tj /F3 10 Tf 0 0 0 rg (ancestor.register\(cls\)) Tj /F1 10 Tf 0 0 0 rg (\), any implementation of generic functions must) Tj T* 0 Tw (take virtual ancestors into account.) Tj T* ET
+BT 1 0 0 1 0 26 Tm .001567 Tw 12 TL /F1 10 Tf 0 0 0 rg (Since in Python it is possible to consider any instance of ) Tj /F3 10 Tf 0 0 0 rg (ABCMeta ) Tj /F1 10 Tf 0 0 0 rg (as a virtual ancestor of any other class) Tj T* 0 Tw .21152 Tw (\(it is enough to register it as ) Tj /F3 10 Tf 0 0 0 rg (ancestor.register\(cls\)) Tj /F1 10 Tf 0 0 0 rg (\), any implementation of generic functions must) Tj T* 0 Tw (be aware of the registration mechanism.) Tj T* ET
Q
Q
q
@@ -7859,7 +7894,7 @@ Q
endstream
endobj
123 0 obj
-<< /Length 11527 >>
+<< /Length 12132 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
@@ -7917,7 +7952,7 @@ Q
q
1 0 0 1 62.69291 663.8236 cm
q
-BT 1 0 0 1 0 14 Tm .530697 Tw 12 TL /F1 10 Tf 0 0 0 rg (The current implementation \(and ) Tj /F3 10 Tf 0 0 0 rg (functools.singledispatch ) Tj /F1 10 Tf 0 0 0 rg (too\) is able to discern that a ) Tj /F3 10 Tf 0 0 0 rg (Set ) Tj /F1 10 Tf 0 0 0 rg (is a) Tj T* 0 Tw /F3 10 Tf 0 0 0 rg (Sized ) Tj /F1 10 Tf 0 0 0 rg (object, so it uses the more specific implementation for ) Tj /F3 10 Tf 0 0 0 rg (Set) Tj /F1 10 Tf 0 0 0 rg (:) Tj T* ET
+BT 1 0 0 1 0 14 Tm .530697 Tw 12 TL /F1 10 Tf 0 0 0 rg (The current implementation \(and ) Tj /F3 10 Tf 0 0 0 rg (functools.singledispatch ) Tj /F1 10 Tf 0 0 0 rg (too\) is able to discern that a ) Tj /F3 10 Tf 0 0 0 rg (Set ) Tj /F1 10 Tf 0 0 0 rg (is a) Tj T* 0 Tw /F3 10 Tf 0 0 0 rg (Sized ) Tj /F1 10 Tf 0 0 0 rg (object, by looking at the class registry, so it uses the more specific implementation for ) Tj /F3 10 Tf 0 0 0 rg (Set) Tj /F1 10 Tf 0 0 0 rg (:) Tj T* ET
Q
Q
q
@@ -7961,17 +7996,11 @@ Q
q
1 0 0 1 62.69291 574.6236 cm
q
-BT 1 0 0 1 0 26 Tm 1.687765 Tw 12 TL /F1 10 Tf 0 0 0 rg (Sometimes it is not clear how to dispatch. For instance, consider the class ) Tj /F3 10 Tf 0 0 0 rg (C) Tj /F1 10 Tf 0 0 0 rg (: it is registered both as) Tj T* 0 Tw 5.08664 Tw /F3 10 Tf 0 0 0 rg (collections.Iterable ) Tj /F1 10 Tf 0 0 0 rg (and ) Tj /F3 10 Tf 0 0 0 rg (collections.Sized) Tj /F1 10 Tf 0 0 0 rg (, and defines the generic function ) Tj /F3 10 Tf 0 0 0 rg (g ) Tj /F1 10 Tf 0 0 0 rg (with) Tj T* 0 Tw (implementations for both ) Tj /F3 10 Tf 0 0 0 rg (collections.Iterable) Tj /F1 10 Tf 0 0 0 rg ( ) Tj /F4 10 Tf (and) Tj /F1 10 Tf ( ) Tj /F3 10 Tf 0 0 0 rg (collections.Sized) Tj /F1 10 Tf 0 0 0 rg (.) Tj T* ET
+BT 1 0 0 1 0 26 Tm 3.503735 Tw 12 TL /F1 10 Tf 0 0 0 rg (Sometimes it is not clear how to dispatch. For instance, consider a class ) Tj /F3 10 Tf 0 0 0 rg (C ) Tj /F1 10 Tf 0 0 0 rg (registered both as) Tj T* 0 Tw 6.013307 Tw /F3 10 Tf 0 0 0 rg (collections.Iterable ) Tj /F1 10 Tf 0 0 0 rg (and ) Tj /F3 10 Tf 0 0 0 rg (collections.Sized) Tj /F1 10 Tf 0 0 0 rg (, and defines a generic function ) Tj /F3 10 Tf 0 0 0 rg (g ) Tj /F1 10 Tf 0 0 0 rg (with) Tj T* 0 Tw (implementations for both ) Tj /F3 10 Tf 0 0 0 rg (collections.Iterable) Tj /F1 10 Tf 0 0 0 rg ( ) Tj /F4 10 Tf (and) Tj /F1 10 Tf ( ) Tj /F3 10 Tf 0 0 0 rg (collections.Sized) Tj /F1 10 Tf 0 0 0 rg (:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 544.6236 cm
-q
-BT 1 0 0 1 0 14 Tm .052651 Tw 12 TL /F1 10 Tf 0 0 0 rg (It is impossible to decide which implementation to use, since the ancestors are independent. The following) Tj T* 0 Tw (function will raise a ) Tj /F3 10 Tf 0 0 0 rg (RuntimeError ) Tj /F1 10 Tf 0 0 0 rg (when called:) Tj T* ET
-Q
-Q
-q
-1 0 0 1 62.69291 331.4236 cm
+1 0 0 1 62.69291 361.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -8097,26 +8126,26 @@ Q
Q
Q
q
-1 0 0 1 62.69291 299.4236 cm
+1 0 0 1 62.69291 317.4236 cm
q
-BT 1 0 0 1 0 14 Tm .745433 Tw 12 TL /F1 10 Tf 0 0 0 rg (This is consistent with the "refuse the temptation to guess" philosophy. ) Tj /F3 10 Tf 0 0 0 rg (functools.singledispatch) Tj T* 0 Tw /F1 10 Tf 0 0 0 rg (would raise a similar error.) Tj T* ET
+BT 1 0 0 1 0 26 Tm .052651 Tw 12 TL /F1 10 Tf 0 0 0 rg (It is impossible to decide which implementation to use, since the ancestors are independent. The following) Tj T* 0 Tw 1.397318 Tw (function will raise a ) Tj /F3 10 Tf 0 0 0 rg (RuntimeError ) Tj /F1 10 Tf 0 0 0 rg (when called. This is consistent with the "refuse the temptation to) Tj T* 0 Tw (guess" philosophy. ) Tj /F3 10 Tf 0 0 0 rg (functools.singledispatch ) Tj /F1 10 Tf 0 0 0 rg (would raise a similar error.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 269.4236 cm
+1 0 0 1 62.69291 287.4236 cm
q
0 0 0 rg
BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL .01104 Tw (It would be easy to rely on the order of registration to decide the precedence order. This is reasonable, but) Tj T* 0 Tw (also fragile:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 263.4236 cm
+1 0 0 1 62.69291 281.4236 cm
Q
q
-1 0 0 1 62.69291 263.4236 cm
+1 0 0 1 62.69291 281.4236 cm
Q
q
-1 0 0 1 62.69291 239.4236 cm
+1 0 0 1 62.69291 257.4236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
q
@@ -8137,10 +8166,10 @@ q
Q
Q
q
-1 0 0 1 62.69291 233.4236 cm
+1 0 0 1 62.69291 251.4236 cm
Q
q
-1 0 0 1 62.69291 209.4236 cm
+1 0 0 1 62.69291 227.4236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
q
@@ -8161,36 +8190,64 @@ q
Q
Q
q
-1 0 0 1 62.69291 209.4236 cm
+1 0 0 1 62.69291 227.4236 cm
Q
q
-1 0 0 1 62.69291 179.4236 cm
+1 0 0 1 62.69291 197.4236 cm
q
BT 1 0 0 1 0 14 Tm .539431 Tw 12 TL /F1 10 Tf 0 0 0 rg (So the ) Tj /F3 10 Tf 0 0 0 rg (decorator ) Tj /F1 10 Tf 0 0 0 rg (module prefers to raise an error in the face of ambiguity. This is the same approach) Tj T* 0 Tw (taken by the standard library.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 125.4236 cm
+1 0 0 1 62.69291 143.4236 cm
q
BT 1 0 0 1 0 38 Tm .143516 Tw 12 TL /F1 10 Tf 0 0 0 rg (However, it should be noted that the ) Tj /F4 10 Tf (dispatch algorithm ) Tj /F1 10 Tf (used by the decorator module is different from the) Tj T* 0 Tw .476098 Tw (one used by the standard library, so in certain cases you will get different answers. The difference is that) Tj T* 0 Tw 1.98816 Tw /F3 10 Tf 0 0 0 rg (functools.singledispatch ) Tj /F1 10 Tf 0 0 0 rg (tries to insert the virtual ancestors ) Tj /F4 10 Tf (before ) Tj /F1 10 Tf (the base classes, whereas) Tj T* 0 Tw /F3 10 Tf 0 0 0 rg (decorator.dispatch_on ) Tj /F1 10 Tf 0 0 0 rg (tries to insert them ) Tj /F4 10 Tf (after ) Tj /F1 10 Tf (the base classes.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 107.4236 cm
+1 0 0 1 62.69291 125.4236 cm
q
0 0 0 rg
BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Here's an example that shows the difference:) Tj T* ET
Q
Q
+q
+1 0 0 1 62.69291 80.22362 cm
+q
+q
+1 0 0 1 0 0 cm
+q
+1 0 0 1 6.6 6.6 cm
+q
+.662745 .662745 .662745 RG
+.5 w
+.960784 .960784 .862745 rg
+n -6 -6 468.6898 36 re B*
+Q
+q
+.960784 .960784 .862745 rg
+n 0 12 18 12 re f*
+.960784 .960784 .862745 rg
+n 24 12 138 12 re f*
+.960784 .960784 .862745 rg
+n 162 12 18 12 re f*
+.960784 .960784 .862745 rg
+n 24 0 294 12 re f*
+BT 1 0 0 1 0 14 Tm 12 TL /F6 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (singledispatch_example2) Tj 0 0 0 rg (\(\):) Tj 0 0 0 rg T* ( ) Tj /F7 10 Tf .25098 .501961 .501961 rg (# adapted from functools.singledispatch test case) Tj /F3 10 Tf 0 0 0 rg T* ET
+Q
+Q
+Q
+Q
+Q
endstream
endobj
124 0 obj
-<< /Length 13885 >>
+<< /Length 13751 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 415.8236 cm
+1 0 0 1 62.69291 439.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -8200,18 +8257,10 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 348 re B*
+n -6 -6 468.6898 324 re B*
Q
q
.960784 .960784 .862745 rg
-n 0 324 18 12 re f*
-.960784 .960784 .862745 rg
-n 24 324 138 12 re f*
-.960784 .960784 .862745 rg
-n 162 324 18 12 re f*
-.960784 .960784 .862745 rg
-n 24 312 294 12 re f*
-.960784 .960784 .862745 rg
n 24 300 84 12 re f*
.960784 .960784 .862745 rg
n 114 300 6 12 re f*
@@ -8395,14 +8444,14 @@ n 66 0 6 12 re f*
n 72 0 6 12 re f*
.960784 .960784 .862745 rg
n 84 0 6 12 re f*
-BT 1 0 0 1 0 326 Tm 12 TL /F6 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (singledispatch_example2) Tj 0 0 0 rg (\(\):) Tj 0 0 0 rg T* ( ) Tj /F7 10 Tf .25098 .501961 .501961 rg (# adapted from functools.singledispatch test case) Tj /F3 10 Tf 0 0 0 rg T* ( ) Tj 0 0 0 rg (singledispatch) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (dispatch_on) Tj 0 0 0 rg (\() Tj .729412 .129412 .129412 rg ('arg') Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* T* ( ) Tj /F6 10 Tf 0 .501961 0 rg (class) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F6 10 Tf 0 0 1 rg (S) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 .501961 0 rg (object) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F6 10 Tf 0 .501961 0 rg (pass) Tj /F3 10 Tf 0 0 0 rg T* T* ( ) Tj /F6 10 Tf 0 .501961 0 rg (class) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F6 10 Tf 0 0 1 rg (V) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 0 0 rg (c) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Sized) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (S) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F6 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (__len__) Tj 0 0 0 rg (\() Tj 0 .501961 0 rg (self) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F6 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj .4 .4 .4 rg (0) Tj 0 0 0 rg T* T* ( ) Tj .666667 .133333 1 rg (@singledispatch) Tj 0 0 0 rg T* ( ) Tj /F6 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (g) Tj 0 0 0 rg (\() Tj 0 0 0 rg (arg) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F6 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ("base") Tj 0 0 0 rg T* T* ( ) Tj .666667 .133333 1 rg (@g.register) Tj 0 0 0 rg (\() Tj 0 0 0 rg (S) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* ( ) Tj /F6 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (g_s) Tj 0 0 0 rg (\() Tj 0 0 0 rg (arg) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F6 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ("s") Tj 0 0 0 rg T* T* ( ) Tj .666667 .133333 1 rg (@g.register) Tj 0 0 0 rg (\() Tj 0 0 0 rg (c) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Container) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* ( ) Tj /F6 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (g_container) Tj 0 0 0 rg (\() Tj 0 0 0 rg (arg) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F6 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ("container") Tj 0 0 0 rg T* T* ( ) Tj 0 0 0 rg (v) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (V) Tj 0 0 0 rg (\(\)) Tj 0 0 0 rg T* ( ) Tj /F6 10 Tf 0 .501961 0 rg (assert) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (g) Tj 0 0 0 rg (\() Tj 0 0 0 rg (v) Tj 0 0 0 rg (\)) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (==) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ("s") Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (c) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Container) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (register) Tj 0 0 0 rg (\() Tj 0 0 0 rg (V) Tj 0 0 0 rg (\)) Tj 0 0 0 rg ( ) Tj /F7 10 Tf .25098 .501961 .501961 rg (# add c.Container to the virtual mro of V) Tj /F3 10 Tf 0 0 0 rg T* ( ) Tj /F6 10 Tf 0 .501961 0 rg (assert) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (g) Tj 0 0 0 rg (\() Tj 0 0 0 rg (v) Tj 0 0 0 rg (\)) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (==) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ("s") Tj 0 0 0 rg ( ) Tj /F7 10 Tf .25098 .501961 .501961 rg (# since the virtual mro is V, Sized, S, Container) Tj /F3 10 Tf 0 0 0 rg T* ( ) Tj /F6 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (g) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (V) Tj T* ET
+BT 1 0 0 1 0 302 Tm 12 TL /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (singledispatch) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (dispatch_on) Tj 0 0 0 rg (\() Tj .729412 .129412 .129412 rg ('arg') Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* T* ( ) Tj /F6 10 Tf 0 .501961 0 rg (class) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F6 10 Tf 0 0 1 rg (S) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 .501961 0 rg (object) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F6 10 Tf 0 .501961 0 rg (pass) Tj /F3 10 Tf 0 0 0 rg T* T* ( ) Tj /F6 10 Tf 0 .501961 0 rg (class) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F6 10 Tf 0 0 1 rg (V) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 0 0 rg (c) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Sized) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (S) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F6 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (__len__) Tj 0 0 0 rg (\() Tj 0 .501961 0 rg (self) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F6 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj .4 .4 .4 rg (0) Tj 0 0 0 rg T* T* ( ) Tj .666667 .133333 1 rg (@singledispatch) Tj 0 0 0 rg T* ( ) Tj /F6 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (g) Tj 0 0 0 rg (\() Tj 0 0 0 rg (arg) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F6 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ("base") Tj 0 0 0 rg T* T* ( ) Tj .666667 .133333 1 rg (@g.register) Tj 0 0 0 rg (\() Tj 0 0 0 rg (S) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* ( ) Tj /F6 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (g_s) Tj 0 0 0 rg (\() Tj 0 0 0 rg (arg) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F6 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ("s") Tj 0 0 0 rg T* T* ( ) Tj .666667 .133333 1 rg (@g.register) Tj 0 0 0 rg (\() Tj 0 0 0 rg (c) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Container) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* ( ) Tj /F6 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (g_container) Tj 0 0 0 rg (\() Tj 0 0 0 rg (arg) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F6 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ("container") Tj 0 0 0 rg T* T* ( ) Tj 0 0 0 rg (v) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (V) Tj 0 0 0 rg (\(\)) Tj 0 0 0 rg T* ( ) Tj /F6 10 Tf 0 .501961 0 rg (assert) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (g) Tj 0 0 0 rg (\() Tj 0 0 0 rg (v) Tj 0 0 0 rg (\)) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (==) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ("s") Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (c) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Container) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (register) Tj 0 0 0 rg (\() Tj 0 0 0 rg (V) Tj 0 0 0 rg (\)) Tj 0 0 0 rg ( ) Tj /F7 10 Tf .25098 .501961 .501961 rg (# add c.Container to the virtual mro of V) Tj /F3 10 Tf 0 0 0 rg T* ( ) Tj /F6 10 Tf 0 .501961 0 rg (assert) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (g) Tj 0 0 0 rg (\() Tj 0 0 0 rg (v) Tj 0 0 0 rg (\)) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (==) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ("s") Tj 0 0 0 rg ( ) Tj /F7 10 Tf .25098 .501961 .501961 rg (# since the virtual mro is V, Sized, S, Container) Tj /F3 10 Tf 0 0 0 rg T* ( ) Tj /F6 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (g) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (V) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 371.8236 cm
+1 0 0 1 62.69291 395.8236 cm
q
BT 1 0 0 1 0 26 Tm 10.88816 Tw 12 TL /F1 10 Tf 0 0 0 rg (If you play with this example and replace the ) Tj /F3 10 Tf 0 0 0 rg (singledispatch ) Tj /F1 10 Tf 0 0 0 rg (definition with) Tj T* 0 Tw 1.50816 Tw /F3 10 Tf 0 0 0 rg (functools.singledispatch) Tj /F1 10 Tf 0 0 0 rg (, the assertion will break: ) Tj /F3 10 Tf 0 0 0 rg (g ) Tj /F1 10 Tf 0 0 0 rg (will return ) Tj /F3 10 Tf 0 0 0 rg ("container" ) Tj /F1 10 Tf 0 0 0 rg (instead of ) Tj /F3 10 Tf 0 0 0 rg ("s") Tj /F1 10 Tf 0 0 0 rg (,) Tj T* 0 Tw (because ) Tj /F3 10 Tf 0 0 0 rg (functools.singledispatch ) Tj /F1 10 Tf 0 0 0 rg (will insert the ) Tj /F3 10 Tf 0 0 0 rg (Container ) Tj /F1 10 Tf 0 0 0 rg (class right before ) Tj /F3 10 Tf 0 0 0 rg (S) Tj /F1 10 Tf 0 0 0 rg (.) Tj T* ET
Q
@@ -8410,7 +8459,7 @@ Q
q
1 0 0 1 62.69291 341.8236 cm
q
-BT 1 0 0 1 0 14 Tm 3.641163 Tw 12 TL /F1 10 Tf 0 0 0 rg (The only way to understand what is happening here is to scratch your head by looking at the) Tj T* 0 Tw (implementations. I will just notice that ) Tj /F3 10 Tf 0 0 0 rg (.dispatch_info ) Tj /F1 10 Tf 0 0 0 rg (is quite useful:) Tj T* ET
+BT 1 0 0 1 0 38 Tm .528935 Tw 12 TL /F1 10 Tf 0 0 0 rg (Notice that here I am not making any bold claim such as "the standard library algorithm is wrong and my) Tj T* 0 Tw 1.082209 Tw (algorithm is right" or viceversa. It just point out that there are some subtle differences. The only way to) Tj T* 0 Tw .43881 Tw (understand what is really happening here is to scratch your head by looking at the implementations. I will) Tj T* 0 Tw (just notice that ) Tj /F3 10 Tf 0 0 0 rg (.dispatch_info ) Tj /F1 10 Tf 0 0 0 rg (is quite essential to see the class precedence list used by algorithm:) Tj T* ET
Q
Q
q
@@ -8868,13 +8917,13 @@ Q
endstream
endobj
126 0 obj
-<< /Length 15474 >>
+<< /Length 15466 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
1 0 0 1 62.69291 729.0236 cm
q
-BT 1 0 0 1 0 26 Tm 3.015984 Tw 12 TL /F1 10 Tf 0 0 0 rg (Even in Python 3.5, however, it is impossible to change the function signature directly. Thus, the) Tj T* 0 Tw 1.617882 Tw /F3 10 Tf 0 0 0 rg (decorator ) Tj /F1 10 Tf 0 0 0 rg (module is still useful! As a matter of fact, this is the main reason why I still maintain the) Tj T* 0 Tw (module and release new versions.) Tj T* ET
+BT 1 0 0 1 0 26 Tm 1.905984 Tw 12 TL /F1 10 Tf 0 0 0 rg (Even in Python 3.5, it is impossible to change the function signature directly. Thus, the ) Tj /F3 10 Tf 0 0 0 rg (decorator) Tj T* 0 Tw 1.624488 Tw /F1 10 Tf 0 0 0 rg (module is still useful! As a matter of fact, this is the main reason why I still maintain the module and) Tj T* 0 Tw (release new versions.) Tj T* ET
Q
Q
q
@@ -9014,7 +9063,7 @@ Q
q
1 0 0 1 62.69291 411.8236 cm
q
-BT 1 0 0 1 0 14 Tm .683984 Tw 12 TL /F1 10 Tf 0 0 0 rg (The error message looks really strange...until you realize that the caller function ) Tj /F4 10 Tf 0 0 0 rg (_memoize ) Tj /F1 10 Tf 0 0 0 rg (uses ) Tj /F4 10 Tf 0 0 0 rg (func ) Tj /F1 10 Tf 0 0 0 rg (as) Tj T* 0 Tw (first argument, so there is a confusion between the positional argument and the keywork arguments.) Tj T* ET
+BT 1 0 0 1 0 14 Tm .467485 Tw 12 TL /F1 10 Tf 0 0 0 rg (The error message looks really strange... until you realize that the caller function ) Tj /F4 10 Tf 0 0 0 rg (_memoize ) Tj /F1 10 Tf 0 0 0 rg (uses ) Tj /F4 10 Tf 0 0 0 rg (func ) Tj /F1 10 Tf 0 0 0 rg (as) Tj T* 0 Tw (first argument, so there is a confusion between the positional argument and the keywork arguments.) Tj T* ET
Q
Q
q
@@ -9612,155 +9661,155 @@ xref
0000000402 00000 n
0000000510 00000 n
0000000699 00000 n
-0000000897 00000 n
-0000001068 00000 n
-0000001239 00000 n
-0000001410 00000 n
-0000001582 00000 n
-0000001754 00000 n
-0000001926 00000 n
-0000002098 00000 n
-0000002270 00000 n
-0000002442 00000 n
-0000002614 00000 n
-0000002786 00000 n
-0000002958 00000 n
-0000003130 00000 n
-0000003302 00000 n
-0000003474 00000 n
-0000003646 00000 n
-0000003818 00000 n
-0000003990 00000 n
-0000004162 00000 n
-0000004334 00000 n
-0000004506 00000 n
-0000004678 00000 n
-0000004850 00000 n
-0000005022 00000 n
-0000005194 00000 n
-0000005366 00000 n
-0000005538 00000 n
-0000005710 00000 n
-0000005882 00000 n
-0000006054 00000 n
-0000006226 00000 n
-0000006398 00000 n
-0000006570 00000 n
-0000006742 00000 n
-0000006914 00000 n
-0000007086 00000 n
-0000007258 00000 n
-0000007430 00000 n
-0000007602 00000 n
-0000007774 00000 n
-0000007946 00000 n
-0000008118 00000 n
-0000008661 00000 n
-0000008780 00000 n
-0000008960 00000 n
-0000009191 00000 n
-0000009314 00000 n
-0000009519 00000 n
-0000009633 00000 n
-0000009750 00000 n
-0000009978 00000 n
-0000010216 00000 n
-0000010428 00000 n
-0000010640 00000 n
-0000010836 00000 n
-0000011067 00000 n
-0000011279 00000 n
-0000011491 00000 n
-0000011703 00000 n
-0000011915 00000 n
-0000012127 00000 n
-0000012318 00000 n
-0000012549 00000 n
-0000012767 00000 n
-0000012998 00000 n
-0000013210 00000 n
-0000013422 00000 n
-0000013611 00000 n
-0000013842 00000 n
-0000014032 00000 n
-0000014263 00000 n
-0000014475 00000 n
-0000014687 00000 n
-0000014899 00000 n
-0000015111 00000 n
-0000015323 00000 n
-0000015434 00000 n
-0000015682 00000 n
-0000015761 00000 n
-0000015878 00000 n
-0000016006 00000 n
-0000016148 00000 n
-0000016277 00000 n
-0000016419 00000 n
-0000016549 00000 n
-0000016684 00000 n
-0000016822 00000 n
-0000016959 00000 n
-0000017085 00000 n
-0000017219 00000 n
-0000017351 00000 n
-0000017492 00000 n
-0000017634 00000 n
-0000017789 00000 n
-0000017927 00000 n
-0000018087 00000 n
-0000018231 00000 n
-0000018345 00000 n
-0000018566 00000 n
-0000026187 00000 n
-0000034520 00000 n
-0000046282 00000 n
-0000059218 00000 n
-0000078640 00000 n
-0000098609 00000 n
-0000115754 00000 n
-0000133434 00000 n
-0000152203 00000 n
-0000164460 00000 n
-0000180554 00000 n
-0000196946 00000 n
-0000213337 00000 n
-0000225530 00000 n
-0000240802 00000 n
-0000254840 00000 n
-0000268108 00000 n
-0000279694 00000 n
-0000293638 00000 n
-0000304633 00000 n
-0000320166 00000 n
-0000330013 00000 n
-0000330297 00000 n
-0000330335 00000 n
-0000330373 00000 n
-0000330411 00000 n
-0000330449 00000 n
-0000330487 00000 n
-0000330525 00000 n
-0000330563 00000 n
-0000330601 00000 n
-0000330639 00000 n
-0000330678 00000 n
-0000330717 00000 n
-0000330756 00000 n
-0000330795 00000 n
-0000330834 00000 n
-0000330873 00000 n
-0000330912 00000 n
-0000330951 00000 n
-0000330990 00000 n
-0000331029 00000 n
-0000331068 00000 n
-0000331107 00000 n
+0000000898 00000 n
+0000001069 00000 n
+0000001240 00000 n
+0000001411 00000 n
+0000001583 00000 n
+0000001755 00000 n
+0000001927 00000 n
+0000002099 00000 n
+0000002271 00000 n
+0000002443 00000 n
+0000002615 00000 n
+0000002787 00000 n
+0000002959 00000 n
+0000003131 00000 n
+0000003303 00000 n
+0000003475 00000 n
+0000003647 00000 n
+0000003819 00000 n
+0000003991 00000 n
+0000004163 00000 n
+0000004335 00000 n
+0000004507 00000 n
+0000004679 00000 n
+0000004851 00000 n
+0000005023 00000 n
+0000005195 00000 n
+0000005367 00000 n
+0000005539 00000 n
+0000005711 00000 n
+0000005883 00000 n
+0000006055 00000 n
+0000006227 00000 n
+0000006399 00000 n
+0000006571 00000 n
+0000006743 00000 n
+0000006915 00000 n
+0000007087 00000 n
+0000007259 00000 n
+0000007431 00000 n
+0000007603 00000 n
+0000007775 00000 n
+0000007947 00000 n
+0000008119 00000 n
+0000008662 00000 n
+0000008781 00000 n
+0000008961 00000 n
+0000009192 00000 n
+0000009315 00000 n
+0000009520 00000 n
+0000009634 00000 n
+0000009751 00000 n
+0000009979 00000 n
+0000010217 00000 n
+0000010429 00000 n
+0000010641 00000 n
+0000010837 00000 n
+0000011068 00000 n
+0000011280 00000 n
+0000011492 00000 n
+0000011704 00000 n
+0000011916 00000 n
+0000012128 00000 n
+0000012319 00000 n
+0000012550 00000 n
+0000012768 00000 n
+0000012999 00000 n
+0000013211 00000 n
+0000013423 00000 n
+0000013612 00000 n
+0000013843 00000 n
+0000014033 00000 n
+0000014264 00000 n
+0000014476 00000 n
+0000014688 00000 n
+0000014900 00000 n
+0000015112 00000 n
+0000015324 00000 n
+0000015435 00000 n
+0000015683 00000 n
+0000015762 00000 n
+0000015879 00000 n
+0000016007 00000 n
+0000016149 00000 n
+0000016278 00000 n
+0000016420 00000 n
+0000016550 00000 n
+0000016685 00000 n
+0000016823 00000 n
+0000016960 00000 n
+0000017086 00000 n
+0000017220 00000 n
+0000017352 00000 n
+0000017493 00000 n
+0000017635 00000 n
+0000017790 00000 n
+0000017928 00000 n
+0000018088 00000 n
+0000018232 00000 n
+0000018346 00000 n
+0000018567 00000 n
+0000026190 00000 n
+0000034449 00000 n
+0000046365 00000 n
+0000059816 00000 n
+0000079241 00000 n
+0000099270 00000 n
+0000116415 00000 n
+0000134095 00000 n
+0000152393 00000 n
+0000163332 00000 n
+0000180836 00000 n
+0000197228 00000 n
+0000213619 00000 n
+0000225808 00000 n
+0000241080 00000 n
+0000255118 00000 n
+0000268389 00000 n
+0000280580 00000 n
+0000294390 00000 n
+0000305385 00000 n
+0000320910 00000 n
+0000330757 00000 n
+0000331041 00000 n
+0000331079 00000 n
+0000331117 00000 n
+0000331155 00000 n
+0000331193 00000 n
+0000331231 00000 n
+0000331269 00000 n
+0000331307 00000 n
+0000331345 00000 n
+0000331383 00000 n
+0000331422 00000 n
+0000331461 00000 n
+0000331500 00000 n
+0000331539 00000 n
+0000331578 00000 n
+0000331617 00000 n
+0000331656 00000 n
+0000331695 00000 n
+0000331734 00000 n
+0000331773 00000 n
+0000331812 00000 n
+0000331851 00000 n
trailer
<< /ID
% ReportLab generated PDF document -- digest (http://www.reportlab.com)
- [(\011\036F\334\314I0?\\,@\235\311+\030\356) (\011\036F\334\314I0?\\,@\235\311+\030\356)]
+ [(\335u\305\027\323\236f+p\321\341\351\)#\340;) (\335u\305\027\323\236f+p\321\341\351\)#\340;)]
/Info 84 0 R /Root 83 0 R /Size 151 >>
startxref
-331146
+331890
%%EOF
diff --git a/src/decorator.py b/src/decorator.py
index 736b356..50876c6 100644
--- a/src/decorator.py
+++ b/src/decorator.py
@@ -372,6 +372,7 @@ def dispatch_on(*dispatch_args):
Decorator to register an implementation for the given types
"""
check(types)
+
def dec(f):
check(getfullargspec(f).args, operator.lt, ' in ' + f.__name__)
typemap[types] = f
diff --git a/src/tests/documentation.py b/src/tests/documentation.py
index f801236..890b82d 100644
--- a/src/tests/documentation.py
+++ b/src/tests/documentation.py
@@ -17,7 +17,7 @@ The ``decorator`` module
Introduction
-----------------------------------------
-The decorator module is over ten years old, but still alive and
+The ``decorator`` module is over ten years old, but still alive and
kicking. It is used by several frameworks (IPython, scipy, authkit,
pylons, pycuda, sugar, ...) and has been stable for a *long*
time. It is your best option if you want to preserve the signature of
@@ -33,7 +33,7 @@ trivial to distribute the module as an universal wheel_ since 2to3 is no more
required. Since Python 2.5 has been released 9 years ago, I felt that
it was reasonable to drop the support for it. If you need to support
ancient versions of Python, stick with the decorator module version
-3.4.2. This version supports all Python releases from 2.6 up to 3.5.
+3.4.2. The current version supports all Python releases from 2.6 up to 3.5.
.. _wheel: http://pythonwheels.com/
@@ -48,8 +48,8 @@ What's New
- **Packaging improvements**
The code is now also available in wheel format. Integration with
- setuptools is also improved: you can now run tests with the command
- ``python setup.py test``.
+ setuptools has improved and you can run the tests with the command
+ ``python setup.py test`` too.
- **Code changes**
A new utility function ``decorate(func, caller)`` has been added.
@@ -65,7 +65,7 @@ What's New
Moreover, all decorators involved preserve the signature of the
decorated functions. For now, this exists mostly to demonstrate
the power of the module. In the future it could be enhanced/optimized;
- however, both it and its API could change. (Such is the fate of
+ however, its API could change. (Such is the fate of
experimental features!) In any case, it is very short and compact
(less then 100 lines), so you can extract it for your own use.
Take it as food for thought.
@@ -75,7 +75,7 @@ Usefulness of decorators
Python decorators are an interesting example of why syntactic sugar
matters. In principle, their introduction in Python 2.4 changed
-nothing, since they do not provide any new functionality which was not
+nothing, since they did not provide any new functionality which was not
already present in the language. In practice, their introduction has
significantly changed the way we structure our programs in Python. I
believe the change is for the best, and that decorators are a great
@@ -109,10 +109,10 @@ can be used as a decorator. However, this definition is somewhat too large
to be really useful. It is more convenient to split the generic class of
decorators in two subclasses:
-*signature-preserving* decorators :
+*signature-preserving* decorators:
Callable objects which accept a function as input and return
- a function *with the same signature*.
-*signature-changing* decorators :
+ a function as output, *with the same signature*.
+*signature-changing* decorators:
Decorators which change the signature of their input function,
or decorators that return non-callable objects.
@@ -147,7 +147,7 @@ in the standard library's ``functools``. Here I am just
interested in giving an example.
Consider the following simple implementation (note that it is
-generally impossible to *correctly* memoize correctly something
+generally impossible to *correctly* memoize something
that depends on non-hashable arguments):
$$memoize_uw
@@ -184,8 +184,8 @@ keyword arguments:
ArgSpec(args=[], varargs='args', varkw='kw', defaults=None)
This means that introspection tools (like ``pydoc``) will give false
-information about the signature of ``f1`` (unless you are using
-Python 3.5)! This is pretty bad: ``pydoc`` will tell you that the
+information about the signature of ``f1`` -- unless you are using
+Python 3.5. This is pretty bad: ``pydoc`` will tell you that the
function accepts the generic signature ``*args, **kw``, but
calling the function with more than one argument raises an error:
@@ -196,9 +196,9 @@ calling the function with more than one argument raises an error:
...
TypeError: f1() takes exactly 1 positional argument (2 given)
-Notice that ``inspect.getargspec`` and ``inspect.getfullargspec``
-will give the wrong signature. This even occurs in Python 3.5
-(although both functions were deprecated in that release).
+Notice that ``inspect.getargspec`` and ``inspect.getfullargspec``
+will give the wrong signature. This even occurs in Python 3.5,
+although both functions were deprecated in that release.
The solution
@@ -213,15 +213,14 @@ the ``decorator`` module is such a factory:
>>> from decorator import decorate
-``decorate`` takes two arguments:
+``decorate`` takes two arguments:
-1. a caller function describing the functionality of the decorator, and
-1. a function to be decorated
+1. a caller function describing the functionality of the decorator, and
-Then, ``decorate`` returns the decorated function.
+2. a function to be decorated.
-The caller function must have signature ``(f, *args, **kw)``, and it
-must call the original function ``f`` with arguments ``args`` and ``kw``,
+The caller function must have signature ``(f, *args, **kw)``, and it
+must call the original function ``f`` with arguments ``args`` and ``kw``,
implementing the wanted capability (in this case, memoization):
$$_memoize
@@ -231,8 +230,8 @@ Now, you can define your decorator as follows:
$$memoize
The difference from the nested function approach of ``memoize_uw``
-is that the decorator module forces you to lift the inner function
-to the outer level. Moreover, you are forced to explicitly pass the
+is that the decorator module forces you to lift the inner function
+to the outer level. Moreover, you are forced to explicitly pass the
function you want to decorate; there are no closures.
Here is a test of usage:
@@ -260,7 +259,7 @@ The signature of ``heavy_computation`` is the one you would expect:
A ``trace`` decorator
------------------------------------------------------
-Here an example of how to define a simple ``trace`` decorator,
+Here is an example of how to define a simple ``trace`` decorator,
which prints a message whenever the traced function is called:
$$_trace
@@ -358,8 +357,9 @@ Here is an example of usage:
``blocking``
-------------------------------------------
-Sometimes one has to deal with blocking resources, such as ``stdin``.
-Sometimes it is better to receive a "busy" message than just blocking everything.
+Sometimes one has to deal with blocking resources, such as ``stdin``.
+Sometimes it is better to receive a "busy" message than just blocking
+everything.
This can be accomplished with a suitable family of decorators,
where the parameter is the busy message:
@@ -401,24 +401,23 @@ to create instances of that class.
As an example, here is a decorator which can convert a
blocking function into an asynchronous function. When
-the function is called, it is executed in a separate thread.
+the function is called, it is executed in a separate thread.
-(This is similar to the approach used in the ``concurrent.futures`` package.
-But I don't recommend that you implement futures this way; this is just an
-example.)
+(This is similar to the approach used in the ``concurrent.futures`` package.
+But I don't recommend that you implement futures this way; this is just an
+example.)
$$Future
The decorated function returns a ``Future`` object. It has a ``.result()``
method which blocks until the underlying thread finishes and returns
-the final result.
+the final result.
Here is the minimalistic usage:
.. code-block:: python
- >>> futurefactory = decorator(Future)
- >>> @futurefactory
+ >>> @decorator(Future)
... def long_running(x):
... time.sleep(.5)
... return x
@@ -431,8 +430,8 @@ Here is the minimalistic usage:
contextmanager
-------------------------------------
-Python's standard library has the ``contextmanager`` decorator,
-which converts a generator function into a ``GeneratorContextManager``
+Python's standard library has the ``contextmanager`` decorator,
+which converts a generator function into a ``GeneratorContextManager``
factory. For instance, if you write this...
.. code-block:: python
@@ -485,11 +484,11 @@ However, there two issues:
the Python 3 functionality to Python 2.)
2. ``GeneratorContextManager`` objects do not preserve the signature of
- the decorated functions! The decorated ``hello`` function above will
+ the decorated functions. The decorated ``hello`` function above will
have the generic signature ``hello(*args, **kwargs)``, but fails if
called with more than zero arguments.
-For these reasons, decorator module (as of release 3.4) offers a
+For these reasons, the `decorator` module, starting from release 3.4, offers a
``decorator.contextmanager`` decorator that solves both problems,
*and* works in all supported Python versions. Its usage is identical,
and factories decorated with ``decorator.contextmanager`` will return
@@ -692,7 +691,8 @@ are not tail recursive, such as the following:
$$fact
-**Reminder:** A function is *tail recursive* if it does either of the following:
+**Reminder:** A function is *tail recursive* if it does either of the
+following:
- returns a value without making a recursive call; or,
- returns directly the result of a recursive call.
@@ -702,7 +702,7 @@ Multiple dispatch
There has been talk of implementing multiple dispatch functions
(i.e. "generic functions") in Python for over ten years. Last year,
-something concrete was done for the first time--and as of Python 3.4,
+something concrete was done for the first time. As of Python 3.4,
we have the decorator ``functools.singledispatch`` to implement generic
functions!
@@ -876,7 +876,7 @@ builtin ``len``--but you should get the idea.
Since in Python it is possible to consider any instance of ``ABCMeta``
as a virtual ancestor of any other class (it is enough to register it
as ``ancestor.register(cls)``), any implementation of generic functions
-must take virtual ancestors into account.
+must be aware of the registration mechanism.
For example, suppose you are using a third-party set-like class, like
the following:
@@ -900,27 +900,25 @@ Now, let's define an implementation of ``get_length`` specific to set:
$$get_length_set
The current implementation (and ``functools.singledispatch`` too)
-is able to discern that a ``Set`` is a ``Sized`` object,
-so it uses the more specific implementation for ``Set``:
+is able to discern that a ``Set`` is a ``Sized`` object, by looking at
+the class registry, so it uses the more specific implementation for ``Set``:
.. code-block:: python
>>> get_length(SomeSet()) # NB: the implementation for Sized would give 0
1
-Sometimes it is not clear how to dispatch. For instance, consider the
-class ``C``: it is registered both as ``collections.Iterable`` and
-``collections.Sized``, and defines the generic function ``g`` with
+Sometimes it is not clear how to dispatch. For instance, consider a
+class ``C`` registered both as ``collections.Iterable`` and
+``collections.Sized``, and defines a generic function ``g`` with
implementations for both ``collections.Iterable`` *and*
-``collections.Sized``.
-
-It is impossible to decide which implementation to use, since the ancestors
-are independent. The following function will raise a ``RuntimeError``
-when called:
+``collections.Sized``:
$$singledispatch_example1
-This is consistent with the "refuse the temptation to guess"
+It is impossible to decide which implementation to use, since the ancestors
+are independent. The following function will raise a ``RuntimeError``
+when called. This is consistent with the "refuse the temptation to guess"
philosophy. ``functools.singledispatch`` would raise a similar error.
It would be easy to rely on the order of registration to decide the
@@ -950,9 +948,13 @@ with ``functools.singledispatch``, the assertion will break: ``g`` will return
``"container"`` instead of ``"s"``, because ``functools.singledispatch``
will insert the ``Container`` class right before ``S``.
-The only way to understand what is happening here is to scratch your
-head by looking at the implementations. I will just notice that
-``.dispatch_info`` is quite useful:
+Notice that here I am not making any bold claim such as "the standard
+library algorithm is wrong and my algorithm is right" or viceversa. It
+just point out that there are some subtle differences. The only way to
+understand what is really happening here is to scratch your head by
+looking at the implementations. I will just notice that
+``.dispatch_info`` is quite essential to see the class precedence
+list used by algorithm:
.. code-block:: python
@@ -1037,24 +1039,26 @@ You see here the inner call to the decorator ``trace``, which calls
This latter reference is due to the fact that internally, the decorator
module uses ``exec`` to generate the decorated function. Notice that
``exec`` is *not* responsibile for the performance penalty, since is the
-called *only once* (at function decoration time); it is *not* called
+called *only once* (at function decoration time); it is *not* called
each time the decorated function is called.
Presently, there is no clean way to avoid ``exec``. A clean solution
-would require changing the CPython implementation, by
+would require changing the CPython implementation, by
adding a hook to functions (to allow changing their signature directly).
-Even in Python 3.5, however, it is impossible to change the
+Even in Python 3.5, it is impossible to change the
function signature directly. Thus, the ``decorator`` module is
still useful! As a matter of fact, this is the main reason why I still
-maintain the module and release new versions.
+maintain the module and release new versions.
-It should be noted that in Python 3.5, a *lot* of improvements have been made:
-you can decorate a function with ``func_tools.update_wrapper``, and ``pydoc``
-will see the correct signature. Unfortunately, the function will still have an incorrect
-signature internally, as you can see by using ``inspect.getfullargspec``; so,
-all documentation tools using the function (which has rightly been deprecated)
-will see the wrong signature.
+It should be noted that in Python 3.5, a *lot* of improvements have
+been made: you can decorate a function with
+``func_tools.update_wrapper``, and ``pydoc`` will see the correct
+signature. Unfortunately, the function will still have an incorrect
+signature internally, as you can see by using
+``inspect.getfullargspec``; so, all documentation tools using the
+function (which has rightly been deprecated) will see the wrong
+signature.
.. _362: http://www.python.org/dev/peps/pep-0362
@@ -1081,12 +1085,12 @@ Here is an example where it is manifest:
...
TypeError: _memoize() got multiple values for ... 'func'
-The error message looks really strange...until you realize that
+The error message looks really strange... until you realize that
the caller function `_memoize` uses `func` as first argument,
so there is a confusion between the positional argument and the
-keywork arguments.
+keywork arguments.
-The solution is to change the name of the first argument in `_memoize`,
+The solution is to change the name of the first argument in `_memoize`,
or to change the implementation like so:
.. code-block:: python
@@ -1182,8 +1186,8 @@ function_annotations = """Function annotations
Python 3 introduced the concept of `function annotations`_: the ability
to annotate the signature of a function with additional information,
-stored in a dictionary named ``__annotations__``. The decorator module
-(as of release 3.3) will understand and preserve these annotations.
+stored in a dictionary named ``__annotations__``. The ``decorator`` module
+(starting from release 3.3) will understand and preserve these annotations.
Here is an example: