├── README.md
├── img
├── py
│ ├── rebind.png
│ └── uniencode.png
└── tinypy310-iso.png
└── python310.rst
/README.md:
--------------------------------------------------------------------------------
1 |
2 | Tiny Python 3.10 Notebook
3 | ========================
4 |
5 | This repository contains the text for the *Tiny Python 3.10 Notebook*.
6 |
7 |
8 |
9 | Warning, this is not an introduction to Python. Rather it is a notebook
10 | containing curated examples for Python 3 as well as the new features
11 | found in Python 3.10. It is designed to accompany technical corporate
12 | training offered by the author or aid those who want a quick refresher
13 | to the Python syntax.
14 |
15 | Reviews
16 | ---------
17 |
18 | > I love these little books, and have several versions across multiple languages. This is the latest in a series of succinct and up-to-date summaries of the syntax and idioms of Python, and have enough whitespace and notes pages to add useful additional information of snippets of code, lists of tricks etc that you pick up along the way.
19 | >
20 | > I also use these books as a neat little tool to wean me off looking at my phone in idle moments. This book is eminently pocketable and if it's like its siblings it takes a battering as well (witness my ES6 book after nearly three years of riding around in my pocket).
21 | >
22 | > I tend to view it as a pre-populated personal notebook, with enough room for embellishment. The quality of the content and the book itself are excellent. I can't wait to start annotating this one, too! - Amazon 3.8 review
23 |
24 | These are for the 3.6 version of this book
25 |
26 | > This is an awesome python3 resource I share all the time. 🐍🎉 - @nnja (MS Developer Advocate)
27 |
28 | > I think it's pretty awesome. It's all of the syntax boiled down to just the facts man. - Brian Okken (Host of Test & Code podcast)
29 |
30 |
31 | > It's the perfect follow on to a training course. - Michael Kennedy (Host of Talk Python podcast)
32 |
33 | > Great Python reference book by @\_\_mharrison\_\_ "Tiny Python 3.6 Notebook" It's NOT a @ProjectJupyter notebook - @okeedoak
34 |
35 | > Goodness! So thankful for @\_\_mharrison\_\_ and his Tiny Python 3.6 Notebook. Great resource! Go get it… - @\_\_jamesssio\_\_
36 |
37 | > Tiny #Python notebook for looking up all the basics. I found this a very concise read if you have some prev prog exp - @andreasose
38 |
39 | > Useful collection of notes on Python 3.6 - @hjelmj
40 |
41 | > Cool work: a tiny and handy notebook containing notes, tables and examples for Python 3.6. Very much recommended! - @epaillas
42 |
43 | > I keep a copy on my desk. Excellent resource - @HLIBIndustry
44 |
45 | > Awesome community work! - @MostafaElzoghbi
46 |
47 | > Интересный формат книги по #python - @ku_al
48 |
49 | Bulk Purchase
50 | ---------------
51 |
52 | If you are interested in purchasing larger amounts (100+) for schools, employees or for
53 | use as giveaways/swag at a conference (much better than a tshirt!), get in touch
54 | with Matt (matt at metasnake dot com).
55 |
56 | Thanks
57 | ------
58 |
59 | If you enjoy this content, consider *purchasing the physical version [on Amazon](https://www.amazon.com/Tiny-Python-3-9-Notebook-Examples/dp/B08L4QWL9H/ref=sr_1_2?crid=QYNIFZ7C3EQE&dchild=1&keywords=tiny+python+notebook&qid=1603324510&sprefix=tiny+python+note%2Caps%2C226&sr=8-2*)
60 | It is a hand laid out version that fits in the pocket and has blank
61 | pages in the back for note taking. Thanks!
62 |
63 |
64 |
65 | Feel free to share this repository on social media.
66 |
67 | Errors
68 | ------
69 |
70 | The author is human and will certainly make errors. You may file a bug
71 | and it may be resolved in a future version of the book. I love feedback
72 | and would love to hear your ideas on what is missing or could be
73 | improved.
74 |
75 | License
76 | -------
77 |
78 | This content is licensed under the
79 | Attribution-NonCommercial-NoDerivatives 4.0 International (CC BY-NC-ND
80 | 4.0)
81 |
82 |
83 |
--------------------------------------------------------------------------------
/img/py/rebind.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattharrison/Tiny-Python-3.10-Notebook/5fcfeb4ff46c3e96f8fe3a3864b3b205f63a9821/img/py/rebind.png
--------------------------------------------------------------------------------
/img/py/uniencode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattharrison/Tiny-Python-3.10-Notebook/5fcfeb4ff46c3e96f8fe3a3864b3b205f63a9821/img/py/uniencode.png
--------------------------------------------------------------------------------
/img/tinypy310-iso.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattharrison/Tiny-Python-3.10-Notebook/5fcfeb4ff46c3e96f8fe3a3864b3b205f63a9821/img/tinypy310-iso.png
--------------------------------------------------------------------------------
/python310.rst:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Introduction
5 | ==============
6 |
7 | This is not so much an instructional manual, but rather notes, tables, and
8 | examples for Python syntax. It was created by the author as an additional
9 | resource during training, meant to be distributed as a physical notebook.
10 | Participants (who favor the physical characteristics of dead tree material)
11 | could add their own notes, thoughts, and have a valuable reference
12 | of curated examples.
13 |
14 |
15 | Running Python
16 | ==============
17 |
18 | Installation
19 | ---------------
20 |
21 | To check if Python is installed, run the following from a terminal::
22 |
23 | $ python3 --version
24 |
25 |
26 | Otherwise, install Python 3 from the website [#]_.
27 |
28 | .. [#] http://python.org
29 |
30 | Invoking Python
31 | ---------------
32 |
33 | The Python executable will behave differently depending on the command line options you give it:
34 |
35 | * Start the Python REPL::
36 |
37 | $ python3
38 |
39 | * Execute the ``file.py`` file::
40 |
41 | $ python3 file.py
42 |
43 | * Execute the ``file.py`` file, and drop into REPL with namespace of ``file.py``::
44 |
45 | $ python3 -i file.py
46 |
47 | * Execute the ``json/tool.py`` module::
48 |
49 | $ python3 -m json.tool
50 |
51 | * Execute ``"print('hi')"`` ::
52 |
53 | $ python3 -c "print('hi')"
54 |
55 | REPL
56 | ----
57 |
58 | * Use the ``help`` function to read the documentation for a module/class/function. As a standalone invocation,
59 | you enter the help system and can explore various topics.
60 | * Use the ``dir`` function to list contents of the namespace, or attributes of an object if you pass one in.
61 |
62 | .. note::
63 |
64 | The majority of code in this book is written as if it were executed in a REPL. If you
65 | are typing it in, ignore the primary and secondary prompts (``>>>`` and ``...``).
66 |
67 | The Zen of Python
68 | ===================
69 |
70 | Run the following in an interpreter to get an Easter egg that describes some of the ethos behind Python. This is also codified in PEP 20::
71 |
72 | >>> import this
73 | The Zen of Python, by Tim Peters
74 |
75 | Beautiful is better than ugly.
76 | Explicit is better than implicit.
77 | Simple is better than complex.
78 | Complex is better than complicated.
79 | Flat is better than nested.
80 | Sparse is better than dense.
81 | Readability counts.
82 | Special cases aren't special enough to break the
83 | rules.
84 | Although practicality beats purity.
85 | Errors should never pass silently.
86 | Unless explicitly silenced.
87 | In the face of ambiguity, refuse the temptation
88 | to guess.
89 | There should be one --and preferably only one--
90 | obvious way to do it.
91 | Although that way may not be obvious at first
92 | unless you're Dutch.
93 | Now is better than never.
94 | Although never is often better than *right* now.
95 | If the implementation is hard to explain, it's a
96 | bad idea.
97 | If the implementation is easy to explain, it may
98 | be a good idea.
99 | Namespaces are one honking great idea -- let's
100 | do more of those!
101 |
102 | These might just seem like silly one liners, but there is a lot of wisdom
103 | packed in here. It is good for Python programmers to review these
104 | every once in a while and see if these hold true for their code. (Or to
105 | justify their code reviews)
106 |
107 | Built-in Types
108 | ===============
109 |
110 | Variables
111 | ---------
112 |
113 | Python variables are like cattle tags, they point to objects (which can be
114 | classes, instances, modules, or functions), but variables are not the objects. You can
115 | reuse variable names for different object types (though you probably shouldn't)::
116 |
117 | >>> a = 400 # a points to an integer
118 | >>> a = '400' # a now points to a string
119 |
120 |
121 | .. note::
122 |
123 | The ``#`` character denotes the start of a comment. There are no multi-line comments, though
124 | most editors with Python support can comment out a region.
125 |
126 | The figure that follows illustrates how everything is an object in Python and variables just point to them.
127 |
128 |
129 | .. figure:: img/py/rebind.png
130 |
131 | Illustration of reusing the same variable
132 |
133 | .. raw:: latex
134 |
135 | %\Needspace{5\baselineskip}
136 | \clearpage
137 |
138 | Assignment Expressions
139 | ----------------------
140 |
141 | In Python 3.8 the *walrus operator* was introduced, ``:=``. The following code::
142 |
143 | rows = connection.fetch(200)
144 | while rows:
145 | process(rows)
146 | rows = connection.fetch(200)
147 |
148 | Can be rewritten as::
149 |
150 | while rows := connection.fetch(200):
151 | process(rows)
152 |
153 | Normal assignment statements cannot be put in ``if`` or ``while`` statements, but
154 | an assignment expression evaluates to the value of the variable, so it can.
155 |
156 | Numbers
157 | -----------
158 |
159 | Python includes three types of numeric literals:
160 | *integers* (unlimited precision), *floats* (usually C ``double``, see ``sys.float_info``), and *complex numbers*.
161 | Python 3.6 added the ability to use underscores to
162 | improve readability (PEP 515)::
163 |
164 | >>> dollars = 3_283_999
165 |
166 | Floats in general are approximations, though since Python 3.1, they are rounded when they are displayed so that may mask the lack of precision to casual users.
167 |
168 | .. raw:: latex
169 |
170 | \Needspace{5\baselineskip}
171 |
172 | .. longtable: format: {r l}
173 |
174 | .. table:: Number types
175 |
176 |
177 | ================ ===========================
178 | Type Example
179 | ================ ===========================
180 | Integer ``14``
181 | Integer (Hex) ``0xe``
182 | Integer (Octal) ``0o16``
183 | Integer (Binary) ``0b1110``
184 | Float ``14.0``
185 | Float ``1.4e1``
186 | Complex ``14+0j``
187 | Underscore ``1_000``
188 | ================ ===========================
189 |
190 | There are many built-in functions for manipulating
191 | numbers ie. ``abs``, ``min``, ``max``, ``ceil``.
192 | Also see the ``math``, ``random``, and ``statistics`` modules in
193 | the standard library. See the ``fractions`` and ``decimal`` libraries in the standard library rational numbers and precise floating point numbers.
194 |
195 |
196 | .. longtable: format: {p{.3\textwidth} l >{\raggedright\arraybackslash}p{.3\textwidth}}
197 |
198 | .. longtable: format: {>{\hangindent=1em\hangafter=1 }p{.3\textwidth} l >{\hangindent=1em\hangafter=1 }p{.3\textwidth}}
199 |
200 | .. table:: Number magic methods
201 |
202 | ====================== ================== =====================================
203 | Operation Provided By Result
204 | ====================== ================== =====================================
205 | ``abs(num)`` ``__abs__`` Absolute value of ``num``
206 | ``num + num2`` ``__add__`` Addition
207 | ``bool(num)`` ``__bool__`` Boolean conversion
208 | ``num == num2`` ``__eq__`` Equality
209 | ``float(num)`` ``__float__`` Float conversion
210 | ``num // num2`` ``__floordiv__`` Integer division
211 | ``num >= num2`` ``__ge__`` Greater or equal
212 | ``num > num2`` ``__gt__`` Greater than
213 | ``int(num)`` ``__int__`` Integer conversion
214 | ``num <= num2`` ``__le__`` Less or equal
215 | ``num < num2`` ``__lt__`` Less than
216 | ``num % num2`` ``__mod__`` Modulus
217 | ``num * num2`` ``__mul__`` Multiplication
218 | ``num != num2`` ``__ne__`` Not equal
219 | ``-num`` ``__neg__`` Negative
220 | ``+num`` ``__pos__`` Positive
221 | ``num ** num2`` ``__pow__`` Power
222 | ``round(num)`` ``__round__`` Round
223 | ``num.__sizeof__()`` ``__sizeof__`` Bytes for internal representation
224 | ``str(num)`` ``__str__`` String conversion
225 | ``num - num2`` ``__sub__`` Subtraction
226 | ``num / num2`` ``__truediv__`` Float division
227 | ``math.trunc(num)`` ``__trunc__`` Truncation
228 | ====================== ================== =====================================
229 |
230 | See ``math.isclose`` and ``cmath.isclose`` for floating point equality testing.
231 |
232 | .. longtable: format: {p{.3\textwidth} l >{\raggedright\arraybackslash}p{.3\textwidth}}
233 |
234 | .. table:: Integer specific methods and operations
235 |
236 | ==================== ================== =====================================
237 | Operation Provided By Result
238 | ==================== ================== =====================================
239 | ``num & num2`` ``__and__`` Bitwise and
240 | ``math.ceil(num)`` ``__ceil__`` Ceiling
241 | ``math.floor(num)`` ``__floor__`` Floor
242 | ``~num`` ``__invert__`` Bitwise inverse
243 | ``num << num2`` ``__lshift__`` Left shift
244 | ``num | num2`` ``__or__`` Bitwise or
245 | ``num >> num2`` ``__rshift__`` Right shift
246 | ``num ^ num2`` ``__xor__`` Bitwise xor
247 | ``num.bit_length()`` ``bit_length`` Number of bits necessary
248 | ==================== ================== =====================================
249 |
250 | .. longtable: format: {p{.4\textwidth} p{.5\textwidth}}
251 |
252 | .. table:: Float specific methods and operations
253 |
254 | ================================== ========================
255 | Operation Result
256 | ================================== ========================
257 | ``f.as_integer_ratio()`` Returns num, denom tuple
258 | ``f.is_integer()`` Boolean if whole number
259 | ``f.hex()`` Hex base 2 version
260 | ``float.fromhex(h)`` Convert above to float
261 | ================================== ========================
262 |
263 | See IEEE 754 for how ``.as_integer_ratio`` works. See ``math.isclose`` for comparing float values.
264 |
265 |
266 |
267 | Strings
268 | -----------
269 |
270 | Python 3 strings hold Unicode data. Python has a few ways to represent strings. There is also a bytes type (PEP 3137). Strings can be created using string literals or by passing an object, or bytes into ``str``::
271 |
272 | >>> str(1)
273 | '1'
274 |
275 |
276 | .. raw:: latex
277 |
278 | \Needspace{10\baselineskip}
279 |
280 |
281 | .. longtable: format: {r l}
282 |
283 | .. table:: String types
284 |
285 | ================ ===========================
286 | Type Example
287 | ================ ===========================
288 | String ``"hello\tthere"``
289 | String ``'hello'``
290 | String ``'''He said, "hello"'''``
291 | Raw string ``r'hello\tthere'``
292 | Byte string ``b'hello'``
293 | ================ ===========================
294 |
295 | .. longtable: format: {>{\hangindent=1em\hangafter=1\raggedright\arraybackslash }p{.3\textwidth} >{\hangindent=1em\hangafter=1\raggedright\arraybackslash }p{.6\textwidth}}
296 |
297 | .. table:: Escape Characters
298 |
299 | =================== =================
300 | Escape Sequence Output
301 | =================== =================
302 | ``\`` newline Ignore trailing newline in triple quoted string
303 | ``\\`` Backslash
304 | ``\'`` Single quote
305 | ``\"`` Double quote
306 | ``\a`` ASCII Bell
307 | ``\b`` ASCII Backspace
308 | ``\n`` Newline
309 | ``\r`` ASCII carriage return
310 | ``\t`` Tab
311 | ``\u12af`` Unicode 16 bit
312 | ``\U12af89bc`` Unicode 32 bit
313 | ``\N{BLACK STAR}`` Unicode name
314 | ``\o84`` Octal character
315 | ``\xFF`` Hex character
316 | =================== =================
317 |
318 |
319 |
320 | .. longtable: format: {p{.3\textwidth} l >{\raggedright\arraybackslash}p{.3\textwidth}}
321 |
322 |
323 | .. longtable: format: {>{\hangindent=1em\hangafter=1\raggedright\arraybackslash }p{.3\textwidth} l >{\hangindent=1em\hangafter=1\raggedright\arraybackslash }p{.3\textwidth}}
324 |
325 | .. table:: String operations
326 |
327 | ============================= ========================= ==========================================================
328 | Operation Provided By Result
329 | ============================= ========================= ==========================================================
330 | ``s + s2`` ``__add__`` String concatenation
331 | ``"foo" in s`` ``__contains__`` Membership
332 | ``s == s2`` ``__eq__`` Equality
333 | ``s >= s2`` ``__ge__`` Greater or equal
334 | ``s[0]`` ``__getitem__`` Index operation
335 | ``s > s2`` ``__gt__`` Greater
336 | ``s <= s2`` ``__le__`` Less than or equal
337 | ``len(s)`` ``__len__`` Length
338 | ``s < s2`` ``__lt__`` Less than
339 | ``s % (1, 'foo')`` ``__mod__`` Formatting
340 | ``s * 3`` ``__mul__`` Repetition
341 | ``s != s2`` ``__ne__`` Not equal
342 | ``repr(s)`` ``__repr__`` Programmer friendly string
343 | ``s.__sizeof__()`` ``__sizeof__`` Bytes for internal representation
344 | ``str(s)`` ``__str__`` User friendly string
345 | ============================= ========================= ==========================================================
346 |
347 |
348 | .. longtable: format: {>{\hangindent=1em\hangafter=1 }p{.35\textwidth} p{.55\textwidth}}
349 |
350 | .. prevent header at bottom of page
351 |
352 | .. raw:: latex
353 |
354 | \Needspace{5\baselineskip}
355 |
356 |
357 | .. longtable: format: {>{\hangindent=1em\hangafter=1\raggedright\arraybackslash }p{.3\textwidth} >{\hangindent=1em\hangafter=1\raggedright\arraybackslash }p{.6\textwidth}}
358 |
359 | .. table:: String methods
360 |
361 | ======================================================= ===========================================================
362 | Operation Result
363 | ======================================================= ===========================================================
364 | ``s.capitalize()`` Capitalizes a string
365 | ``s.casefold()`` Lowercase in a unicode compliant manner
366 | ``s.center(w, [char])`` Center a string in ``w`` spaces with ``char`` (default ``" "``)
367 | ``s.count(sub, [start, [end]])`` Count ``sub`` in ``s`` between ``start`` and ``end``
368 | ``s.encode(encoding, errors= 'strict')`` Encode a string into bytes
369 | ``s.endswith(sub)`` Check for a suffix
370 | ``s.expandtabs( tabsize=8)`` Replaces tabs with spaces
371 | ``s.find(sub, [start, [end]])`` Find substring or return ``-1``
372 | ``s.format(*args, **kw)`` Format string
373 | ``s.format_map( mapping)`` Format strings with a mapping
374 | ``s.index(sub, [start, [end]])`` Find substring or raise ``ValueError``
375 | ``s.isalnum()`` Boolean if alphanumeric
376 | ``s.isalpha()`` Boolean if alphabetic
377 | ``s.isdecimal()`` Boolean if decimal
378 | ``s.isdigit()`` Boolean if digit
379 | ``s.isidentifier()`` Boolean if valid identifier
380 | ``s.islower()`` Boolean if lowercase
381 | ``s.isnumeric()`` Boolean if numeric
382 | ``s.isprintable()`` Boolean if printable
383 | ``s.isspace()`` Boolean if whitespace
384 | ``s.istitle()`` Boolean if titlecased
385 | ``s.isupper()`` Boolean if uppercased
386 | ``s.join(iterable)`` Return a string inserted between sequence
387 | ``s.ljust(w, [char])`` Left justify in ``w`` spaces with ``char`` (default ``' '``)
388 | ``s.lower()`` Lowercase
389 | ``s.lstrip([chars])`` Left strip ``chars`` (default spacing).
390 | ``s.partition(sub)`` Split string at first occurrence of substring, return ``(before, sub, after)``
391 | ``s.removeprefix(sub)`` Remove ``sub`` from start of string
392 | ``s.removesuffix(sub)`` Remove ``sub`` from end of string
393 | ``s.replace(old, new, [count])`` Replace substring with new string
394 | ``s.rfind(sub, [start, [end]])`` Find rightmost substring or return ``-1``
395 | ``s.rindex(sub, [start, [end]])`` Find rightmost substring or raise ``ValueError``
396 | ``s.rjust(w, [char)`` Right justify in w spaces with char (default ``" "``)
397 | ``s.rpartition(sub)`` Rightmost partition
398 | ``s.rsplit([sep, [maxsplit=-1])`` Rightmost split by ``sep`` (defaults to whitespace)
399 | ``s.rstrip([chars])`` Right strip
400 | ``s.split([sep, [maxsplit=-1]])`` Split a string into sequence around substring
401 | ``s.splitlines( keepends=False)`` Break string at line boundaries
402 | ``s.startswith( prefix, [start, [end]])`` Check for prefix
403 | ``s.strip([chars])`` Remove leading and trailing whitespace (default) or ``chars``
404 | ``s.swapcase()`` Swap casing of string
405 | ``s.title()`` Titlecase string
406 | ``s.translate(table)`` Use a translation table to replace strings
407 | ``s.upper()`` Uppercase
408 | ``s.zfill(width)`` Left fill with ``0`` so string fills ``width`` (no truncation)
409 | ======================================================= ===========================================================
410 |
411 |
412 | Lists
413 | -----
414 |
415 | Lists are ordered mutable sequences. They can be created with the list literal syntax::
416 |
417 | >>> people = ['Paul', 'John', 'George']
418 | >>> people.append('Ringo')
419 |
420 | Lists can also be created by calling the constructor with an optional sequence::
421 |
422 |
423 | >>> people = list(('Paul', 'John', 'George'))
424 | >>> people
425 | ['Paul', 'John', 'George']
426 |
427 | The ``in`` operator is useful for checking membership on sequences::
428 |
429 | >>> 'Yoko' in people
430 | False
431 |
432 | If we need the index number during iteration, the ``enumerate`` function gives us a tuple of index, item pairs::
433 |
434 | >>> for i, name in enumerate(people, 1):
435 | ... print('{} - {}'.format(i, name))
436 | 1 - Paul
437 | 2 - John
438 | 3 - George
439 |
440 |
441 | We can do index operations on most sequences::
442 |
443 | >>> people[0]
444 | 'Paul'
445 | >>> people[-1] # len(people) - 1
446 | 'George'
447 |
448 | We can also do *slicing* operations on most sequences::
449 |
450 | >>> people[1:2]
451 | ['John']
452 | >>> people[:1] # Implicit start at 0
453 | ['Paul']
454 | >>> people[1:] # Implicit end at len(people)
455 | ['John', 'George']
456 | >>> people[::2] # Take every other item
457 | ['Paul', 'George']
458 | >>> people[::-1] # Reverse sequence
459 | ['George', 'John', 'Paul']
460 |
461 |
462 | .. raw:: latex
463 |
464 | \Needspace{5\baselineskip}
465 |
466 |
467 | .. longtable: format: {p{.25\textwidth} l >{\raggedright\arraybackslash}p{.35\textwidth}}
468 |
469 | .. longtable: format: {>{\hangindent=1em\hangafter=1 }p{.25\textwidth} l >{\hangindent=1em\hangafter=1 }p{.35\textwidth}}
470 |
471 | .. table:: List Operations
472 |
473 | ================================== ========================= ============================================================
474 | Operation Provided By Result
475 | ================================== ========================= ============================================================
476 | ``l + l2`` ``__add__`` List concatenation (see ``.extend``)
477 | ``"name" in l`` ``__contains__`` Membership
478 | ``del l[idx]`` ``__del__`` Remove item at index ``idx`` (see ``.pop``)
479 | ``l == l2`` ``__eq__`` Equality
480 | ``"{}".format(l)`` ``__format__`` String format of list
481 | ``l >= l2`` ``__ge__`` Greater or equal. Compares items in lists from left
482 | ``l[idx]`` ``__getitem__`` Index operation
483 | ``l > l2`` ``__gt__`` Greater. Compares items in lists from left
484 | No hash ``__hash__`` Set to ``None`` to ensure you can't insert in dictionary
485 | ``l += l2`` ``__iadd__`` Augmented (mutates ``l``) concatenation
486 | ``l *= 3`` ``__imul__`` Augmented (mutates ``l``) repetition
487 | ``for thing in l:`` ``__iter__`` Iteration
488 | ``l <= l2`` ``__le__`` Less than or equal. Compares items in lists from left
489 | ``len(l)`` ``__len__`` Length
490 | ``l < l2`` ``__lt__`` Less than. Compares items in lists from left
491 | ``l * 2`` ``__mul__`` Repetition
492 | ``l != l2`` ``__ne__`` Not equal
493 | ``repr(l)`` ``__repr__`` Programmer friendly string
494 | ``reversed(l)`` ``__reversed__`` Reverse
495 | ``foo * l`` ``__rmul__`` Called if ``foo`` doesn't implement ``__mul__``
496 | ``l[idx] = 'bar'`` ``__setitem__`` Index operation to set value
497 | ``l.__sizeof__()`` ``__sizeof__`` Bytes for internal representation
498 | ``str(l)`` ``__str__`` User friendly string
499 | ================================== ========================= ============================================================
500 |
501 | .. longtable: format: {p{.4\textwidth} p{.55\textwidth}}
502 |
503 | .. longtable: format: {>{\hangindent=1em\hangafter=1 }p{.4\textwidth} >{\hangindent=1em\hangafter=1 }p{.55\textwidth}}
504 |
505 | .. table:: List Methods
506 |
507 | ============================================================ ============================================================
508 | Operation Result
509 | ============================================================ ============================================================
510 | ``l.append(item)`` Append ``item`` to end
511 | ``l.clear()`` Empty list (mutates ``l``)
512 | ``l.copy()`` Shallow copy
513 | ``l.count(thing)`` Number of occurrences of ``thing``
514 | ``l.extend(l2)`` List concatenation (mutates ``l``)
515 | ``l.index(thing[, start[, stop]])`` Index of ``thing`` else ``ValueError``. Python 3.10 has added optional arguments start and stop to search for ``thing`` within a subsection of the array
516 | ``l.insert(idx, bar)`` Insert ``bar`` at index ``idx``
517 | ``l.pop([idx])`` Remove last item or item at ``idx``
518 | ``l.remove(bar)`` Remove first instance of ``bar`` else ``ValueError``
519 | ``l.reverse()`` Reverse (mutates ``l``)
520 | ``l.sort([key=], reverse=False)`` In-place sort, by optional ``key`` function (mutates ``l``)
521 | ============================================================ ============================================================
522 |
523 |
524 |
525 | Dictionaries
526 | --------------
527 |
528 | Dictionaries are mutable mappings of keys to values. Keys
529 | must be hashable, but values can be any object. Here is a dictionary
530 | literal::
531 |
532 | >>> instruments = {'Paul': 'Bass',
533 | ... 'John': 'Guitar'}
534 |
535 | Dictionaries can also be made by calling the constructor with an optional
536 | mapping, an iterable, or using keyword arguments. The iterable must be a sequence of 2-pairs::
537 |
538 | >>> instruments = dict([('Paul', 'Bass'),
539 | ... ('John', 'Guitar')])
540 |
541 | Here is an example using keyword arguments::
542 |
543 | >>> instruments = dict(Paul='Bass',
544 | ... John='Guitar')
545 |
546 |
547 | If you have two parallel arrays the following also works::
548 |
549 | >>> names = ['Paul', 'John']
550 | >>> insts = ['Bass', 'Guitar']
551 | >>> instruments = dict(zip(names, insts))
552 |
553 | They support index operations, containment, and looping::
554 |
555 | >>> instruments['George'] = 'Guitar'
556 | >>> 'Ringo' in instruments
557 | False
558 |
559 | >>> for name in instruments:
560 | ... print('{} - {}'.format(name,
561 | ... instruments[name]))
562 | Paul - Bass
563 | John - Guitar
564 | George - Guitar
565 |
566 | Dictionaries have an ``.update`` method to merge two dictionaries::
567 |
568 | >>> i2 = {'Ringo': 'Drums'}
569 | >>> i2.update(instruments)
570 | >>> i2
571 | {'Ringo': 'Drums', 'Paul': 'Bass', 'John': 'Guitar',
572 | 'George': 'Guitar'}
573 |
574 | PEP 448 introduced Additional Unpacking Generalizations in Python 3.5. This adds the ability to unpack into a dictionary literal and can be used to merge dictionaries::
575 |
576 | >>> {'Ringo': 'Drums', **instruments}
577 | {'Ringo': 'Drums', 'Paul': 'Bass', 'John': 'Guitar',
578 | 'George': 'Guitar'}
579 |
580 | You can unpack into the ``dict`` constructor if the keys are strings::
581 |
582 | >>> dict(Ringo='Drums', **instruments)
583 | {'Ringo': 'Drums', 'Paul': 'Bass', 'John': 'Guitar',
584 | 'George': 'Guitar'}
585 |
586 | PEP 584 added union operators to dictionaries (Python 3.9)::
587 |
588 | >>> {'Ringo': 'Drums'} | instruments
589 | {'Ringo': 'Drums', 'Paul': 'Bass', 'John': 'Guitar',
590 | 'George': 'Guitar'}
591 |
592 |
593 | .. longtable: format: {p{.25\textwidth} l >{\raggedright\arraybackslash}p{.35\textwidth}}
594 |
595 |
596 | .. longtable: format: {>{\hangindent=1em\hangafter=1\raggedright\arraybackslash }p{.25\textwidth} l >{\hangindent=1em\hangafter=1\raggedright\arraybackslash }p{.35\textwidth}}
597 |
598 | .. table:: Magic Dictionary Methods
599 |
600 | ======================================= ========================= ============================================================
601 | Operation Provided By Result
602 | ======================================= ========================= ============================================================
603 | ``key in d`` ``__contains__`` Membership
604 | ``del d[key]`` ``__delitem__`` Delete key
605 | ``d == d2`` ``__eq__`` Equality. Dicts are equal or not equal
606 | ``"{}".format(d)`` ``__format__`` String format of dict
607 | ``d[key]`` ``__getitem__`` Get value for ``key`` (see ``.get``)
608 | ``for key in d:`` ``__iter__`` Iteration over keys
609 | ``len(d)`` ``__len__`` Length
610 | ``d != d2`` ``__ne__`` Not equal
611 | ``repr(d)`` ``__repr__`` Programmer friendly string
612 | ``d[key] = value`` ``__setitem__`` Set ``value`` for ``key``
613 | ``d.__sizeof__()`` ``__sizeof__`` Bytes for internal representation
614 | ``d | d2`` ``__or__`` Return a new dictionary overwriting common keys with ``d2``
615 | ``d |= d2`` ``__ior__`` Mutate ``d`` with values of ``d2`` (dictionary or iterable of (key, value) pairs)
616 | ======================================= ========================= ============================================================
617 |
618 |
619 | .. longtable: format: {p{.3\textwidth} >{\raggedright\arraybackslash}p{.6\textwidth}}
620 |
621 | .. longtable: format: {>{\hangindent=1em\hangafter=1 }p{.3\textwidth} >{\hangindent=1em\hangafter=1 }p{.6\textwidth}}
622 |
623 | .. table:: Dictionary Methods
624 |
625 |
626 | ================================================================= ============================================================
627 | Operation Result
628 | ================================================================= ============================================================
629 | ``d.clear()`` Remove all items (mutates ``d``)
630 | ``d.copy()`` Shallow copy
631 | ``d.fromkeys(iter, value=None)`` Create dict from iterable with values set to value
632 | ``d.get(key, [default])`` Get value for ``key`` or return default (``None``)
633 | ``d.items()`` View of (key, value) pairs
634 | ``d.keys()`` View of keys
635 | ``d.pop(key, [default])`` Return value for key or default (``KeyError`` if not set)
636 | ``d.popitem()`` Return arbitrary (key, value) tuple. ``KeyError`` if empty
637 | ``d.setdefault(k, [default])`` Does ``d.get(k, default)``. If ``k`` missing, sets to default
638 | ``d.update(d2)`` Mutate ``d`` with values of ``d2`` (dictionary or iterable of (key, value) pairs)
639 | ``d.values()`` View of values
640 | ================================================================= ============================================================
641 |
642 |
643 | Tuples
644 | -------
645 |
646 | Tuples are immutable sequences. Typically they are used to store
647 | *record* type data. Here they are created with tuple literals::
648 |
649 | >>> member = ('Paul', 'Bass', 1942)
650 | >>> member2 = ('Ringo', 'Drums', 1940)
651 |
652 | You can also use the tuple constructor which takes an optional sequence::
653 |
654 | >>> member2 = tuple(['Ringo', 'Drums', 1940])
655 |
656 | Note that parentheses aren't usually required::
657 |
658 | >>> row = 1, 'Fred' # 2 item tuple
659 | >>> row2 = (2, 'Bob') # 2 item tuple
660 | >>> row3 = ('Bill') # String!
661 | >>> row4 = ('Bill',) # 1 item tuple
662 | >>> row5 = 'Bill', # 1 item tuple
663 | >>> row6 = () # Empty tuple
664 |
665 | Named tuples can be used in place of normal tuples and allow context (or names)
666 | to be added to positional members. The syntax for creating them is a little
667 | different because we are dynamically creating a class first (hence the
668 | capitalized variable)::
669 |
670 | >>> from collections import namedtuple
671 | >>> Member = namedtuple('Member',
672 | ... 'name, instrument, birth_year')
673 | >>> member3 = Member('George', 'Guitar', 1943)
674 |
675 | We can access members by position or name (name allows us to be more explicit)::
676 |
677 | >>> member3[0]
678 | 'George'
679 |
680 | >>> member3.name
681 | 'George'
682 |
683 | .. longtable: format: {p{.3\textwidth} l >{\raggedright\arraybackslash}p{.3\textwidth}}
684 |
685 | .. longtable: format: {>{\hangindent=1em\hangafter=1\raggedright\arraybackslash }p{.3\textwidth} l >{\hangindent=1em\hangafter=1\raggedright\arraybackslash }p{.3\textwidth}}
686 |
687 | .. table:: Tuple Operations
688 |
689 | ================================== ========================= ============================================================
690 | Operation Provided Result
691 | ================================== ========================= ============================================================
692 | ``t + t2`` ``__add__`` Tuple concatenation
693 | ``"name" in t`` ``__contains__`` Membership
694 | ``t == t2`` ``__eq__`` Equality
695 | ``"{}".format(t)`` ``__format__`` String format of tuple
696 | ``t >= t2`` ``__ge__`` Greater or equal. Compares items in tuple from left
697 | ``t[idx]`` ``__getitem__`` Index operation
698 | ``t > t2`` ``__gt__`` Greater. Compares items in tuple from left
699 | ``hash(t)`` ``__hash__`` For set/dict insertion
700 | ``for thing in t:`` ``__iter__`` Iteration
701 | ``t <= t2`` ``__le__`` Less than or equal. Compares items in tuple from left
702 | ``len(t)`` ``__len__`` Length
703 | ``t < t2`` ``__lt__`` Less than. Compares items in tuple from left
704 | ``t * 2`` ``__mul__`` Repetition
705 | ``t != t2`` ``__ne__`` Not equal
706 | ``repr(t)`` ``__repr__`` Programmer friendly string
707 | ``foo * t`` ``__rmul__`` Called if ``foo`` doesn't implement ``__mul__``
708 | ``t.__sizeof__()`` ``__sizeof__`` Bytes for internal representation
709 | ``str(t)`` ``__str__`` User friendly string
710 | ================================== ========================= ============================================================
711 |
712 |
713 | .. longtable: format: {p{.3\textwidth} p{.6\textwidth}}
714 |
715 | .. table:: Tuple Methods
716 |
717 | ============================================================ ============================================================
718 | Operation Result
719 | ============================================================ ============================================================
720 | ``t.count(item)`` Count of item
721 | ``t.index(thing)`` Index of ``thing`` else ``ValueError``
722 | ============================================================ ============================================================
723 |
724 | Sets
725 | -----
726 |
727 | A set is a mutable unordered collection that cannot contain duplicates.
728 | Sets can be created with the literal syntax::
729 |
730 | >>> vowels = {'a', 'e', 'i', 'o', 'u'}
731 |
732 | Set can also be created by passing a sequence to the constructor::
733 |
734 | >>> vowels = set('aeiou')
735 |
736 |
737 | Sets are used to
738 | remove duplicates and test for membership::
739 |
740 | >>> digits = [0, 1, 1, 2, 3, 4, 5, 6,
741 | ... 7, 8, 9]
742 | >>> digit_set = set(digits) # remove extra 1
743 |
744 | >>> 9 in digit_set
745 | True
746 |
747 | Sets are useful because they provide *set operations*, such as union
748 | (``|``), intersection (``&``), difference (``-``), and xor (``^``)::
749 |
750 | >>> odd = {1, 3, 5, 7, 9}
751 | >>> prime = set([2, 3, 5, 7])
752 | >>> even = digit_set - odd
753 | >>> even
754 | {0, 2, 4, 6, 8}
755 |
756 | >>> prime & even # in intersection
757 | {2}
758 |
759 | >>> odd | even # in both
760 | {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
761 |
762 | >>> even ^ prime # not in both
763 | {0, 3, 4, 5, 6, 7, 8}
764 |
765 | .. raw:: latex
766 |
767 | \Needspace{10\baselineskip}
768 |
769 |
770 | .. note::
771 |
772 | There is no literal syntax for an empty set. You need to use::
773 |
774 | >>> empty = set()
775 |
776 |
777 |
778 | .. longtable: format: {p{.25\textwidth} l >{\raggedright\arraybackslash}p{.35\textwidth}}
779 |
780 | .. longtable: format: {>{\hangindent=1em\hangafter=1\raggedright\arraybackslash }p{.25\textwidth} l >{\hangindent=1em\hangafter=1\raggedright\arraybackslash }p{.35\textwidth}}
781 |
782 | .. table:: Set Operations
783 |
784 | ======================================= ========================= ============================================================
785 | Operation Provided By Result
786 | ======================================= ========================= ============================================================
787 | ``s & s2`` ``__and__`` Set intersection (see ``.intersection``)
788 | ``"name" in s`` ``__contains__`` Membership
789 | ``s == s2`` ``__eq__`` Equality. Sets are equal or not equal
790 | ``"{}".format(s)`` ``__format__`` String format of set
791 | ``s >= s2`` ``__ge__`` ``s`` in ``s2`` (see ``.issuperset``)
792 | ``s > s2`` ``__gt__`` Strict superset (``s >= s2`` but ``s != s2``)
793 | No hash ``__hash__`` Set to ``None`` to ensure you can't insert in dictionary
794 | ``s &= s2`` ``__iand__`` Augmented (mutates ``s``) intersection (see ``.intersection _update``)
795 | ``s |= s2`` ``__ior__`` Augmented (mutates ``s``) union (see ``.update``)
796 | ``s -= s2`` ``__isub__`` Augmented (mutates ``s``) difference (see ``.difference_update``)
797 | ``for thing in s:`` ``__iter__`` Iteration
798 | ``s ^= s2`` ``__ixor__`` Augmented (mutates ``s`` ) xor (see ``.symmetric _difference_update``)
799 | ``s <= s2`` ``__le__`` ``s2`` in ``s`` (see ``.issubset``)
800 | ``len(s)`` ``__len__`` Length
801 | ``s < s2`` ``__lt__`` Strict subset (``s <= s2`` but ``s != s2``)
802 | ``s != s2`` ``__ne__`` Not equal
803 | ``s | s2`` ``__or__`` Set union (see ``.union``)
804 | ``foo & s`` ``__rand__`` Called if ``foo`` doesn't implement ``__and__``
805 | ``repr(s)`` ``__repr__`` Programmer friendly string
806 | ``foo | s`` ``__ror__`` Called if ``foo`` doesn't implement ``__or__``
807 | ``foo - s`` ``__rsub__`` Called if ``foo`` doesn't implement ``__sub__``
808 | ``foo ^ s`` ``__rxor__`` Called if ``foo`` doesn't implement ``__xor__``
809 | ``s.__sizeof__()`` ``__sizeof__`` Bytes for internal representation
810 | ``str(s)`` ``__str__`` User friendly string
811 | ``s - s2`` ``__sub__`` Set difference (see ``.difference``)
812 | ``s ^ s2`` ``__xor__`` Set xor (see ``.symmetric _difference``)
813 | ======================================= ========================= ============================================================
814 |
815 | .. raw:: latex
816 |
817 | %\Needspace{5\baselineskip}
818 | \clearpage
819 |
820 |
821 |
822 | .. longtable: format: {p{.55\textwidth} p{.35\textwidth}}
823 |
824 | .. longtable: format: {>{\hangindent=1em\hangafter=1\arraybackslash }p{.6\textwidth} >{\hangindent=1em\hangafter=1\raggedright\arraybackslash }p{.30\textwidth}}
825 |
826 | .. table:: Set Methods
827 |
828 | ================================================================= ============================================================
829 | Operation Result
830 | ================================================================= ============================================================
831 | ``s.add(item)`` Add ``item`` to ``s`` (mutates ``s``)
832 | ``s.clear()`` Remove elements from ``s`` (mutates ``s``)
833 | ``s.copy()`` Shallow copy
834 | ``s.difference(s2)`` Return set with elements from ``s`` and not ``s2``
835 | ``s.difference_update(s2)`` Remove ``s2`` items from ``s`` (mutates ``s``)
836 | ``s.discard(item)`` Remove ``item`` from s (mutates ``s``). No error on missing ``item``
837 | ``s.intersection(s2)`` Return set with elements from both sets
838 | ``s.intersection_update(s2)`` Update ``s`` with members of ``s2`` (mutates ``s``)
839 | ``s.isdisjoint(s2)`` ``True`` if there is no intersection of these two sets
840 | ``s.issubset(s2)`` ``True`` if all elements of ``s`` are in ``s2``
841 | ``s.issuperset(s2)`` ``True`` if all elements of ``s2`` are in ``s2``
842 | ``s.pop()`` Remove arbitrary item from s (mutates ``s``). ``KeyError`` on missing ``item``
843 | ``s.remove(item)`` Remove ``item`` from s (mutates ``s``). ``KeyError`` on missing ``item``
844 | ``s.symmetric_difference(s2)`` Return set with elements only in one of the sets
845 | ``s.symmetric_difference_update(s2)`` Update ``s`` with elements only in one of the sets (mutates ``s``)
846 | ``s.union(s2)`` Return all elements of both sets
847 | ``s.update(s2)`` Update ``s`` with all elements of both sets (mutates ``s``)
848 | ================================================================= ============================================================
849 |
850 | Built in Functions
851 | =====================
852 |
853 | In the default namespace you have access to various callables:
854 |
855 | .. longtable: format: {p{.35\textwidth} p{.55\textwidth}}
856 |
857 | .. longtable: format: {>{\hangindent=1em\hangafter=1\raggedright\arraybackslash }p{.35\textwidth} >{\hangindent=1em\hangafter=1\raggedright\arraybackslash }p{.55\textwidth}}
858 |
859 | .. table:: Built in callables
860 |
861 | ================================================================= ============================================================
862 | Operation Result
863 | ================================================================= ============================================================
864 | ``abs(x)`` Absolute value protocol (call ``x.__abs__()``)
865 | ``all(seq)`` Boolean check if all items in ``seq`` are truthy
866 | ``any(seq)`` Boolean check if at least one item in ``seq`` is truthy
867 | ``ascii(x)`` ASCII representation of object
868 | ``bin(i)`` String containing binary version of number (``int(bin(i), 2)`` to reverse)
869 | ``bool(x)`` Boolean protocol (call ``x.__bool__()``)
870 | ``breakpoint()`` Create a breakpoint (convenience to call ``sys.breakpointhook()`` ie ``import pdb; pdb.set_trace()``)
871 | ``bytearray(x)`` Create a mutable bytearray from iterable of ints, text string, bytes, an integer, or pass nothing for an empty bytearray
872 | ``bytes(x)`` Create an immutable bytes from iterable of ints, text string, bytes, an integer, or pass nothing for an empty bytes
873 | ``callable(x)`` Boolean check if you can do ``x()`` (ie ``x.__call__`` exists)
874 | ``chr(i)`` Convert integer codepoint to Unicode string (``ord(chr(i))`` to reverse)
875 | ``@classmethod`` Use to decorate a method so you can invoke it on the class
876 | ``compile(source, fname, mode)`` Compile ``source`` to code (``fname`` used for error, ``mode`` is ``exec``: module, ``single``: statement, ``eval``: expression). Can run ``eval(code)`` on expression, ``exec(code)`` on statement
877 | ``complex(i, y)`` Create complex number
878 | ``copyright`` Python copyright string
879 | ``credits`` Python credits string
880 | ``delattr(obj, attr)`` Remove attribute from ``obj`` (``del obj.attr``)
881 | ``dict([x])`` Create a dictionary from a mapping, iterable of k,v tuples, named parameters, or pass nothing for an empty dictionary
882 | ``dir([obj])`` List attributes of ``obj``, or names in current namespace if no ``obj`` provided (see ``vars``)
883 | ``divmod(num, denom)`` Return tuple pair of ``num//denom`` and ``num%denom``
884 | ``enumerate(seq, [start])`` Return iterator of index, item tuple pairs. Index begins at ``start`` or ``0`` (default)
885 | ``eval(source, globals=None, locals=None)`` Run ``source`` (expression string or result of ``compile``) with globals and locals
886 | ``exec(source, globals=None, locals=None)`` Run ``source`` (statement string or result of ``compile``) with globals and locals
887 | ``exit([code])`` Exit Python interpreter and return code (default 0)
888 | ``filter([function], seq)`` Return iterator of items where ``function(item)`` is truthy (or ``item`` is truthy if ``function`` is missing)
889 | ``float(x)`` Convert string or number to float (call ``x.__float__()``)
890 | ``format(obj, fmt)`` Format protocol (call ``obj.__format__(fmt)``)
891 | ``frozenset([seq])`` Create ``frozenset`` from ``seq`` (empty if missing)
892 | ``getattr(obj, attr)`` Get attribute from ``obj`` (``obj.attr``)
893 | ``globals()`` Return *mutable* dictionary with current global variables
894 | ``hasattr(obj, attr)`` Check if attribute on ``obj`` (``obj.attr`` doesn't throw ``AttributeError``)
895 | ``hash(x)`` Hash value protocol for object (call ``x.__hash__()``)
896 | ``help([x])`` Start interactive help (if no ``x``), or print documentation for ``x``
897 | ``hex(i)`` String containing hexadecimal version of number (``int(hex(i), 16)`` to reverse)
898 | ``id(x)`` Identity of ``x``
899 | ``input([prompt])`` Read string from standard input
900 | ``int(x, [base=10])`` Create integer from number or string
901 | ``isinstance(obj, class_or_tuple)`` Boolean check if ``obj`` is an instance or subclass of ``class_or_tuple``. As of PEP 604 (Python 3.10), calls to this method is also supported with a type union object.
902 | ``issubclass(cls, class_or_tuple)`` Boolean check if ``cls`` is the class or derived from ``class_or_tuple``. As of PEP 604 (Python 3.10), calls to this method is also supported with a type union object.
903 | ``iter(seq)`` Iteration protocol (call ``seq.__iter__()``)
904 | ``len(seq)`` Number of items in sequence
905 | ``license()`` Display Python licenses
906 | ``list([seq])`` Convert ``seq`` to list (empty if missing)
907 | ``locals()`` Return dictionary of local attributes (unlike ``globals``, not guaranteed to update namespace when mutated)
908 | ``map(function, *seqs)`` Call ``function(item)`` for item in ``seqs`` (if single sequence) or ``function(seqs[0][0], seqs[1][0]...)``
909 | ``max(seq, *, [default], [key])`` Return maximum value from ``seq``. ``default`` (value if empty ``seq``) and ``key`` (function to determine magnitude) are keyword parameters.
910 | ``memoryview(obj)`` Create ``memoryview`` from ``obj``
911 | ``min(seq, *, [default], [key])`` Return minimum value from ``seq``. ``default`` (value if empty ``seq``) and ``key`` (function to determine magnitude) are keyword parameters.
912 | ``next(iter, [default])`` Get next item from iteration protocol (call ``iter.__next__()``), if ``default`` provide return instead of raising ``StopIteration``
913 | ``object`` Root base type
914 | ``oct(i)`` String containing octal version of number (``int(oct(i), 8)`` to reverse)
915 | ``open(filename, [mode], [encoding], [errors])`` Open a file
916 | ``ord(s)`` Convert Unicode string to integer codepoint (``chr(ord(s))`` to reverse)
917 | ``pow(num, exp, [z])`` Power protocol (call ``num.__pow__(exp, z)``) (``num ** exp`` or ``num ** exp % z``)
918 | ``print(val, [val2 ...], *, sep=' ', end='\n', file=sys.stdout)`` Print values to ``file``. Print protocol (call ``val.__str__()``)
919 | ``@property`` Decorator to turn a method into an attribute
920 | ``quit()`` Quit interpreter
921 | ``range([start], stop, [step])`` Return range object that iterates from ``start`` (default ``0``) to ``stop - 1``, by ``step`` increments (default ``1``)
922 | ``repr(x)`` Representation protocol (call ``x.__repr__()``)
923 | ``reversed(seq)`` Reverse iterator
924 | ``round(num, [ndigits=0])`` Round to ``ndigits`` protocol (call ``num.__round__()``) (use banker's rounding)
925 | ``set([seq])`` Create ``set`` from ``seq`` (empty if missing)
926 | ``setattr(obj, attr, val)`` Set attribute on ``obj`` (``obj.attr = val``)
927 | ``slice([start], stop, [step])`` Create ``slice`` object
928 | ``sorted(seq, * [key=None], [reverse=False])`` Sorted list in ascending order (use ``key`` function to customize sort property)
929 | ``@staticmethod`` Use to decorate a method so you can invoke it on the class or instance
930 | ``str(obj)`` Create string (call ``obj.__str__()``)
931 | ``str(bytes, [encoding], [errors])`` Create string from bytes (``errors`` defaults to ``strict``)
932 | ``sum(seq, [start=0])`` Sum values from ``seq`` (use ``start`` as initial value)
933 | ``super()`` Get access to superclass
934 | ``tuple([seq])`` Convert ``seq`` to tuple (empty if missing)
935 | ``type(name, bases, dict)`` Create a new type of ``name``, with base classes ``bases``, and attributes ``dict``
936 | ``type(obj)`` Return type of ``obj``
937 | ``vars([obj])`` Return ``obj.__dict__`` or ``locals()`` if missing (see ``dir``)
938 | ``zip(seq1, [seq2, ...], [strict=False])`` Return iterable of tuples of ``(seq1[0], seq2[0])``, ``(seq1[1], seq2[1])``, ... until shortest sequence (set ``strict=True`` to require all sequences have an equal length)
939 | ================================================================= ============================================================
940 |
941 | Unicode
942 | =========
943 |
944 | Python 3 represents strings as Unicode. We can *encode* strings to a series of
945 | bytes such as UTF-8. If we have bytes, we can *decode* them to a Unicode string::
946 |
947 | >>> x_sq = 'x²'
948 | >>> x_sq.encode('utf-8')
949 | b'x\xc2\xb2'
950 |
951 | >>> utf8_bytes = b'x\xc2\xb2'
952 | >>> utf8_bytes.decode('utf-8')
953 | 'x²'
954 |
955 | If you have the unicode glyph, you can use that directly. Alternatively, you
956 | can enter a code point using ``\u`` followed by the 16-bit hex value xxxx.
957 | For larger code points, use ``\U`` followed by xxxxxxxx. If you have the
958 | Unicode name (obtained by consulting tables at unicode.org), you can use
959 | the ``\N`` syntax. The following are equivalent::
960 |
961 | >>> result = 'x²'
962 | >>> result = 'x\u00b2'
963 | >>> result = 'x\N{SUPERSCRIPT TWO}'
964 |
965 | .. figure:: img/py/uniencode.png
966 |
967 | Image illustrating *encoding* a Unicode string to a byte representation. In this case,
968 | we convert to UTF-8. There are other byte encodings for this string. If we have a UTF-8
969 | byte string, we can *decode* it into a Unicode string. Note that we should be explicit
970 | about the decoding as there are potentially other encodings that we could decode to
971 | that might give the user erroneous data, or *mojibake*.
972 |
973 | .. note::
974 |
975 | PEP 3131 introduced Unicode identifiers. You can
976 | create variables that have Unicode characters in them::
977 |
978 | >>> Ω_val = 10
979 | >>> Ω_val
980 | 10
981 |
982 | String Formatting
983 | =================
984 |
985 | Most modern Python code uses the ``.format`` method (PEP 3101) to create strings from other parts. The format method uses ``{}`` as a placeholder.
986 |
987 | Inside of the placeholder we can provide different specifiers:
988 |
989 | * ``{0}`` - reference first positional argument
990 | * ``{}`` - reference implicit positional argument
991 | * ``{result}`` - reference keyword argument
992 | * ``{bike.tire}`` - reference attribute of argument
993 | * ``{names[0]}`` - reference first element of argument
994 |
995 | ::
996 |
997 | >>> person = {'name': 'Paul',
998 | ... 'instrument': 'Bass'}
999 | >>> inst = person['instrument']
1000 |
1001 |
1002 | >>> print("Name: {} plays: {}".format(
1003 | ... person['name'], inst))
1004 | Name: Paul plays: Bass
1005 |
1006 | or::
1007 |
1008 | >>> print("Name: {name} "
1009 | ... "plays: {inst}".format(
1010 | ... name=person['name'], inst=inst))
1011 | Name: Paul plays: Bass
1012 |
1013 | You can also use *f-strings* in Python 3.6 (see PEP 498)::
1014 |
1015 | >>> print(f'Name: {person["name"]} plays: {inst}')
1016 | Name: Paul plays: Bass
1017 |
1018 | F-strings inspect variables that are available and allow you to
1019 | inline methods, or attributes from those variables.
1020 |
1021 | In Python 3.8, f-strings support ``=`` for self-documenting
1022 | expressions, which insert the variable name before the value.
1023 | This is useful for debugging::
1024 |
1025 | >>> name = 'Paul'
1026 | >>> print(f'{name=}')
1027 | name='Paul'
1028 |
1029 | You can also use the ``=`` specifier with expressions::
1030 |
1031 | >>> print(f'Name: {person["name"]=} plays: {inst=}')
1032 | Name: person["name"]='Paul' plays: inst='Bass'
1033 |
1034 |
1035 | Conversion Flags
1036 | ----------------
1037 |
1038 | You can provide a *conversion flag* inside the placeholder.
1039 |
1040 | * ``!s`` - Call ``str()`` on argument
1041 | * ``!r`` - Call ``repr()`` on argument
1042 | * ``!a`` - Call ``ascii()`` on argument
1043 |
1044 | ::
1045 |
1046 | >>> class Cat:
1047 | ... def __init__(self, name):
1048 | ... self.name = name
1049 | ... def __format__(self, data):
1050 | ... return "Format"
1051 | ... def __str__(self):
1052 | ... return "Str"
1053 | ... def __repr__(self):
1054 | ... return "Repr"
1055 |
1056 | >>> cat = Cat("Fred")
1057 | >>> print("{} {!s} {!a} {!r}".format(cat, cat, cat,
1058 | ... cat))
1059 | Format Str Repr Repr
1060 |
1061 | Format Specification
1062 | --------------------
1063 |
1064 | You can provide a format specification following a colon. The grammar for format specification is as follows::
1065 |
1066 | [[fill]align][sign][#][0][width][grouping_option]
1067 | [.precision][type]
1068 |
1069 | The following table lists the field meanings.
1070 |
1071 | .. longtable: format: {>{\hangindent=1em\hangafter=1\raggedright\arraybackslash }r >{\hangindent=1em\hangafter=1\raggedright\arraybackslash}p{.55\textwidth}}
1072 |
1073 |
1074 | =================== =================================
1075 | Field Meaning
1076 | =================== =================================
1077 | fill Character used to fill in
1078 | ``align`` (default is space)
1079 | align Alight output ``<`` (left align),
1080 | ``>`` (right align),
1081 | ``^`` (center align), or
1082 | ``=`` (put padding after sign)
1083 | sign For numbers ``+`` (show sign
1084 | on both positive and negative
1085 | numbers,
1086 | ``-`` (default, only on negative), or
1087 | *space* (leading space for
1088 | positive, sign on negative)
1089 | # Prefix integers. ``0b`` (binary),
1090 | ``0o`` (octal), or ``0x`` (hex)
1091 | 0 Enable zero padding
1092 | width Minimum field width
1093 | grouping_option Number separator ``,`` (use comma for thousands
1094 | separator), ``_`` (Use underscore
1095 | for thousands separator)
1096 | .precision For floats (digits after period (floats),
1097 | for non-numerics (max length)
1098 | type Number type or ``s`` (string format default)
1099 | see Integer and Float charts
1100 | =================== =================================
1101 |
1102 | The tables below lists the various options we have for formatting integer and floating point numbers.
1103 |
1104 | =================== =================================
1105 | Integer Types Meaning
1106 | =================== =================================
1107 | ``b`` binary
1108 | ``c`` character - convert to unicode
1109 | character
1110 | ``d`` decimal (default)
1111 | ``n`` decimal with locale specific
1112 | separators
1113 | ``o`` octal
1114 | ``x`` hex (lower-case)
1115 | ``X`` hex (upper-case)
1116 | =================== =================================
1117 |
1118 | .. raw:: latex
1119 |
1120 | \Needspace{5\baselineskip}
1121 |
1122 |
1123 |
1124 | .. longtable: format: {>{\hangindent=1em\hangafter=1\raggedright\arraybackslash }r >{\hangindent=1em\hangafter=1\raggedright\arraybackslash}p{.55\textwidth}}
1125 |
1126 | =================== =================================
1127 | Float Types Meaning
1128 | =================== =================================
1129 | ``e``/``E`` Exponent. Lower/upper-case e
1130 | ``f`` Fixed point
1131 | ``g``/``G`` General. Fixed with exponent for
1132 | large,
1133 | and small numbers (``g`` default)
1134 | ``n`` ``g`` with locale specific
1135 | separators
1136 | ``%`` Percentage (multiplies by 100)
1137 | =================== =================================
1138 |
1139 | Some ``format`` Examples
1140 | ------------------------
1141 |
1142 | Here are a few examples of using ``.format``.
1143 | Let’s format a string in the center of 12 characters surrounded by ``*``.
1144 | ``*`` is the *fill* character, ``^`` is the *align* field, and ``12`` is the
1145 | *width* field::
1146 |
1147 | >>> "Name: {:*^12}".format("Ringo")
1148 | 'Name: ***Ringo****'
1149 |
1150 | Next, we format a percentage using a width of 10, one decimal place and the
1151 | sign before the width padding. ``=`` is the *align* field, ``10.1`` are the *width*
1152 | and *precision* fields, and ``%`` is the *float type*, which converts the number
1153 | to a percentage::
1154 |
1155 | >>> "Percent: {:=10.1%}".format(-44/100)
1156 | 'Percent: - 44.0%'
1157 |
1158 | Below is a binary and a hex conversion. The *integer type* field is set to ``b`` and ``x`` respectively::
1159 |
1160 | >>> "Binary: {:#b}".format(12)
1161 | 'Binary: 0b1100'
1162 |
1163 | >>> "Hex: {:#x}".format(12)
1164 | 'Hex: 0xc'
1165 |
1166 | Files
1167 | ==========
1168 |
1169 | The ``open`` function will take a file path and mode as input and return a file
1170 | handle. There are various modes to open a file, depending on the content and
1171 | your needs. If you open the file in binary mode, you will get bytes out. In text
1172 | mode you will get strings back:
1173 |
1174 | .. longtable: format: {r l}
1175 |
1176 | .. table:: File Modes
1177 |
1178 |
1179 | ================= ======================================================================
1180 | Mode Meaning
1181 | ================= ======================================================================
1182 | ``'r'`` Read text file (default)
1183 | ``'w'`` Write text file (truncates if exists)
1184 | ``'x'`` Write text file, throw ``FileExistsError`` if exists.
1185 | ``'a'`` Append to text file (write to end)
1186 | ``'rb'`` Read binary file
1187 | ``'wb'`` Write binary (truncate)
1188 | ``'w+b'`` Open binary file for reading and writing
1189 | ``'xb'`` Write binary file, throw ``FileExistsError`` if exists.
1190 | ``'ab'`` Append to binary file (write to end)
1191 | ================= ======================================================================
1192 |
1193 | Writing Files
1194 | --------------
1195 |
1196 | We use a context manager with a file to ensure that the file is closed when the context block exits.
1197 |
1198 | ::
1199 |
1200 | >>> with open('/tmp/names.txt', 'w') as fout:
1201 | ... fout.write('Paul\r\nJohn\n')
1202 | ... fout.writelines(['Ringo\n', 'George\n'])
1203 |
1204 | Reading Files
1205 | -------------
1206 |
1207 | With an opened text file, you can iterate over the lines. This saves memory as the lines are only read in as needed::
1208 |
1209 | >>> with open('/tmp/names.txt') as fin:
1210 | ... for line in fin:
1211 | ... print(repr(line))
1212 | 'Paul\n'
1213 | 'John\n'
1214 | 'Ringo\n'
1215 | 'George\n'
1216 |
1217 | .. longtable: format: {p{.25\textwidth} p{.65\textwidth}}
1218 |
1219 | .. longtable: format: {>{\hangindent=1em\hangafter=1\raggedright\arraybackslash }p{.25\textwidth} >{\hangindent=1em\hangafter=1\raggedright\arraybackslash }p{.65\textwidth}}
1220 |
1221 | .. table:: File Methods/Attributes
1222 |
1223 | ================================================================= ============================================================
1224 | Operation Result
1225 | ================================================================= ============================================================
1226 | ``f.__iter__()`` Support iteration
1227 | ``f.__next__()`` Return next item of iteration (line in text)
1228 | ``f.__repr__()`` Implementation for ``repr(f)``
1229 | ``f.buffer`` File buffer
1230 | ``f.close()`` Close file
1231 | ``f.closed`` Is closed
1232 | ``f.detach()`` Detach file buffer from file
1233 | ``f.encoding`` The encoding of the file (default is ``locale.getpreferredencoding()``)
1234 | ``f.errors`` Error mode of encoding (``'strict'`` default)
1235 | ``f.fileno()`` Return file descriptor
1236 | ``f.flush()`` Write file buffer
1237 | ``f.isatty()`` Is interactive file
1238 | ``f.linebuffering`` Buffered by lines
1239 | ``f.name`` Name of file
1240 | ``f.newlines`` End of line characters encountered (tuple or string)
1241 | ``f.read( size=-1)`` Read ``size`` characters (``-1`` is whole file)
1242 | ``f.readable()`` Is opened for reading
1243 | ``f.readline( size=-1)`` Read ``size`` characters from line (``-1`` is whole line)
1244 | ``f.readlines( hint=-1)`` Read bytes less than ``hint`` characters of lines from file (``-1`` is all file)
1245 | ``f.seek(cookie, whence=0)`` Change stream location to ``cookie`` bytes (may be negative) offset from ``whence`` (``0`` - start, ``1`` - current position, ``2`` - end).
1246 | ``f.seekable()`` File supports random access
1247 | ``f.tell()`` Current stream location
1248 | ``f.truncate( pos=None)`` Truncate file to ``pos`` bytes
1249 | ``f.writeable()`` File supports writing
1250 | ``f.write(text)`` Write ``text`` to file
1251 | ``f.writelines( lines)`` Write ``lines`` to file (provide newlines if you want them)
1252 | ================================================================= ============================================================
1253 |
1254 |
1255 | Functions
1256 | ============
1257 |
1258 | Defining functions
1259 | ------------------
1260 |
1261 | Functions may take input, do some processing, and return output. You can
1262 | provide a docstring directly following the name
1263 | and parameters of the function::
1264 |
1265 |
1266 |
1267 | >>> def add_numbers(x, y):
1268 | ... """ add_numbers sums up x and y
1269 | ...
1270 | ... Arguments:
1271 | ... x -- object that supports addition
1272 | ... y -- object that supports addition
1273 | ... """
1274 | ... return x + y
1275 |
1276 |
1277 | .. note::
1278 |
1279 | We use whitespace to specify a block in Python. We typically indent following a colon. PEP 8 recommends using 4 spaces. Don't mix tabs and spaces.
1280 |
1281 | We can create anonymous functions using the ``lambda`` statement. Because they
1282 | only allow an expression following the colon, it is somewhat crippled in functionality.
1283 | They are commonly used as a ``key`` argument to ``sorted``, ``min``, or ``max``::
1284 |
1285 | >>> add = lambda x, y: x + y
1286 | >>> add(4, 5)
1287 | 9
1288 |
1289 |
1290 | Functions can have *default* arguments. Since Python 3.7, you can have more than 255 arguments for a single function! Be careful with mutable types as arguments,
1291 | as the default is bound to the function when the function is created, not when it is called::
1292 |
1293 | >>> def add_n(x, n=42):
1294 | ... return x + n
1295 |
1296 | >>> add_n(10)
1297 | 52
1298 | >>> add_n(3, -10)
1299 | -7
1300 |
1301 |
1302 |
1303 | Functions can support variable positional arguments::
1304 |
1305 | >>> def add_many(*args):
1306 | ... result = 0
1307 | ... for arg in args:
1308 | ... result += arg
1309 | ... return result
1310 |
1311 | >>> add_many()
1312 | 0
1313 | >>> add_many(1)
1314 | 1
1315 | >>> add_many(42, 3.14)
1316 | 45.14
1317 |
1318 | Functions can support variable keyword arguments::
1319 |
1320 | >>> def add_kwargs(**kwargs):
1321 | ... result = 0
1322 | ... for key in kwargs:
1323 | ... result += kwargs[key]
1324 | ... return result
1325 |
1326 | >>> add_kwargs(x=1, y=2, z=3)
1327 | 6
1328 |
1329 | >>> add_kwargs()
1330 | 0
1331 |
1332 | >>> add_kwargs(4)
1333 | Traceback (most recent call last):
1334 | ...
1335 | TypeError: add_kwargs() takes 0 positional arguments
1336 | but 1 was given
1337 |
1338 |
1339 | You can indicate the end of positional parameters by using a single ``*``. This gives you *keyword only* parameters (PEP 3102)::
1340 |
1341 | >>> def add_points(*, x1=0, y1=0, x2=0, y2=0):
1342 | ... return x1 + x2, y1 + y2
1343 |
1344 | >>> add_points(x1=1, y1=1, x2=3, y2=4)
1345 | (4, 5)
1346 |
1347 | >>> add_points(1, 1, 3, 4)
1348 | Traceback (most recent call last):
1349 | ...
1350 | TypeError: add_points() takes 0 positional arguments
1351 | but 4 were given
1352 |
1353 |
1354 | Python 3.8 added *positional only* parameters (PEP 570). Parameters that precede a ``/`` are
1355 | positional only, and can have a keyword provided when they are invoked.
1356 | There are many Python functions coded in C (ie ``math.sin``) that do not support keyword
1357 | arguments, so this allows Python functions to emulate this behavior::
1358 |
1359 | >>> def mysin(x, /):
1360 | ... import math
1361 | ... return math.sin(x)
1362 |
1363 |
1364 | .. note::
1365 |
1366 | Many of the built-in functions and methods in Python have a ``/`` in
1367 | the documentation. That slash indicates that the parameters before it
1368 | are positional only::
1369 |
1370 | >>> help(math.sin)
1371 | Help on built-in function sin in module math:
1372 |
1373 | sin(x, /)
1374 | Return the sine of x (measured in radians).
1375 |
1376 |
1377 | Calling Functions
1378 | -----------------
1379 |
1380 | You can also use ``*`` and ``**`` to *unpack* sequence and dictionary
1381 | arguments::
1382 |
1383 | >>> def add_all(*args, **kwargs):
1384 | ... """Add all arguments"""
1385 | ... result = 0
1386 | ... for num in args + tuple(kwargs.values()):
1387 | ... result += num
1388 | ... return result
1389 |
1390 | >>> sizes = (2, 4.5)
1391 | >>> named_sizes = {"this": 3, "that": 1}
1392 |
1393 |
1394 |
1395 | The following two examples are the equivalent::
1396 |
1397 | >>> add_all(*sizes)
1398 | 6.5
1399 |
1400 | >>> add_all(sizes[0], sizes[1])
1401 | 6.5
1402 |
1403 |
1404 | .. raw:: latex
1405 |
1406 | \Needspace{5\baselineskip}
1407 |
1408 | The following two examples are the equivalent::
1409 |
1410 |
1411 | >>> add_all(**named_sizes)
1412 | 4
1413 |
1414 | >>> add_all(this=3, that=1)
1415 | 4
1416 |
1417 | You can also combine ``*`` and ``**`` on invocation::
1418 |
1419 |
1420 | >>> add_all(*sizes, **named_sizes)
1421 | 10.5
1422 |
1423 | Getting Help
1424 | ------------
1425 |
1426 | You can get help on a function that has a docstring by using ``help``::
1427 |
1428 | >>> help(add_all)
1429 | Help on function add_all in module __main__:
1430 |
1431 | add_all(*args, **kwargs)
1432 | Add all arguments
1433 |
1434 | Classes
1435 | ==========
1436 |
1437 | Python supports object oriented programming but doesn't require you to create classes. You
1438 | can use the built-in data structures to great effect. Here's a class for a simple bike. The class attribute,
1439 | ``num_passengers``, is shared for all instances of ``Bike``. The instance attributes, ``size`` and
1440 | ``ratio``, are unique to each instance::
1441 |
1442 |
1443 | >>> class Bike:
1444 | ... ''' Represents a bike '''
1445 | ... num_passengers = 1 # class attribute
1446 | ...
1447 | ... def __init__(self, wheel_size,
1448 | ... gear_ratio):
1449 | ... ''' Create a bike specifying the
1450 | ... wheel size, and gear ratio '''
1451 | ... # instance attributes
1452 | ... self.size = wheel_size
1453 | ... self.ratio = gear_ratio
1454 | ...
1455 | ... def gear_inches(self):
1456 | ... return self.ratio * self.size
1457 |
1458 |
1459 |
1460 | We can call the constructor (``__init__``), by invoking the class name. Note that ``self`` is the instance,
1461 | but Python passes that around for us automatically::
1462 |
1463 | >>> bike = Bike(26, 34/13)
1464 | >>> print(bike.gear_inches())
1465 | 68.0
1466 |
1467 | We can access both class attributes and instance attributes on the instance::
1468 |
1469 | >>> bike.num_passengers
1470 | 1
1471 |
1472 | >>> bike.size
1473 | 26
1474 |
1475 | If an attribute is not found on the instance, Python will then look for it on the class, it will look through
1476 | the parent classes to continue to try and find it. If the lookup is unsuccessful, an ``AttributeError`` is raised.
1477 |
1478 | Subclasses
1479 | ------------
1480 |
1481 | To subclass a class, simply place the parent class name in parentheses following
1482 | the class name in the declaration. We can call the ``super`` function to gain access to parent
1483 | methods::
1484 |
1485 | >>> class Tandem(Bike):
1486 | ... num_passengers = 2
1487 | ...
1488 | ... def __init__(self, wheel_size, rings, cogs):
1489 | ... self.rings = rings
1490 | ... self.cogs = cogs
1491 | ... ratio = rings[0] / cogs[0]
1492 | ... super().__init__(wheel_size, ratio)
1493 | ...
1494 | ... def shift(self, ring_idx, cog_idx):
1495 | ... self.ratio = self.rings[ring_idx] \
1496 | ... / self.cogs[cog_idx]
1497 | ...
1498 |
1499 | .. note::
1500 |
1501 | In the above example, we used a ``\`` to indicate that the
1502 | line continued on the following line. This is usually required
1503 | unless there is an implicit line continuation with an opening
1504 | brace that hasn't been closed
1505 | (``(``, ``[``, or ``{``).
1506 |
1507 | The instance of the subclass can call methods that are defined on its class or the parent class::
1508 |
1509 | >>> tan = Tandem(26, [42, 36], [24, 20, 15, 11])
1510 | >>> tan.shift(1, -1)
1511 | >>> tan.gear_inches()
1512 | 85.0909090909091
1513 |
1514 | Class Methods and Static Methods
1515 | --------------------------------
1516 |
1517 | The ``classmethod`` decorator is used to create methods that you
1518 | can invoke directly on the
1519 | class. This allows us to create alternate constructors. Note
1520 | that the implicit first argument is the class, commonly
1521 | named ``cls`` (as ``class`` is a keyword and will error out)::
1522 |
1523 | >>> INCHES_PER_METER = 39.37
1524 |
1525 | >>> class MountainBike(Bike):
1526 | ... @classmethod
1527 | ... def from_metric(cls, size_meters, ratio):
1528 | ... return cls(size_meters *
1529 | ... INCHES_PER_METER,
1530 | ... ratio)
1531 |
1532 |
1533 | >>> mtn = MountainBike.from_metric(.559, 38/11)
1534 | >>> mtn.gear_inches()
1535 | 76.0270490909091
1536 |
1537 | .. note::
1538 |
1539 | In the above example, we had an implicit line continuation without a
1540 | backslash, because there was a ``(`` on the line.
1541 |
1542 | The ``staticmethod`` decorator lets you attach functions to
1543 | a class. (I don't like them, just use a function). Note
1544 | that they don't get an implicit first argument. It can be
1545 | called on the instance or the class::
1546 |
1547 | >>> class Recumbent(Bike):
1548 | ... @staticmethod
1549 | ... def is_fast():
1550 | ... return True
1551 |
1552 | >>> Recumbent.is_fast()
1553 | True
1554 |
1555 | >>> lawnchair = Recumbent(20, 4)
1556 | >>> lawnchair.is_fast()
1557 | True
1558 |
1559 | Properties
1560 | ----------
1561 |
1562 | If you want to have actions occur under the covers on attribute access,
1563 | you can use properties to do that::
1564 |
1565 |
1566 |
1567 | >>> class Person:
1568 | ... def __init__(self, name):
1569 | ... self._name = name
1570 | ...
1571 | ... @property
1572 | ... def name(self):
1573 | ... if self._name == 'Richard':
1574 | ... return 'Ringo'
1575 | ... return self._name
1576 | ...
1577 | ... @name.setter
1578 | ... def name(self, value):
1579 | ... self._name = value
1580 | ...
1581 | ... @name.deleter
1582 | ... def name(self):
1583 | ... del self._name
1584 |
1585 | Rather than calling the ``.name()`` method, we access the attribute::
1586 |
1587 | >>> p = Person('Richard')
1588 | >>> p.name
1589 | 'Ringo'
1590 |
1591 | >>> p.name = 'Fred'
1592 |
1593 |
1594 | Data classes
1595 | ------------
1596 |
1597 | Python 3.7 introduced data classes (PEP 557). They can describe the attributes of
1598 | a class using annotations::
1599 |
1600 | >>> import typing
1601 | >>> from dataclasses import dataclass
1602 | >>> @dataclass
1603 | ... class Bike2:
1604 | ... num_passengers: typing.ClassVar[int]
1605 | ... wheel_size: float
1606 | ... gear_ratio: float
1607 | ...
1608 | ... def gear_inches(self):
1609 | ... return self.gear_ratio * self.wheel_size
1610 |
1611 |
1612 |
1613 |
1614 | Looping
1615 | =======
1616 |
1617 | You can loop over objects in a sequence::
1618 |
1619 | >>> names = ['John', 'Paul', 'Ringo']
1620 | >>> for name in names:
1621 | ... print(name)
1622 | John
1623 | Paul
1624 | Ringo
1625 |
1626 | The ``break`` statement will pop you out of a loop::
1627 |
1628 | >>> for name in names:
1629 | ... if name == 'Paul':
1630 | ... break
1631 | ... print(name)
1632 | John
1633 |
1634 | The ``continue`` statement skips over the body of the loop and *continues*
1635 | at the next item of iteration::
1636 |
1637 | >>> for name in names:
1638 | ... if name == 'Paul':
1639 | ... continue
1640 | ... print(name)
1641 | John
1642 | Ringo
1643 |
1644 | You can use the ``else`` statement to indicate that every item was looped
1645 | over, and a ``break`` was never encountered::
1646 |
1647 | >>> for name in names:
1648 | ... if name == 'George':
1649 | ... break
1650 | ... else:
1651 | ... raise ValueError("No Georges")
1652 | Traceback (most recent call last):
1653 | ...
1654 | ValueError: No Georges
1655 |
1656 | Don't loop over index values (``range(len(names))``). Use ``enumerate``::
1657 |
1658 | >>> for i, name in enumerate(names, 1):
1659 | ... print("{}. {}".format(i, name))
1660 | 1. John
1661 | 2. Paul
1662 | 3. Ringo
1663 |
1664 | ``while`` Loops
1665 | ---------------
1666 |
1667 | You can use ``while`` loops to create loops as well. If it is an infinite loop,
1668 | you can break out of it::
1669 |
1670 | >>> done = False
1671 | >>> while not done:
1672 | ... # some work
1673 | ... done = True
1674 |
1675 |
1676 | You can add an ``else`` clause that only runs when the ``while`` conditional becomes false. If you break out of the loop it will not run.
1677 |
1678 | Iteration Protocol
1679 | ------------------
1680 |
1681 | To make an iterator implement ``__iter__`` and ``__next__``::
1682 |
1683 | >>> class fib:
1684 | ... def __init__(self, limit=None):
1685 | ... self.val1 = 1
1686 | ... self.val2 = 1
1687 | ... self.limit = limit
1688 | ...
1689 | ... def __iter__(self):
1690 | ... return self
1691 | ...
1692 | ... def __next__(self):
1693 | ... val = self.val1
1694 | ... self.val1 = self.val2
1695 | ... self.val2 = val + self.val1
1696 | ... if self.limit is not None and \
1697 | ... val < self.limit:
1698 | ... return val
1699 | ... raise StopIteration
1700 |
1701 |
1702 | Use the iterator in a loop::
1703 |
1704 | >>> e = fib(6)
1705 | >>> for val in e:
1706 | ... print(val)
1707 | 1
1708 | 1
1709 | 2
1710 | 3
1711 | 5
1712 |
1713 | Unrolling the protocol::
1714 |
1715 | >>> e = fib(6)
1716 | >>> it = iter(e) # calls e.__iter__()
1717 | >>> next(it) # calls it.__next__()
1718 | 1
1719 | >>> next(it)
1720 | 1
1721 | >>> next(it)
1722 | 2
1723 | >>> next(it)
1724 | 3
1725 | >>> next(it)
1726 | 5
1727 | >>> next(it)
1728 | Traceback (most recent call last):
1729 | ...
1730 | StopIteration
1731 |
1732 |
1733 |
1734 | Conditionals
1735 | ===============
1736 |
1737 | Python has an ``if`` statement with zero or more ``elif`` statements,
1738 | and an optional ``else`` statement at the end. In Python, the word ``elif`` is Dutch for *else if*::
1739 |
1740 | >>> grade = 72
1741 |
1742 | >>> def letter_grade(grade):
1743 | ... if grade > 90:
1744 | ... return 'A'
1745 | ... elif grade > 80:
1746 | ... return 'B'
1747 | ... elif grade > 70:
1748 | ... return 'C'
1749 | ... else:
1750 | ... return 'D'
1751 |
1752 | >>> letter_grade(grade)
1753 | 'C'
1754 |
1755 | Python supports the following tests: ``>``, ``>=``, ``<``, ``<=``, ``==``, and ``!=``. For boolean operators use ``and``, ``or``, and ``not`` (``&``, ``|``, and ``^`` are the bitwise operators).
1756 |
1757 |
1758 | Note that Python also supports *range comparisons*::
1759 |
1760 | >>> x = 4
1761 | >>> if 3 < x < 5:
1762 | ... print("Four!")
1763 | Four!
1764 |
1765 | Python does not have a switch statement, often dictionaries are used to support a similar construct::
1766 |
1767 | >>> def add(x, y):
1768 | ... return x + y
1769 |
1770 | >>> def sub(x, y):
1771 | ... return x - y
1772 |
1773 | >>> ops = {'+': add, '-': sub}
1774 |
1775 | >>> op = '+'
1776 | >>> a = 2
1777 | >>> b = 3
1778 | >>> ops[op](a, b)
1779 | 5
1780 |
1781 |
1782 |
1783 | Truthiness
1784 | ----------
1785 |
1786 | You can define the ``__bool__`` method to teach your classes how to act in a boolean context. If that doesn't exists, Python will use ``__len__``, and finally default to ``True``.
1787 |
1788 | The following table lists *truthy* and *falsey* values:
1789 |
1790 | +-------------------+---------------------------------+
1791 | | Truthy | Falsey |
1792 | +===================+=================================+
1793 | | ``True`` | ``False`` |
1794 | +-------------------+---------------------------------+
1795 | | Most objects | ``None`` |
1796 | +-------------------+---------------------------------+
1797 | | ``1`` | ``0`` |
1798 | +-------------------+---------------------------------+
1799 | | ``3.2`` | ``0.0`` |
1800 | +-------------------+---------------------------------+
1801 | | ``[1, 2]`` | ``[]`` (empty list) |
1802 | +-------------------+---------------------------------+
1803 | | ``{'a': 1, | ``{}`` (empty dict) |
1804 | | 'b': 2}`` | |
1805 | +-------------------+---------------------------------+
1806 | | ``'string'`` | ``""`` (empty string) |
1807 | +-------------------+---------------------------------+
1808 | | ``'False'`` | |
1809 | +-------------------+---------------------------------+
1810 | | ``'0'`` | |
1811 | +-------------------+---------------------------------+
1812 |
1813 | Short Circuiting
1814 | ----------------
1815 |
1816 | The ``and`` statement will short circuit if it evaluates to false::
1817 |
1818 | >>> 0 and 1/0
1819 | 0
1820 |
1821 | Likewise, the ``or`` statement will short circuit when something evaluates to true::
1822 |
1823 | >>> 1 or 1/0
1824 | 1
1825 |
1826 | Ternary Operator
1827 | ------------------
1828 |
1829 | Python has its own ternary operator, called a *conditional expression* (see PEP 308). These are handy as they can be used in comprehension constructs and ``lambda`` functions::
1830 |
1831 | >>> last = 'Lennon' if band == 'Beatles' else 'Jones'
1832 |
1833 | Note that this has similar behavior to an ``if`` statement, but it is an expression, and not a statement. Python
1834 | distinguishes these two. An easy way to determine between the two, is to remember that an expression follows a ``return`` statement. Anything you can ``return`` is an expression.
1835 |
1836 |
1837 |
1838 |
1839 |
1840 | Exceptions
1841 | ============
1842 |
1843 | Python can catch one or more exceptions (PEP 3110). You can provide a chain of different exceptions to catch if you want to react differently.
1844 | A few hints:
1845 |
1846 | * Try to keep the block of the ``try`` statement down to the code that throws exceptions
1847 | * Be specific about the exceptions that you catch
1848 | * If you want to inspect the exception, use ``as`` to create a variable to point to it
1849 |
1850 | If you use a bare ``raise`` inside of an ``except`` block, Python's traceback will point back to the
1851 | location of the original exception, rather than where it is raised from.
1852 |
1853 | ::
1854 |
1855 | >>> def avg(seq):
1856 | ... try:
1857 | ... result = sum(seq) / len(seq)
1858 | ... except ZeroDivisionError as e:
1859 | ... return None
1860 | ... except Exception:
1861 | ... raise
1862 | ... return result
1863 |
1864 |
1865 | >>> avg([1, 2, 4])
1866 | 2.3333333333333335
1867 |
1868 | >>> avg([]) is None
1869 | True
1870 |
1871 | >>> avg('matt')
1872 | Traceback (most recent call last):
1873 | ...
1874 | TypeError: unsupported operand type(s) for +: 'int'
1875 | and 'str'
1876 |
1877 | Raising Exceptions
1878 | ------------------
1879 |
1880 | You can raise an exception using the ``raise`` statement (PEP 3109)::
1881 |
1882 | >>> def bad_code(x):
1883 | ... raise ValueError('Bad code')
1884 |
1885 | >>> bad_code(1)
1886 | Traceback (most recent call last):
1887 | ...
1888 | ValueError: Bad code
1889 |
1890 | Decorators
1891 | ==========
1892 |
1893 | A decorator (PEP 318) allows us to insert logic before and after a function is called. You can define a decorator with a function that takes a function as input and returns a function as output. Here is the identity decorator::
1894 |
1895 | >>> def identity(func):
1896 | ... return func
1897 |
1898 |
1899 | We can decorate a function with it like this::
1900 |
1901 | >>> @identity
1902 | ... def add(x, y):
1903 | ... return x + y
1904 |
1905 | A more useful decorator can inject logic before and after calling the original function. To do this we create a function inside of the function and return that::
1906 |
1907 | >>> import functools
1908 | >>> def verbose(func):
1909 | ... @functools.wraps(func)
1910 | ... def inner(*args, **kwargs):
1911 | ... print("Calling with:{} {}".format(args,
1912 | ... kwargs))
1913 | ... res = func(*args, **kwargs)
1914 | ... print("Result:{}".format(res))
1915 | ... return res
1916 | ... return inner
1917 |
1918 | Above, we use print functions to illustrate before/after behavior, otherwise this is very similar to identity decorator.
1919 |
1920 | There is a special syntax for applying the decorator. We put ``@`` before the decorator name and place that on a line directly above the function we wish to decorate. Using the ``@verbose`` line before a function declaration is syntactic sugar for re-assigning the variable pointing to the function to the result of calling
1921 | the decorator with the function passed into it::
1922 |
1923 | >>> @verbose
1924 | ... def sub(x, y):
1925 | ... return x - y
1926 |
1927 | This could also be written as, ``sub = verbose(sub)``. Note that our decorated
1928 | function will still call our original function, but add in some ``print`` statements::
1929 |
1930 | >>> sub(5, 4)
1931 | Calling with:(5, 4) {}
1932 | Result:1
1933 | 1
1934 |
1935 | As of Python 3.9 (PEP 614), any valid expression can be used as a decorator.
1936 |
1937 | Parameterized Decorators
1938 | ------------------------
1939 |
1940 | Because we can use closures to create functions, we can use closures to create decorators as well.
1941 | This is very similar to our decorator above, but now we make a function that will
1942 | return a decorator. Based on the inputs to that function, we can control (or parameterize)
1943 | the behavior of the decorator:
1944 |
1945 | .. raw:: latex
1946 |
1947 | %\Needspace{5\baselineskip}
1948 | \clearpage
1949 |
1950 |
1951 | ::
1952 |
1953 | >>> def verbose_level(level):
1954 | ... def verbose(func):
1955 | ... @functools.wraps(func)
1956 | ... def inner(*args, **kwargs):
1957 | ... for i in range(level): # parameterized!
1958 | ... print("Calling with:{} {}".format(
1959 | ... args, kwargs))
1960 | ... res = func(*args, **kwargs)
1961 | ... print("Result:{}".format(res))
1962 | ... return res
1963 | ... return inner
1964 | ... return verbose
1965 |
1966 | When you decorate with parameterized decorators, the decoration looks differently,
1967 | because we need to invoke the function to create a decorator::
1968 |
1969 | >>> @verbose_level(2)
1970 | ... def div(x, y):
1971 | ... return x/y
1972 |
1973 | >>> div(1, 5)
1974 | Calling with:(1, 5) {}
1975 | Calling with:(1, 5) {}
1976 | Result:0.2
1977 | 0.2
1978 |
1979 |
1980 |
1981 | Class Decorators and Metaclasses
1982 | ================================
1983 |
1984 | Python allows you to dynamically create and modify classes. Class decorators and
1985 | metaclasses are two ways to do this.
1986 |
1987 |
1988 | Class Decorators
1989 | -----------------
1990 |
1991 | You can decorate a class definition with a *class decorator* (PEP 3129). It is a function that takes a class as input and returns a class.
1992 |
1993 | ::
1994 |
1995 | >>> def add_chirp(cls):
1996 | ... 'Class decorator to add speak method'
1997 | ... def chirp(self):
1998 | ... return "CHIRP"
1999 | ... cls.speak = chirp
2000 | ... return cls
2001 | ...
2002 | >>> @add_chirp
2003 | ... class Bird:
2004 | ... pass
2005 |
2006 | >>> b = Bird()
2007 | >>> print(b.speak())
2008 | CHIRP
2009 |
2010 |
2011 | Creating Classes with ``type``
2012 | --------------------------------
2013 |
2014 | You can use ``type`` to determine the type of an object, but you can also
2015 | provide the name, parents, and attributes map, and it will return a class.
2016 |
2017 | ::
2018 |
2019 | >>> def howl(self):
2020 | ... return "HOWL"
2021 |
2022 | >>> parents = ()
2023 | >>> attrs_map = {'speak': howl}
2024 | >>> F = type('F', parents, attrs_map)
2025 |
2026 | >>> f = F()
2027 | >>> print(f.speak())
2028 | HOWL
2029 |
2030 |
2031 | Metaclasses with Functions
2032 | --------------------------
2033 |
2034 | In the class definition you can specify a metaclass (PEP 3115), which can be a
2035 | function or a class. Here is an example of a function that can
2036 | alter the class.
2037 |
2038 | ::
2039 |
2040 | >>> def meta(name, parents, attrs_map):
2041 | ... def bark(self):
2042 | ... return "WOOF!"
2043 | ... attrs_map['speak'] = bark
2044 | ... return type(name, parents, attrs_map)
2045 |
2046 | >>> class Dog(metaclass=meta):
2047 | ... pass
2048 |
2049 | >>> d = Dog()
2050 | >>> print(d.speak())
2051 | WOOF!
2052 |
2053 | Metaclasses with Classes
2054 | ------------------------
2055 |
2056 | You can define a class decorator and use either ``__new__`` or
2057 | ``__init__``. Typically most use ``__new__`` as it can alter
2058 | attributes like ``__slots__``.
2059 |
2060 | ::
2061 |
2062 | >>> class CatMeta(type): # Needs to subclass type
2063 | ... def __new__(cls, name, parents, attrs_map):
2064 | ... # cls is CatMeta
2065 | ... # res is the class we are creating
2066 | ... res = super().__new__(cls, name,
2067 | ... parents, attrs_map)
2068 | ... def meow(self):
2069 | ... return "MEOW"
2070 | ... res.speak = meow
2071 | ... return res
2072 | ...
2073 | ... def __init__(cls, name, parents, attrs_map):
2074 | ... super().__init__(name, parents, attrs_map)
2075 |
2076 | >>> class Cat(metaclass=CatMeta):
2077 | ... pass
2078 |
2079 | >>> c = Cat()
2080 | >>> print(c.speak())
2081 | MEOW
2082 |
2083 | Generators
2084 | ==========
2085 |
2086 | Generators (PEP 255) are functions that suspend their state as you iterate over the results
2087 | of them. Each ``yield`` statement returns the next item of iteration and then
2088 | *freezes* the state of the function. When iteration is resumed, the function
2089 | continues from the point it was frozen. Note, that the result of calling the
2090 | function is a generator::
2091 |
2092 | >>> def fib_gen():
2093 | ... val1, val2 = 1, 1
2094 | ... while 1:
2095 | ... yield val1
2096 | ... val1, val2 = val2, (val1+val2)
2097 |
2098 |
2099 | We can simulate iteration by using the iteration protocol::
2100 |
2101 | >>> gen = fib_gen()
2102 | >>> gen_iter = iter(gen)
2103 | >>> next(gen_iter)
2104 | 1
2105 | >>> next(gen_iter)
2106 | 1
2107 | >>> next(gen_iter)
2108 | 2
2109 | >>> next(gen_iter)
2110 | 3
2111 |
2112 |
2113 |
2114 | Coroutines
2115 | ==========
2116 |
2117 | The ``asyncio`` library (PEP 3153) provides asynchronous I/O in Python 3. We use ``async def`` to define a *coroutine function* (see PEP 492). The result of calling this is a *coroutine object*. Inside a coroutine we can use ``var = await future`` to suspend the coroutine and wait for ``future`` to return. We can also await another coroutine. A coroutine object may be created but isn't run until an event loop is running::
2118 |
2119 | >>> import asyncio
2120 | >>> async def greeting():
2121 | ... print("Here they are!")
2122 |
2123 | >>> co = greeting()
2124 | >>> co # Not running
2125 |
2126 |
2127 | >>> loop = asyncio.get_event_loop()
2128 | >>> loop.run_until_complete(co)
2129 | Here they are!
2130 | >>> loop.close()
2131 |
2132 |
2133 | .. raw:: latex
2134 |
2135 |
2136 | \clearpage
2137 |
2138 |
2139 | .. note::
2140 |
2141 | Since Python 3.7 you can use::
2142 |
2143 | asyncio.run(greeting())
2144 |
2145 | instead of explicitly creating and running the loop.
2146 |
2147 |
2148 | To return an object, use an ``asyncio.Future``::
2149 |
2150 | >>> async def compute(future):
2151 | ... print("Starting...")
2152 | ... # Simulate IO...
2153 | ... res = await answer()
2154 | ... future.set_result(res)
2155 |
2156 |
2157 | >>> async def answer():
2158 | ... await asyncio.sleep(1)
2159 | ... return 42
2160 |
2161 | >>> f = asyncio.Future()
2162 | >>> loop = asyncio.get_event_loop()
2163 | >>> loop.run_until_complete(compute(f))
2164 | >>> loop.close()
2165 | >>> f.result()
2166 | 42
2167 |
2168 |
2169 | .. note::
2170 |
2171 | ``await`` and ``async`` are *soft keywords* in Python 3.6. You will get a warning if you use them for variable names. Since Python 3.7, they are reserved keywords.
2172 |
2173 | .. note::
2174 |
2175 | For backwards compatibility in Python 3.4:
2176 |
2177 | * ``await`` can be replaced with ``yield from``
2178 |
2179 | * ``async def`` can be replaced with a function
2180 | decorated with ``@asyncio.coroutine``
2181 |
2182 |
2183 |
2184 | Asynchronous Generators
2185 | --------------------------
2186 |
2187 | Python 3.6 adds asynchronous generators (PEP 525). You can use the ``yield``
2188 | statement in an ``async def`` function::
2189 |
2190 | >>> async def fib():
2191 | ... v1, v2 = 1, 1
2192 | ... while True:
2193 | ... # similate io
2194 | ... await asyncio.sleep(1)
2195 | ... yield v1
2196 | ... v1, v2 = v2, v1+v2
2197 | ... if v1 > 5:
2198 | ... break
2199 |
2200 | >>> async def get_results():
2201 | ... async for num in fib():
2202 | ... print(num)
2203 |
2204 | >>> loop = asyncio.get_event_loop()
2205 | >>> loop.run_until_complete(get_results())
2206 | 1 # sleeps for 1 sec before each print
2207 | 1
2208 | 2
2209 | 3
2210 | 5
2211 | >>> loop.close()
2212 |
2213 |
2214 |
2215 |
2216 | Comprehensions
2217 | ==============
2218 |
2219 | Comprehension constructs allow us to combine the functional ideas behind map and filter into an
2220 | easy to read, single line of code. When you see code that is aggregating into a list (or dict, set, or
2221 | generator), you
2222 | can replace it with a list comprehension (or dict, set comprehension, or generator expression). Here
2223 | is an example of the code smell::
2224 |
2225 | >>> nums = range(10)
2226 | >>> result = []
2227 | >>> for num in nums:
2228 | ... if num % 2 == 0: # filter
2229 | ... result.append(num*num) # map
2230 |
2231 | This can be specified with a list comprehension (PEP 202)::
2232 |
2233 | >>> result = [num*num for num in nums
2234 | ... if num % 2 == 0]
2235 |
2236 | To construct a list comprehension:
2237 |
2238 | * Assign the result (``result``) to brackets. The brackets signal to the
2239 | reader of the code that a list will be returned::
2240 |
2241 | result = [ ]
2242 |
2243 | * Place the *for* loop construct inside the brackets. No colons are
2244 | necessary::
2245 |
2246 | result = [for num in nums]
2247 |
2248 | * Insert any operations that filter the accumulation after the for
2249 | loop::
2250 |
2251 | result = [for num in nums if num % 2 == 0]
2252 |
2253 | * Insert the accumulated object (``num*num``) at the front directly
2254 | following the left bracket. Insert parentheses around the object if
2255 | it is a tuple::
2256 |
2257 | result = [num*num for num in nums
2258 | if num % 2 == 0]
2259 |
2260 | Set Comprehensions
2261 | ------------------
2262 |
2263 | If you replace the ``[`` with ``{``, you will get a set comprehension (PEP 274) instead of a list comprehension::
2264 |
2265 | >>> {num*num for num in nums if num % 2 == 0}
2266 | {0, 64, 4, 36, 16}
2267 |
2268 | Dict Comprehensions
2269 | -------------------
2270 |
2271 | If you replace the ``[`` with ``{``, and separate the key and value with a colon,
2272 | you will get a dictionary comprehension (PEP 274)::
2273 |
2274 | >>> {num:num*num for num in nums if num % 2 == 0}
2275 | {0: 0, 2: 4, 4: 16, 6: 36, 8: 64}
2276 |
2277 | .. note::
2278 |
2279 | Since Python 3.6, dictionaries are now ordered by key entry. Hence the ordering above.
2280 |
2281 | Generator Expressions
2282 | ---------------------
2283 |
2284 | If you replace the ``[`` with ``(``, you will get a generator instead of a list. This is called a *generator expression* (PEP 289)::
2285 |
2286 | >>> (num*num for num in nums if num % 2 == 0)
2287 | at 0x10a6f8780>
2288 |
2289 | Asynchronous Comprehensions
2290 | ---------------------------
2291 |
2292 | Python 3.6 (PEP 530) gives us *asynchronous comprehensions*. You can add ``async`` following what you are collecting to make it asynchronous. If you had the following code::
2293 |
2294 | >>> async def process(aiter):
2295 | ... result = []
2296 | ... async for num in aiter:
2297 | ... if num % 2 == 0: # filter
2298 | ... result.append(num*num) # map
2299 |
2300 | You could replace it with::
2301 |
2302 | >>> async def process(aiter):
2303 | ... result = [num*num async for num in aiter
2304 | ... if num % 2 == 0]
2305 |
2306 |
2307 |
2308 | Context Managers
2309 | ================
2310 |
2311 | If you find code where you need to make sure something happens before *and* after a block,
2312 | a context manager (PEP 343) is a convenient way to enforce that. Another code smell that indicates
2313 | you could be using a context manager is a ``try``/``finally`` block.
2314 |
2315 | Context managers can be created with functions or classes.
2316 |
2317 | If we were writing a Python module to write TeX, we might do something like this to ensure that
2318 | the environments are closed properly::
2319 |
2320 | >>> def start(env):
2321 | ... return '\\begin{{{}}}'.format(env)
2322 |
2323 | >>> def end(env):
2324 | ... return '\\end{{{}}}'.format(env)
2325 |
2326 | >>> def may_error():
2327 | ... import random
2328 | ... if random.random() < .5:
2329 | ... return 'content'
2330 | ... raise ValueError('Problem')
2331 |
2332 |
2333 | >>> out = []
2334 | >>> out.append(start('center'))
2335 |
2336 | >>> try:
2337 | ... out.append(may_error())
2338 | ... except ValueError:
2339 | ... pass
2340 | ... finally:
2341 | ... out.append(end('center'))
2342 |
2343 | This code can use a context manager to be a little cleaner.
2344 |
2345 | Function Based Context Managers
2346 | -------------------------------
2347 |
2348 | To create a context manager with a function, decorate with
2349 | ``contextlib.contextmanager``, and yield where you want to insert your block::
2350 |
2351 | >>> import contextlib
2352 | >>> @contextlib.contextmanager
2353 | ... def env(name, content):
2354 | ... content.append('\\begin{{{}}}'.format(name))
2355 | ... try:
2356 | ... yield
2357 | ... except ValueError:
2358 | ... pass
2359 | ... finally:
2360 | ... content.append('\\end{{{}}}'.format(name))
2361 |
2362 | Our code looks better now, and there will always be a closing tag::
2363 |
2364 | >>> out = []
2365 | >>> with env('center', out):
2366 | ... out.append(may_error())
2367 |
2368 | >>> out
2369 | ['\\begin{center}', 'content', '\\end{center}']
2370 |
2371 | Class Based Context Managers
2372 | ----------------------------
2373 |
2374 | To create a class based context manager, implement the ``__enter__`` and ``__exit__`` methods::
2375 |
2376 | >>> class env:
2377 | ... def __init__(self, name, content):
2378 | ... self.name = name
2379 | ... self.content = content
2380 | ...
2381 | ... def __enter__(self):
2382 | ... self.content.append('\\begin{{{}}}'.format(
2383 | ... self.name))
2384 | ...
2385 | ... def __exit__(self, type, value, tb):
2386 | ... # if error in block, t, v, & tb
2387 | ... # have non None values
2388 | ... # return True to hide exception
2389 | ... self.content.append('\\end{{{}}}'.format(
2390 | ... self.name))
2391 | ... return True
2392 |
2393 | The code looks the same as using the function based context manager::
2394 |
2395 | >>> out = []
2396 | >>> with env('center', out):
2397 | ... out.append(may_error())
2398 |
2399 | >>> out # may_error had an issue
2400 | ['\\begin{center}', '\\end{center}']
2401 |
2402 | Parenthesized context managers
2403 | ---------------
2404 | Using enclosing parentheses for continuation across multiple lines in context managers is supported since Python 3.10 (PEP 617)
2405 | Now it is possible to format long collections of context managers, in multiple lines, in a similar way as it was already possible with import statements.
2406 |
2407 | Examples of which is now valid::
2408 | >>> with (
2409 | ... CtxManager1() as example1,
2410 | ... CtxManager2() as example2,
2411 | ... CtxManager3() as example3,
2412 | ...):
2413 |
2414 | Context objects
2415 | ---------------
2416 |
2417 | Some context managers create objects that we can use while inside of the context.
2418 | The ``open`` context manager returns a file object::
2419 |
2420 | with open('/tmp/test.txt') as fin:
2421 | # muck around with fin
2422 |
2423 | To create an object in a function based context manager, simply ``yield`` the object.
2424 | In a class based context manager, return the object in the ``__enter__`` method.
2425 |
2426 | Type Union Operator
2427 | ===================
2428 | Python 3.10 (PEP 605) has introduced a new type union operator overloading the ``|`` operator on types which enables the syntax ``X | Y``.
2429 | This operator lets us write "either type X or type Y" in cleaner format.
2430 |
2431 | A basic example::
2432 |
2433 | >>> (int | str) | float == int | str | float
2434 | True
2435 |
2436 | It can also be used to apply type hints to methods accepting arguments of multiple types::
2437 |
2438 | >>> def square(number: int | float) -> int | float:
2439 | ... return number ** 2
2440 |
2441 | The union type operator can also be passed as second argument to ``isinstance()`` and ``issubclass()`` method::
2442 |
2443 | >>> x = 10
2444 | >>> isinstance(x, int | str)
2445 | True
2446 |
2447 | Type Annotations
2448 | ===================
2449 |
2450 | Python 3.6 (PEP 483 and 484) allows you to provide types for
2451 | input and output of functions. They can be used to:
2452 |
2453 | * Allow 3rd party libraries such as mypy [#]_ to run static typing
2454 | * Assist editors with type inference
2455 | * Aid developers in understanding code
2456 |
2457 | .. [#] http://mypy-lang.org/
2458 |
2459 | Types can be expressed as:
2460 |
2461 | * Built-in classes
2462 | * Third party classes
2463 | * Abstract Base Classes
2464 | * Types found in the ``types`` module
2465 | * User-defined classes
2466 |
2467 | A basic example::
2468 |
2469 | >>> def add(x: int, y: int) -> float:
2470 | ... return x + y
2471 |
2472 | >>> add(2, 3)
2473 | 5
2474 |
2475 | Note that Python does not do type checking, you need to use something like mypy::
2476 |
2477 | >>> add("foo", "bar")
2478 | 'foobar'
2479 |
2480 | You can also specify the types of variables with a comment::
2481 |
2482 | >>> from typing import Dict
2483 | >>> ages = {} # type: Dict[str, int]
2484 |
2485 | As of PEP 585 (Python 3.9) you type hint on built in container without using the parallel types from the ``typing`` module. You can also *parameterize* the type::
2486 |
2487 | >>> from __future__ import annotations
2488 | >>> ages: dict[str, int] = {}
2489 |
2490 | As of PEP 604 (Python 3.10) you can use the new union operator ``|`` to define a union instead of ``typing.Union``::
2491 |
2492 | >>> typing.List[str | int]
2493 | >>> typing.Dict[str, int | float]
2494 |
2495 | As of PEP 613 (Python 3.10) the ``typing`` module has a special value ``TypeAlias`` which allows the type alias declaration to be explicit:
2496 | >>> x = 1 # untyped global expression
2497 | >>> x: int = 1 # typed global expression
2498 |
2499 | >>> x: TypeAlias = int # type alias
2500 | >>> x: TypeAlias = “MyClass” # type alias
2501 |
2502 | The ``typing`` Module
2503 | ---------------------
2504 |
2505 | This module allows you to provide hints for:
2506 |
2507 | * Callback functions
2508 | * Generic containers
2509 | * The ``Any`` type
2510 |
2511 | To designate a class or function to not type check its annotations, use the ``@typing.no_type_check`` decorator.
2512 |
2513 | Type Checking
2514 | -------------
2515 |
2516 | Python provides no support for type checking. You will need to install a tool like ``mypy``::
2517 |
2518 | $ pip install mypy
2519 | $ python3 -m mypy script.py
2520 |
2521 | Scripts, Packages, and Modules
2522 | ==============================
2523 |
2524 | Scripts
2525 | ---------
2526 |
2527 | A script is a Python file that you invoke ``python`` on. Typically there is a line near
2528 | the bottom that looks like this::
2529 |
2530 | if __name__ == '__main__':
2531 | # execute something
2532 |
2533 | This test allows you to change the code path when you execute the code versus when you import the code.
2534 | The ``__name__`` attribute of a module is set to ``'__main__'`` when you execute that module. Otherwise,
2535 | if you import the module, it will be the name of the module (without ``.py``).
2536 |
2537 | Modules
2538 | ----------
2539 |
2540 | Modules are files that end in ``.py``. According to PEP 8, we lowercase the
2541 | module name and don't put underscores between the words in them. Any
2542 | module found in the ``PYTHONPATH`` environment variable or the ``sys.path``
2543 | list, can be imported.
2544 |
2545 | Packages
2546 | -----------
2547 |
2548 | A directory that has a file named ``__init__.py`` in it is a *package*. A package can
2549 | have modules in it as well as sub packages. The package should be found in
2550 | ``PYTHONPATH`` or ``sys.path`` to be imported. An example might look like this::
2551 |
2552 |
2553 | packagename/
2554 | __init__.py
2555 | module1.py
2556 | module2.py
2557 | subpackage/
2558 | __init__.py
2559 |
2560 | The ``__init__.py`` module can be empty or can import code from other modules in the
2561 | package to remove nesting in import statements.
2562 |
2563 | Importing
2564 | ------------
2565 |
2566 | You can import a package or a module::
2567 |
2568 | import packagename
2569 | import packagename.module1
2570 |
2571 | Assume there is a ``fib`` function in ``module1``. You have access to everything in the namespace of the module you imported. To use this function you will need to use the fully qualified name, ``packagename.module1.fib``::
2572 |
2573 | import packagename.module1
2574 |
2575 | packagename.module1.fib()
2576 |
2577 |
2578 | If you only want to import the ``fib`` function, use the ``from`` variant::
2579 |
2580 | from packagename.module1 import fib
2581 |
2582 | fib()
2583 |
2584 | You can also rename imports using ``as``::
2585 |
2586 | from packagename.module1 import fib as package_fib
2587 |
2588 | package_fib()
2589 |
2590 | Environments
2591 | ================
2592 |
2593 | Python 3 includes the ``venv`` module for creating a sandbox for your project or a *virtual environment*.
2594 |
2595 | To create an environment on Unix systems, run::
2596 |
2597 | $ python3 -m venv /path/to/env
2598 |
2599 | On Windows, run::
2600 |
2601 | c:\> python -m venv c:\path\to\env
2602 |
2603 | To enter or *activate* the environment on Unix, run::
2604 |
2605 | $ source /path/to/env/bin/activate
2606 |
2607 | On Windows, run::
2608 |
2609 | c:\> c:\path\to\env\Scripts\activate.bat
2610 |
2611 | Your prompt should have the name of the active virtual environment in parentheses.
2612 | To *deactivate* an environment on both platforms, just run the following::
2613 |
2614 | (env) $ deactivate
2615 |
2616 | Installing Packages
2617 | -------------------
2618 |
2619 | You should now have a ``pip`` executable, that will install a package from PyPI [#]_ into your virtual environment::
2620 |
2621 | (env) $ pip install django
2622 |
2623 | .. [#] https://pypi.python.org/pypi
2624 |
2625 | To uninstall a package run::
2626 |
2627 | (env) $ pip uninstall django
2628 |
2629 | If you are having issues installing a package, you might want to look into alternative Python distributions such as Anaconda [#]_ that have prepackaged many harder to install packages.
2630 |
2631 | .. [#] https://docs.continuum.io/anaconda/
2632 |
2633 | Conda
2634 | -----
2635 |
2636 | Even though Conda [#]_ is not part of Python, it is a common tool for managing it. Here are the Conda equivalents of virtual environments and pip. The commands are the same on Windows and Unix.
2637 |
2638 | To create a Conda environment, run::
2639 |
2640 | $ conda create --name ENV_NAME python
2641 |
2642 | To list Conda environments, run::
2643 |
2644 | $ conda info --envs
2645 |
2646 | To activate a Conda environment, run::
2647 |
2648 | $ conda activate ENV_NAME
2649 |
2650 | To deactivate a Conda environment, run::
2651 |
2652 | $ conda deactivate
2653 |
2654 | To install a package, run::
2655 |
2656 | $ conda install django
2657 |
2658 | .. [#] https://conda.io
2659 |
--------------------------------------------------------------------------------