Effective Python Flashcards

(540 cards)

1
Q

“What does ““Pythonic”” code adhere to?”

A

””“Pythonic”” code adheres to community conventions

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

“Where do idiomatic patterns arise from?”

A

“Idiomatic patterns arise from experience and practical use.”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

“What happens when you write Python like another language?”

A

“Writing Python like another language leads to less readable

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

“How does knowing the Pythonic way improve code quality?”

A

“Knowing the Pythonic way of doing common tasks improves code quality.”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

“Which Python version do most examples in the document use?”

A

“Most examples in the document use Python 3.7

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

“What is the most commonly preinstalled Python runtime?”

A

“CPython is the most commonly preinstalled runtime.”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

“What might the ‘python’ command refer to on many systems?”

A

“On many systems

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

“What does ‘python3’ typically refer to?”

A

“python3 typically refers to Python 3.x.”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

“How can you programmatically inspect your Python version?”

A

“You can programmatically inspect your version using the sys module.”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

“When did Python 2 reach end-of-life and what does this mean?”

A

“Python 2 reached end-of-life on January 1

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

“What is the 2to3 migration tool?”

A

“2to3: Included with Python for converting Python 2 code to Python 3.”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

“What is the six migration tool?”

A

“six: A community-supported compatibility library for writing code that works on both Python 2 and 3.”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

“What is the recommendation for all new projects?”

A

“Use Python 3 for all new projects and development work.”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

“Why is Python 2 deprecated?”

A

“Python 2 is deprecated and has not received bug fixes

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

“Why is continuing to use Python 2 discouraged?”

A

“Continuing to use Python 2 is discouraged due to the lack of official support.”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

“Should you use spaces or tabs for indentation?”

A

“Use spaces

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

“How many spaces should you use per indentation level?”

A

“Indent using four spaces per level.”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

“What is the line length limit according to PEP 8?”

A

“Limit lines to 79 characters or fewer.”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
19
Q

“How should you indent continuation lines for long expressions?”

A

“Indent continuation lines by 4 additional spaces beyond normal indentation.”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
20
Q

“How many blank lines should separate functions and classes in a file?”

A

“Separate functions and classes in a file with two blank lines.”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
21
Q

“How many blank lines should separate methods within a class?”

A

“Separate methods within a class with one blank line.”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
22
Q

“What is the spacing rule between keys and colons in dictionaries?”

A

“No space between keys and colons.”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
23
Q

“What is the spacing rule after colons in dictionaries?”

A

“One space after the colon

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
24
Q

“What is the spacing rule for variable assignments with the = operator?”

A

“Use exactly one space before and after the = operator.”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
25
“What is the spacing rule before the colon in type annotations?”
“No space before the colon.”
26
“What is the spacing rule after the colon in type annotations?”
“One space after the colon (e.g.
27
“What is the naming convention for functions?”
“Functions: lowercase_with_underscores.”
28
“What is the naming convention for variables?”
“Variables: lowercase_with_underscores.”
29
“What is the naming convention for attributes?”
“Attributes: lowercase_with_underscores.”
30
“What is the naming convention for protected attributes?”
“Protected attributes: _leading_underscore.”
31
“What is the naming convention for private attributes?”
“Private attributes: __double_leading_underscore.”
32
“What is the naming convention for classes?”
“Classes: CapitalizedWord.”
33
“What is the naming convention for exceptions?”
“Exceptions: CapitalizedWord.”
34
“What is the naming convention for constants at module level?”
“Constants (at module level): ALL_CAPS.”
35
“What should the first parameter of instance methods be?”
“First parameter of instance methods: self.”
36
“What should the first parameter of class methods be?”
“First parameter of class methods: cls.”
37
“What is the preferred way to write inline negation?”
“Use inline negation: if a is not b instead of if not a is b.”
38
“How should you check container lengths against zero?”
“Avoid comparing container lengths to zero.”
39
“What should you prefer when checking if a container is empty?”
“Prefer truthiness: if not container instead of if len(container) == 0.”
40
“How do non-empty containers evaluate in boolean context?”
“Non-empty containers evaluate to True.”
41
“Should you use single-line if statements?”
“Avoid single-line if statements.”
42
“Should you use single-line for loops?”
“Avoid single-line for and while loops.”
43
“Should you use single-line while loops?”
“Avoid single-line for and while loops.”
44
“Should you use single-line except compound statements?”
“Avoid single-line except compound statements.”
45
“What should you prefer for multi-line expressions over line continuation?”
“Prefer parentheses for multi-line expressions over using \ line continuation.”
46
“How should you handle expressions that don’t fit on one line?”
“If an expression doesn’t fit on one line
47
“Why should you avoid the \ line continuation character?”
“Avoid using the \ line continuation character—parentheses are preferred for clarity and safety.”
48
“Where should you place all imports in a file?”
“Place all imports at the top of the file.”
49
“What type of imports should you use (absolute vs relative)?”
“Use absolute imports (e.g.
50
“When should you use explicit relative imports?”
“Use explicit relative imports (e.g.
51
“What is the first type of import in the organization order?”
“Standard library modules.”
52
“What is the second type of import in the organization order?”
“Third-party packages.”
53
“What is the third type of import in the organization order?”
“Local application imports.”
54
“How should you arrange imports within each section?”
“Within each section
55
“What tool helps enforce PEP 8 and detect common issues?”
“Tools like pylint help enforce PEP 8 and detect common issues.”
56
“What does the bytes type represent?”
“bytes: Raw 8-bit data with binary encoding.”
57
“What does the str type represent?”
“str: Unicode text that does not have any text encoding.”
58
“How do you convert str to bytes?”
“Use .encode() to convert str to bytes.”
59
“How do you convert bytes to str?”
“Use .decode() to convert bytes to str.”
60
“Where should you handle encoding/decoding in your program?”
“Handle encoding/decoding at the boundaries of the program (input/output)
61
“How do bytes and str behave in terms of similarity and interoperability?”
“bytes and str behave similarly but are not interoperable.”
62
“What do file operations expect by default
str or bytes?”
63
“Can you compare bytes and str?”
“Can’t compare or concatenate bytes and str.”
64
“Can you concatenate bytes and str?”
“Can’t compare or concatenate bytes and str.”
65
“How does % formatting behave for bytes vs. str?”
”% formatting behaves differently for bytes vs. str.”
66
“What happens when using a bytes object in a str format expression?”
“Using a bytes object in a str format expression invokes **repr**() unexpectedly.”
67
“What parameter should you use in open() to avoid encoding surprises?”
“Use the encoding parameter in open().”
68
“How can you check the system default encoding?”
“Check system default encoding using locale.getpreferredencoding().”
69
“How do you create byte strings and what do they represent?”
“Byte strings start with the letter b
70
“How do you create raw strings and what are they useful for?”
“Raw strings start with the letter r
71
“What do string prefixes help Python determine?”
“These prefixes help Python determine how to interpret and store the string’s contents.”
72
“What is the definition of formatting in the context of strings?”
“Formatting: The process of combining predefined text with data values into a single human-readable string.”
73
“What is the definition of a format string?”
“Format string: A string containing placeholders that are replaced with values during the formatting process. It serves as a template for structured output.”
74
“What are format specifiers used for?”
“Format strings use format specifiers (e.g.
75
“Where do format specifiers originate from?”
“These specifiers come from C’s printf function
76
“What printf format types does Python support?”
“Python supports all the usual printf options
77
“What printf controls does Python support?”
“Controls for decimal places
78
“How do you include format specifiers in str.format() placeholders?”
“Inside {} placeholders in str.format()
79
“What happens behind the scenes with format specifiers in str.format()?”
“These format specifiers are passed to the built-in format() function behind the scenes (e.g.
80
“What aspects can format specifiers control?”
“This allows for control over aspects such as number precision
81
“What does this formatting mechanism enable?”
“This mechanism enables fine-grained formatting for each value in the string.”
82
“How can you customize format behavior for custom classes?”
“You can define a class-specific way to control how its instances are formatted by implementing the **format** special method.”
83
“What method does Python call when formatting an object?”
“When str.format() or an f-string formats an object
84
“What does implementing **format** allow custom objects to do?”
“This allows custom objects to support formatting specifiers just like built-in types (e.g.
85
“When is implementing **format** useful?”
“Useful for aligning with specific formatting conventions or generating domain-specific string outputs.”
86
“How can format strings accept dictionaries with the % operator?”
“Format strings can accept a dictionary instead of a tuple when using the % operator.”
87
“How are dictionary keys matched in format strings?”
“Dictionary keys are matched to named placeholders in the format string (e.g.
88
“What does the dictionary approach help with in terms of value reuse?”
“This approach helps reuse values without repetition in the format string.”
89
“What does dictionary formatting introduce in terms of verbosity?”
“However
90
“Why are dictionary format strings verbose (key repetition)?”
“Keys must be repeated multiple times: in the format string
91
“What happens to expressions with dictionary formatting?”
“Expressions become longer
92
“What makes C-Style % format strings error-prone?”
“Error-prone due to type mismatches if tuple values are changed.”
93
“What reading difficulty exists with % format strings?”
“Difficult to read when modifying values inline.”
94
“What repetition problem exists with % format strings?”
“Requires value repetition when using the same value multiple times.”
95
“What verbosity problem exists with dictionary formatting using %?”
“Dictionary formatting with % adds verbosity and redundancy.”
96
“What does the str.format() method introduce instead of %?”
“Introduces {} placeholders instead of %.”
97
“What argument types does str.format() support?”
“Supports positional and named arguments.”
98
“How does str.format() offer formatting specifiers?”
“Offers formatting specifiers via format(value
99
“What value reference capability does str.format() have?”
“Can reference the same value multiple times without duplication.”
100
“Does str.format() solve inline modification issues?”
“Doesn’t solve inline modification issues.”
101
“How verbose is str.format() with complex expressions?”
“Remains verbose with nested or dynamic expressions.”
102
“What complexity does str.format() add with dictionaries or indexes?”
“Adds complexity when using dictionaries or indexes.”
103
“What escaping requirement does str.format() have?”
“Requires escaping {} braces.”
104
“What is the overall assessment of str.format() expressiveness?”
“Overall
105
“When were interpolated format strings (F-Strings) introduced?”
“Introduced in Python 3.6.”
106
“What prefix do you use for F-strings?”
“Use f””…”” prefix for string literals.”
107
“What can you reference inside F-string {} placeholders?”
“Reference any name or expression directly inside {}.”
108
“Are str.format() options available inside F-string placeholders?”
“All str.format() options still available inside the placeholder.”
109
“What redundancy problem do F-strings solve?”
“Redundancy (no keys/tuples needed).”
110
“What inline transformation capability do F-strings provide?”
“Inline transformation (you can apply expressions directly).”
111
“How do F-strings improve readability?”
“Readability (shorter and cleaner).”
112
“Do F-strings support multi-line formatting?”
“Supports multi-line formatting using adjacent string literals.”
113
“What is the recommendation for F-strings in new code?”
“Use for all new code; f-strings are preferred.”
114
“What does the !s conversion flag do in F-strings?”
”!s → convert with str()”
115
“What does the !r conversion flag do in F-strings?”
”!r → convert with repr()”
116
“What does the !a conversion flag do in F-strings?”
”!a → convert with ascii()”
117
“What types of Python expressions can you include in F-string placeholders?”
“You can also include full Python expressions in {}: Supports method calls
118
“What does including full expressions in F-strings eliminate?”
“Eliminates the need for temporary variables and enhances clarity.”
119
“What does Python’s pithy syntax make easy to do?”
“Python’s pithy syntax makes it easy to write single-line expressions that implement a lot of logic.”
120
“What are the different states that query string parameters may have?”
“Some query string parameters may have multiple values
121
“What method is used on the result dictionary and what does it return?”
“Using the get method on the result dictionary will return different values in each circumstance.”
122
“What is one way to add a default value to a variable when the surrounding logic doesn’t merit a whole if statement or helper function?”
“One way to add a default value to a variable if the surrounding logic doesn’t merit a whole if statement or helper function is to use a Boolean.”
123
“What values also evaluate to False besides False itself?”
“Empty strings
124
“What is the behavior of a dictionary’s get method when the initial value isn’t found?”
“The behavior of a dictionary’s get method is to return its second argument if the initial value isn’t found.”
125
“What does Python do if you set the get method’s default to a list?”
“If you set it to a list
126
“What type of expressions can make code like ‘red = values.get(”“red””
[””””])[0] or 0’ cleaner while keeping it short?”
127
“What characteristic do if/else statements that are spread out over multiple lines have?”
“if/else statements that are spread out over multiple lines are very complex.”
128
“When should you write a helper function?”
“If you need to re-use logic repeatedly
129
“What should you consider doing as soon as expressions get complicated?”
“As soon as expressions get complicated
130
“What always outweighs the benefits of brevity?”
“What you gain in readability always outweighs the benefits of brevity.”
131
“What principle should you follow regarding code repetition?”
“Follow the DRY principle (don’t repeat yourself).”
132
“What is Python’s built-in tuple used for?”
“Python has a built-in tuple that can be used to create immutable
133
“What is the simplest case of a tuple?”
“In the simplest case
134
“How can the values in a tuple be accessed?”
“The values in a tuple can be accessed through numerical indexes.”
135
“What happens once a tuple is created regarding modification?”
“Once a tuple is created
136
“What does Python’s unpacking syntax allow?”
“Python also has syntax for unpacking
137
“How do the patterns in unpacking look compared to mutating tuples?”
“The patterns that you specify in unpacking look a lot like trying to mutate tuples
138
“What advantages does unpacking have over accessing tuple indexes?”
“Unpacking has less visual noise than accessing the tuple’s indexes
139
“Where else does the pattern matching syntax of unpacking work?”
“The same pattern matching syntax of unpacking works when assigned to lists
140
“What might surprise newcomers to Python about unpacking?”
“Newcomers to Python may be surprised to learn that unpacking can even be used to swap values in place without the need to create temporary variables.”
141
“What is possible to do with indexes using unpacking syntax?”
“It’s possible to swap indexes on a single line with unpacking syntax.”
142
“What is another valuable application of unpacking?”
“Another valuable application of unpacking is in the target list of for loops and similar constructs
143
“What is the Pythonic way to write a for loop and why?”
“The Pythonic way to write a for loop is like this
144
“What additional unpacking functionality does Python provide?”
“Python provides additional unpacking functionality to for list construction
145
“What will using unpacking wisely enable you to do?”
“Using unpacking wisely will enable you to avoid indexing when possible
146
“What is the range built-in function useful for?”
“The range built-in function is useful for loops that iterate over a set of integers.”
147
“What can you do when you have a data structure to iterate over?”
“When you have a data structure to iterate over
148
“What do you often want to know when iterating over a list?”
“Often
149
“What built-in function does Python provide to address knowing the index while iterating?”
“Python provides the enumerate built-in function to address this situation.”
150
“What does enumerate yield?”
“enumerate yields pairs of the loop index and the next value from the given iterator.”
151
“What does the built-in next function do?”
“The built-in next function advances an iterator.”
152
“How can each pair yielded by enumerate be used?”
“Each pair yielded by enumerate can be unpacked in a for statement.”
153
“How can you make loops even shorter with enumerate?”
“You can make some loops even shorter by specifying the number from which enumerate should begin counting.”
154
“What do you often find yourself with in Python regarding lists?”
“Often in Python you find yourself with many lists of related objects.”
155
“What do list comprehensions make easy?”
“List comprehensions make it easy to take a source list and get a derived list by applying an expression.”
156
“What is a common way people iterate over a list?”
“A common way people iterate over a list is to iterate over the len of the list using a for loop.”
157
“What are the characteristics of iterating over two lists using a for loop?”
“Iterating over two lists by using a for loop to iterate over one of them is visually noisy and hard to read.”
158
“How is using enumerate compared to the for loop approach?”
“Using enumerate is slightly better
159
“What does the zip function do?”
“The zip function wraps two or more iterators in a lazy generator and then generates tuples with the next value from each iterator.”
160
“How can the tuples from zip be used?”
“These tuples can be unpacked with a for statement.”
161
“How does the resulting code from zip compare to indexing into multiple lists?”
“The resulting code is much cleaner than the code for indexing into multiple lists.”
162
“How does zip consume iterators and what does this mean for memory usage?”
“zip consumes the iterators it wraps one item at a time
163
“What should you beware of regarding zip’s behavior?”
“Beware of zip’s behavior when the input iterators are different lengths.”
164
“What does zip do when iterators are different lengths?”
“zip keeps yielding tuples until any one of the wrapped iterators is exhausted.”
165
“How long is zip’s output?”
“Its output is as long as long as its shortest input.”
166
“When is zip’s approach of stopping at the shortest input fine?”
“This approach is fine when iterators are the same length
167
“How is zip’s behavior in other cases?”
“In other cases
168
“What should you consider if you don’t expect the lengths of lists passed to zip to be equal?”
“If you don’t expect the lengths of the lists passed to zip to be equal
169
“What does zip_longest do with missing values?”
“zip_longest replaces missing values with whatever fillvalue is passed to it (its default is None).”
170
“What do Python loops let you put after a loop’s repeated interior block?”
“Python loops let you put an else block after a loop’s repeated interior block.”
171
“Is this feature available in most other languages?”
“This feature isn’t available in most other languages.”
172
“When does the else block run?”
“The else block runs immediately after the loop finishes.”
173
“Does the else block behavior make sense?”
“This doesn’t really make sense.”
174
“What do else and except clearly mean in if/else and try/except statements?”
“In if/else and try/except statements
175
“What pattern does the else clause in try/except/else follow?”
“The else clause in a try/except/else follows this pattern as well: it will only execute if there is no exception to handle.”
176
“Why is try/finally intuitive?”
“try/finally is also intuitive because it’s clear that the finally block executes after the try block is finished.”
177
“What happens to the else block when using a break statement in a loop?”
“Using a break statement in a loop actually skips the else block.”
178
“What is another surprise about the else block?”
“Another surprise is that the else block runs immediately if you loop over an empty sequence.”
179
“When else does the else block run?”
“The else block also runs when while loops are initially False.”
180
“What is the rationale for these behaviors of else blocks after loops?”
“The rationale for these behaviors is that else blocks after loops are useful when using loops to search for something.”
181
“What doesn’t outweigh the burden on code understanding?”
“The expressivity you gain from using an else block doesn’t outweigh the burden you put on other people (including yourself) who want to understand your code in the future.”
182
“What should simple constructs like loops be in Python?”
“Simple constructs like loops should be self-evident in Python.”
183
“What should you do regarding else blocks after loops?”
“You should avoid using else blocks after loops entirely.”
184
“What is an assignment expression also known as and when was it introduced?”
“An assignment expression (also known as a walrus operator) is a nee syntax introduced in Python 3.8 to solve a long-standing problem with the language that can cause code duplication.”
185
“How are normal assignment statements written and pronounced versus assignment expressions?”
“Whereas normal assignment statements are written a = b and pronounced ““a equals b””
186
“Why are assignment expressions useful?”
“Assignment expressions are useful because they enable you to assign variables in places where assignment statements are disallowed (like the conditional expression of an if statement).”
187
“What does an assignment expression’s value evaluate to?”
“An assignment expression’s value evaluates to whatever was assigned to the operator on the left side of the walrus operator.”
188
“What do people sometimes do that makes code noisier than needed?”
“Sometimes people define a variable above a statement that is only used in one place.”
189
“What does defining a variable above a statement that’s only used in one place do to the code?”
“This code is noisier than it needs to be
190
“What is much more readable to use instead?”
“It’s much more readable to use a walrus operator.”
191
“What pattern is extremely common in Python?”
“The pattern of fetching a value
192
“What do programmers try to do to work around multiple references to a variable?”
“A lot of programmers try to work around multiple references to a variable by using a variety of tricks that hurt readability.”
193
“Why were assignment expressions added to the language?”
“Assignment expressions were added to the language to streamline this process.”
194
“What is an example of code rewritten with a walrus operator and what does it accomplish?”
“Here is an example of code rewritten with a walrus operator. This makes the code a lot more readable and makes it clear that count is only relevant to the first block of the if statement: if count := fresh_fruit.get(‘lemon’
195
“What do assignment expressions do and then evaluate?”
“Assignment expressions assign a value to a variable
196
“What is the fundamental nature of the walrus operator?”
“This behavior (assign and then evaluate) is the fundamental nature of the walrus operator.”
197
“When do you have to surround an assignment expression with parentheses?”
“If an expression is a sub-expression of a larger expression
198
“What should you try to avoid regarding parentheses?”
“Try to avoid surrounding expressions with parentheses when you can.”
199
“What is another common variation of the problematic underused variable pattern?”
“Another common variation of the problematic underused variable pattern is that someone needs to assign a variable in the enclosing scope depending on some condition
200
“What is another common way to handle variable assignment?”
“Another common way to do this is to alter the variable in an else block after it’s referenced by a function.”
201
“Why can this approach feel odd?”
“This approach can feel odd because the variable has 2 different locations where it can initially be defined.”
202
“Does this split work and why do people prefer a different construct?”
“This split technically works because of Python’s scoping rules
203
“What is one way to improve readability?”
“One way to improve readability is to assign a variable outside of a block of code
204
“What is one frustration new Python programmers have?”
“One frustration new Python programmers have is the lack of a flexible switch/case statement.”
205
“What is the general style for appropriating switch/case functionality?”
“The general style for appropriating this type of functionality is to have a deep nesting of multiple if
206
“What does the walrus operator provide for nested if/elif/else statements?”
“The walrus operator provides an elegant solution to making nested if/elif/else statements more readable.”
207
“What should you do if you see ugly constructs in your code?”
“If you see ugly constructs in your code
208
“What is another common frustration of new Python programmers?”
“Another common frustration of new Python programmers is the lack of a do/while loop.”
209
“What is a loop-and-a-half technique?”
“A loop-and-a-half technique is where you use an infinite loop
210
“What does the loop-and-a-half technique undermine?”
“However
211
“When is it time to consider using assignment expressions?”
“When you find yourself repeating the same expression or assignment multiple times within a grouping of lines
212
“What are many programs written to do
and how does Python organize this work?”
213
“What is the dict type and how does it store data?”
“The dict type is similar to lists and stores lookup keys mapped to corresponding values (in what is often called an associative array or a hash table).”
214
“What performance characteristics do dictionaries provide and why are they ideal for certain tasks?”
“Dictionaries provide constant time (amortized) performance for assignments and accesses
215
“How does Python enhance lists and dictionaries beyond other languages?”
“Python has special syntax and built-in modules that enhance readability and extend the capabilities of lists and dictionaries beyond what you might expect from simple array
216
“What does slicing allow you to do and what types support it?”
“Python includes syntax for slicing sequences into pieces. Slicing allows you to access a subset of a sequence’s items with minimal effort. The simplest uses for slicing are built-in types (e.g. list
217
“What is the basic form of slicing syntax and how do start/end indexes work?”
“The basic form of the slicing syntax is list[start:end]
218
“What are the best practices for slicing from the start and end of lists?”
“When slicing from the start of a list
219
“When are negative numbers helpful in slicing?”
“Using negative numbers for slicing is helpful for doing offsets relative to the end of a list.”
220
“How does slicing handle indexes beyond list boundaries
and how does this compare to direct access?”
221
“Give examples of safe slicing operations and one that causes an error. When can you get surprising results?”
“These are fine: first_twenty_items = a[:20] and last_twenty_items = a[-20:]. This will cause an IndexError: a[20]. Indexing a list by a negative variable is one of the few situations where you can get surprising results from slicing.”
222
“What type of object does slicing return and how does modifying slices affect the original list?”
“The result of slicing a list is a whole new list. References to the objects from the original list are maintained. Modifying the result of slicing won’t affect the original list.”
223
“How do slice assignments work and how do they differ from unpacking assignments?”
“When used in assignments
224
“What happens when you slice or assign with no start or end indexes?”
“If you leave out both the start and the end indexes when slicing
225
“What is the syntax for stride in slicing and what does it allow you to do?”
“In addition to basic slicing
226
“What are the main problems with stride syntax?”
“The stride syntax often causes unexpected behavior that can introduce bugs. The stride part of the slicing syntax can be very confusing. Having three numbers within the brackets is hard to read because of the density. It’s not obvious when the start and end indexes come into effect relative to the stride value
227
“Give an example of a common stride trick and when it breaks.”
“A common Python trick for reversing a byte or Unicode string is to slice the string with a stride of -1: x = b’mongoose’
228
“What are the recommendations for using stride safely?”
“To prevent problems
229
“What memory considerations exist with stride operations and what alternative is available?”
“Striding and slicing creates an extra shallow copy of the data. The first operation should try to reduce the size of the resulting slice by as much as possible. If your program can’t afford the time or memory required for two steps
230
“What is the limitation of basic unpacking and how do newcomers typically handle it?”
“One limitation of basic unpacking is that you have to know the length of the sequences you’re unpacking in advance. Newcomers to Python often try to use indexing and slicing to retrieve the first couple of values from a list. This works
231
“What is a starred expression and what are its benefits?”
“A starred expression is a form of catch-all unpacking. This syntax allows one part of the unpacking assignment to receive all values that didn’t match any other part of the unpacking pattern. Using this expression in your code makes it shorter
232
“What are the rules and limitations for starred expressions?”
“To unpack assignments that have a star expression
233
“What type do star expressions become and what happens with no leftover items?”
“Star expressions become list instances in all cases. If there are no leftover items from the sequence being unpacked
234
“How does unpacking generators compare to using indexes and slices
and what risk exists?”
235
“What does the list type’s sort method do and what types does it work with?”
“The list built-in type provides a sort method for ordering the items in a list instance based on a variety of criteria. By default
236
“When should you define natural ordering for custom classes and when doesn’t it make sense?”
“If a class you’re designing should have a natural ordering like integers do
237
“What is the key parameter and how does it work?”
“Often there’s an attribute on the object you’d like to use for sorting. To support this
238
“What can you do within key functions and how might you use them with basic types?”
“Within functions that you pass to the key parameter (including lambda functions)
239
“How do you sort by multiple criteria using tuples?”
“Sometimes you need to use multiple criteria for sorting. The best way to do this is to use the tuple type. Tuples are immutable sequences of arbitrary Python values. They are comparable by default and have a natural ordering
240
“How do tuples implement comparison?”
“Tuples implement these special method comparators by iterating over each position in the tuple and comparing the corresponding values one index at a time. If the first position of 2 tuples being compared are equal
241
“What is the limitation of tuple sorting and how does the reverse parameter affect it?”
“One limitation of having the key function return a tuple is that the direction of the sorting criteria must be the same (either all in descending or ascending order). If you provide the reverse parameter to the sort method
242
“How can you mix sorting directions and what limitation exists?”
“For numerical values it’s possible to mix sorting directions by using the unary minus operator in the key function. This negates one of the values in the returned tuple
243
“How does Python’s stable sorting algorithm work and what does it allow?”
“For situations where unary negation isn’t possible
244
“How do you use multiple sorts and what order should you execute them in?”
“When you use this approach
245
“Which approach is preferred for multiple sorting criteria?”
“The approach of having the key function return a tuple
246
“How did dictionaries behave in Python 3.5 and before
and why?”
247
“When did dictionaries start preserving insertion order and what methods were affected?”
“Starting with Python 3.6
248
“How did the ordering change affect other Python features?”
“There are many repercussions of this change on other Python features that are dependent on the dict type and its specific implementation. Keyword arguments to functions (including the **kwarg catch-all parameter) previously would come through in seemingly random order
249
“Is dictionary insertion ordering part of Python’s specification and can you rely on it?”
“The ways that dictionaries preserve insertion ordering is now part of the Python language specification. For the language features above
250
“What is OrderedDict and when might it be better than regular dict?”
“For a long time the collections built-in module has had an OrderedDict class that preserves insertion ordering. Although this class’s behavior is similar to that of the standard dict type (since Python 3.7)
251
“Should you always assume ordering behavior and what can cause gotchas?”
“You shouldn’t always assume that ordering behavior will be present when you’re handling dictionaries. Python makes it easy for programmers to design custom container types that emulate the standard protocols matching list
252
“How can you create custom dict-like classes and what should you ensure?”
“To create a dict-like class that can hold things in alphabetical order
253
“What are the fundamental dictionary operations and why might keys be missing?”
“The three fundamental operations for interacting with dictionaries are accessing
254
“What does the dict get method do and why is it efficient?”
“The flow of fetching a key that exists or returning a default value is so common that the dict built-in type provides the get method to accomplish this task. The second parameter to get is the default value to return in the case that the key (the first parameter) isn’t present. This only requires one access and one assignment.”
255
“What problems do alternative approaches to get have and when is get best?”
“It’s possible to write short in and KeyError approaches in various ways
256
“What should you consider for counter dictionaries?”
“If you’re maintaining dictionaries of counters
257
“How many accesses do different approaches require for complex dictionary values?”
“If you need to access values that are a complex type in a dictionary (e.g. a list)
258
“What does the setdefault method do and what are its problems?”
“The dict type also provides the setdefault method to shorten this pattern. setdefault tries to fetch the value of a key in the dictionary. If the key isn’t present
259
“What inefficiencies and risks exist with setdefault?”
“If you use the setdefault approach
260
“When are there few instances where setdefault is appropriate and what should you use instead?”
“There are only a few instances where using setdefault is the shortest way to handle missing dictionary keys (e.g. when the default values are cheap to construct
261
“When do various approaches work for missing keys and when does setdefault appear shortest?”
“When you work with a dictionary that you didn’t create there are a variety of ways to handle missing keys. Even though the get method is better than using in expressions and KeyError exceptions
262
“When would you control dictionary creation and what is inefficient about repeated setdefault?”
“One possible case where you’d control the creation of a dictionary you’d access would be when you’re trying to keep track of the internal state of a class. When you use the setdefault method
263
“How does defaultdict solve the setdefault problem and what do you provide to it?”
“The defaultdict class from the collections module simplifies the problem with setdefault above by automatically storing a default value when a key doesn’t exist. All you have to do is provide a function that will return the default value to use each time a key is missing. There are still cases where defaultdict will fall short of solving your problems
264
“When do existing methods fall short and what problems can occur?”
“The built-in dict type’s setdefault method results in shorter code when handling specific keys in some specific circumstances. For many situations like this
265
“How can you handle custom logic for missing keys?”
“You can subclass the dict type and implement the **missing** special method to handle custom logic for handling missing keys.”
266
What is the first functional tool programmers use in Python?
The first functional tool programmers use in Python is the function.
267
What do functions let you do in Python?
Functions let you break down large programs into smaller, simpler pieces with names to represent their intent like in other programming languages.
268
What wide variety of extra features do functions in Python have?
Functions in Python have a wide variety of extra features that make a programmer's life easier by doing things like clarifying the intentions of callers, make a function's purpose more obvious, eliminate noise, or significantly reducing subtle bugs that are difficult to find (among other things).
269
How do Python's function features compare to other languages?
Some of these features are similar to the capabilities of functions in other languages, but many are unique to Python.
270
What effect does unpacking syntax have on Python functions?
One effect of unpacking syntax is that it allows Python functions to seemingly return more than one value.
271
How do Python functions actually return multiple values?
The way that this works is that multiple values are returned in a multi-item tuple.
272
How does the calling code handle multiple return values?
The calling code then unpacks the returned tuples by assigning them to multiple variables.
273
Can multiple return values be received by starred expressions?
Yes, multiple values can also be received by starred expressions for catch-all unpacking.
274
What problem can occur if all return values are numeric?
If all the return values of a function are numeric, it can be very easy to mix them up, which can cause bugs that are hard to catch.
275
What happens when you use a large number of return values?
Using a large number of values is extremely error prone.
276
What issue arises with functions that return several values?
A function that returns several values is long and will probably need to be wrapped in one of several ways, which hurts readability.
277
What is the rule for unpacking multiple return values from a function?
To avoid problems like this, you should never use more than 3 variables when you unpack multiple return values from a function.
278
What could the 3 variables be when unpacking return values?
These could be individual values from a 3 tuple, two variables and one catch-all starred expression, or anything shorter.
279
What should you do if you need to unpack more than 3 return values?
If you need to unpack more return values than that, you're better off defining a lightweight class or namedtuple and having your function return an instance of that instead.
280
Why might Python programmers give special meaning to None as a return value?
When you write a utility function, there's a draw for Python programmers to give special meaning to the return value None. It seems to make sense in some cases.
281
What is a common mistake with None return values?
The misinterpretation of a False-equivalent return value in Python is a common mistake in code when None has a special meaning.
282
How many ways are there to reduce errors with None return values?
There are two ways to reduce the chance of errors like this.
283
What is the first approach to reduce None errors?
One way to reduce the chance of errors like this is to split the return value into a 2-tuple.
284
What does the first part of the 2-tuple approach indicate?
The first part of the tuple indicates whether the operation was a success or failure.
285
What does the second part of the 2-tuple approach contain?
The second part is the actual result of what was computed.
286
What is the problem with the 2-tuple approach?
The problem is that callers can easily ignore the first part of the tuple (using the underscore variable names, a Python convention for unused variables).
287
Why doesn't the 2-tuple approach look wrong at first glance?
The resulting code doesn't look wrong at first glance, but it can be just as error prone as returning None.
288
What is the second and better way to reduce None errors?
The second (and better) way to reduce these errors is to never return None for special cases. Instead, raise an Exception up to the caller and have the caller deal with it.
289
How might you design functions when raising exceptions?
It might be helpful to design functions so that the function can assume that a return value is always valid and use the results immediately in an else block after try (since the function raises an exception).
290
How can you use type annotations with the exception approach?
You can also use the above approach with type annotations.
291
What can you specify about a function's return value with type annotations?
You can specify that a function's return value will always be float and thus will never be None.
292
Does Python's gradual typing provide a way to indicate exceptions in function interfaces?
However, Python's gradual typing purposefully doesn't provide a way to indicate when exceptions are part of a function's interface (also known as checked exceptions).
293
How should you document exception-raising behavior?
Instead, you have to document the exception-raising behavior and expect callers to rely on that in order to know which Exceptions they should plan to catch.
294
What happens when you combine type annotations, docstrings, and exception techniques?
If you use type annotations and docstrings with the other techniques in this section, the chance of the caller doing the wrong thing is extremely low.
295
What is a good use case for closures in sorting?
A good way to do things like rendering a user interface so it display important messages or exceptional events is to sort a list of numbers but prioritize one group of them to come first.
296
What is a common way to implement prioritized sorting?
A common way to do this is to pass a helper function as the key argument to a list's sort method.
297
What will the helper function's return value be used for?
The helper's return value will be used as the value for sorting each item in the list.
298
What can the helper function check for in sorting?
The helper function can check whether the given item is in the important group and can vary the sorting value accordingly.
299
What is the first reason helper functions work for sorting?
Python supports closures (functions that refer to variables from the scope in which they were defined). This is why inner functions can access parameters from their parent functions.
300
What is the second reason helper functions work for sorting?
Functions are first-class objects in Python, which means you can refer to them directly, assign them to variables, pass them as arguments to other functions, compare them in expressions and if statements, and more. This is why the sort function can accept a closure function as the key argument.
301
What is the third reason helper functions work for sorting?
Python has specific rules for comparing sequences (including tuples). It compares the items at index zero and then moves on to index one if they are equal, and so on. This is why the return values from closure functions can cause a sort order to have 2 distinct groups.
302
What is the first scope Python traverses when a variable is referenced?
The current function's scope.
303
What is the second scope Python traverses when a variable is referenced?
Any enclosing scopes (such as other containing functions).
304
What is the third scope Python traverses when a variable is referenced?
The scope of the module that contains the code (also called the global scope).
305
What is the fourth scope Python traverses when a variable is referenced?
The built-in scope (that contains functions like len and str).
306
What happens if a variable is not found in any scope?
If none of these places has defined a variable with the referenced name, then a NameError exception is raised.
307
How does assigning to a variable work differently from referencing it?
Assigning to a variable works differently.
308
What happens if a variable is defined in the current scope when assigning?
If a variable is defined in the current scope, it will take on the new value.
309
What happens if the variable doesn't exist in the current scope when assigning?
If the variable doesn't exist in the current scope, Python treats the assignment as a variable definition.
310
What is critical about the scope of a newly defined variable?
Critically, the scope of the newly defined variable is the function that contains the assignment.
311
What is the scoping bug?
This problem is sometimes called the scoping bug because it can be so surprising to newbies.
312
Why is the scoping bug behavior actually intentional?
But this behavior is the intended result: it prevents local variables in a function from polluting the containment module.
313
What would happen without the scoping bug behavior?
Not only would this be noise, but the interplay of the resulting global variables could cause obscure bugs.
314
What special syntax exists for getting data out of a closure?
In Python, there is a special syntax for getting data out of a closure.
315
What is the nonlocal statement used for?
The nonlocal statement is used to indicate that scope traversal should happen upon assignment for a specific variable name.
316
What is the limit of the nonlocal statement?
The only limit is that nonlocal won't traverse up to the module level scope (to avoid polluting globals).
317
What does the nonlocal statement make clear?
The nonlocal statement makes it clear when data is being assigned out of a closure and into another scope.
318
What is nonlocal complimentary to?
It's complimentary to the global statement, which indicates that a variable's assignment should go directly into the module scope.
319
What caution exists about using nonlocal?
However, much of with the anti-pattern of global variables, I'd caution against using nonlocal for anything beyond simple functions.
320
Why can nonlocal be hard to follow?
The side effects of nonlocal can be hard to follow.
321
Why is nonlocal especially hard to understand in long functions?
It's especially hard to understand in long functions where the nonlocal statements and assignments to associate variables are far apart.
322
What should you do when nonlocal usage gets complicated?
When your usage of nonlocal starts getting complicated, it's better to wrap your state in a helper class.
323
What can accepting variable positional arguments do?
Accepting a variable number of positional arguments can make a function call clearer and reduce visual noise (these positional arguments are often called varargs for short, or star args in reference to the conventional name for the parameter *args).
324
How do you make a parameter accept variable positional arguments?
Prefixing the last positional parameter name at the end of the function with a * makes it a list that contains all of the following positional arguments.
325
What advantage exists when changing a function that uses *args?
If you need to change a function and you use this technique, you don't need to change the body of the function at all, and the responsibility for the changes goes to the caller.
326
How does variadic function syntax compare to starred expressions?
Variadic functions have a very similar syntax to the starred expressions used in unpacking assignments.
327
How can you call a variadic function with a sequence?
If you have a sequence (like a list) and want to call a variadic function, you can do this by using the * operator.
328
What does the * operator do when calling a variadic function?
This instructs Python to pass items from the sequence as positional arguments to the function (function(*sequence)).
329
What is the first issue with optional positional arguments?
One issue with optional positional arguments are always turned into a tuple before they are passed to a function.
330
What does this mean for generators passed with the * operator?
This means that if the caller of a function uses the * operator on a generator, it will be iterated until it's exhausted.
331
When are functions that accept *args best for?
Functions that accept *args are best for situations where you know the number of inputs in the argument list that will be reasonably small.
332
What is *args ideal for?
*args is ideal for function calls that pass many literals or variable names together.
333
What is *args primarily for?
It's primarily for the convenience of the programmer and the readability of the code.
334
What is the second issue with *args?
The second issue with *args is that you can't add new positional arguments to a function in the future without migrating every caller.
335
What happens if you add a positional argument in front of *args?
If you tried to add a positional argument in front of the argument list, existing callers will subtly break if they aren't updated.
336
Why are bugs from adding positional arguments hard to track down?
Bugs of the kind that are mentioned above are hard to track down because the code still runs without raising exceptions.
337
How can you avoid the problem of adding arguments to *args functions?
To avoid this possibility entirely, you should use keyword-only arguments when you want to extend functions that accept *args.
338
What additional defensive measure can you take with *args?
To be even more defensive, you could also consider using type annotations.
339
How does Python let you pass arguments like most other languages?
Like in most other languages, Python lets you pass arguments by position when you call a function.
340
Can normal Python arguments be passed by keyword?
All normal arguments to Python functions can also be passed by keyword, where the name of the argument is used in an assignment within the parentheses of a function call.
341
In what order can keyword arguments be passed?
The keyword arguments can be passed in any order as long as all the required positional arguments are specified.
342
Can you mix keyword and positional arguments?
You can also mix and match keyword and positional arguments.
343
What order must positional and keyword arguments follow?
Positional arguments must be specified before keyword arguments.
344
How many times can each argument be specified?
Each argument can be specified only once.
345
How can you use a dictionary's contents to call a function?
If you already have a dictionary and want to use its contents to call a function, you can do so by using the ** operator.
346
What does the ** operator do?
This instructs Python to pass the values from the dictionary as the corresponding keyword arguments of the function.
347
Can you mix the ** operator with other arguments?
You can mix the ** operator with positional or keyword arguments in the function call, as long as no argument is repeated.
348
Can you use the ** operator multiple times?
You can also use the ** operator multiple times if you know the dictionaries don't contain overlapping keys.
349
What is the **kwargs catch-all parameter?
If you'd like for a function to receive any named keyword argument, you can use the **kwargs catch-all parameter to collect those arguments into a dict that you can then process.
350
What is the first benefit of keyword arguments?
One benefit of keyword arguments is that they make the function call clearer to new readers of the code.
351
What is another benefit of keyword arguments?
Another benefit of keyword arguments is that they can have default values specified in the function definition.
352
What do default values allow a function to do?
This allows a function to provide additional capabilities when you need them, but you can accept the default behavior most of the time.
353
What does having default values eliminate?
This eliminates repetitive code and reduces noise.
354
What does the fact that keyword arguments have default values mean?
The fact that keyword arguments have a default values means that they can reduce noise.
355
When do keyword arguments with defaults work well?
Using keyword arguments like this works well for simple values, but it gets tricky for complex default values.
356
Are keyword arguments required?
Keyword arguments are optional.
357
What is one last benefit of keyword arguments?
One last benefit of keyword arguments is that they provide a powerful way to extend a function's parameters while remaining backwards compatible with existing callers.
358
What does backward compatibility mean for code migration?
This means you can provide additional functionality without having to migrate a lot of existing code, which reduces the chance of introducing bugs.
359
When is providing backward compatibility crucial?
Providing backwards compatibility using optional arguments is crucial for functions that accept *args.
360
What is the problem with optional keyword arguments?
The only problem with using optional keyword arguments is that they may be specified as positional arguments.
361
Why is supplying optional arguments positionally confusing?
Supplying optional arguments positionally can be confusing because it isn't clear what the values correspond to.
362
What is the best practice for optional arguments?
The best practice is to always specify optional arguments using the keyword names and never pass them as positional arguments.
363
What can function authors do to minimize errors?
As a function author, you can also require that callers use this more explicit keyword style to minimize potential errors.
364
When might you need to use a non-static type as a default value?
Sometimes you need to use a non-static type as a keyword argument's default value.
365
When is a default argument value evaluated?
A default argument value is only evaluated once per module load, which usually happens when a program starts up.
366
What is the convention for avoiding default value problems?
The convention for making sure that you don't run into default value problems is to provide a default value of None and to document the actual behavior in the docstring.
367
What should your code do when it sees None as a default?
When your code sees the default value None, it allocates the default value accordingly.
368
When is using None for default values especially important?
Using None for default argument values is especially important when the arguments are mutable.
369
What should you not assign as a default value?
Don't assign a dictionary as a default value because run into the problems described above.
370
Can you use the None approach with type annotations?
You can also use the None approach with type annotations.
371
What does the flexibility of keyword arguments enable?
The flexibility of keyword arguments enables you to write functions that will be clear to new readers of your code for many use cases.
372
What can happen if you use arguments that are hard to make sense of?
If you use arguments that are hard to make sense of in your code, this can cause bugs that are hard to track down.
373
What is one way to fix issues with unclear arguments?
One way to fix the issue mentioned above is to use keyword arguments.
374
What is the problem with keyword arguments being optional?
The problem with using keyword arguments is they are optional, so callers can ignore them.
375
What is better than keyword arguments for complex functions?
It's better to use keyword-only arguments with complex functions than keyword arguments.
376
How do keyword-only arguments work?
These arguments can only be supplied by keyword, never by position.
377
What does the * in the argument list indicate?
The * in the argument list indicated the end of a positional argument and the beginning of keyword-only arguments.
378
What happens when you update a function to use keyword-only arguments?
Updating a function to use the strategy mentioned above will break all the previous callers to the function.
379
What are positional-only arguments?
Positional-only arguments can only be supplied by position.
380
What character indicates where positional-only arguments end?
The / character indicates where the positional-only arguments end.
381
What advantage do positional-only arguments provide?
Using positional-only arguments will make it so all the previous calls won't break if you use the strategy mentioned above.
382
What can parameters between / and * do?
One notable consequence of keyword and positional-only arguments is that any parameter name between / and * in the argument can be passed by either position or by keyword (which is the default for all function arguments in Python).
383
How can allowing both argument passing styles affect code?
Depending on your API's style or needs, allowing both argument passing styles can increase readability and noise.
384
What special syntax does Python have for decorators?
Python has a special syntax for decorators that can be applied to functions.
385
What ability does a decorator have?
A decorator has the ability to run additional code before and after each call to a function it wraps.
386
What can decorators access and modify?
This means that decorators can access and modify input arguments, return values, and raised exceptions.
387
What can decorator functionality be useful for?
This functionality can be useful for enforcing schematics, debugging, registering functions, and more.
388
How do you apply a decorator to a function?
You can apply this decorator to a function by using the @ symbol.
389
What is using the @ symbol equivalent to?
Using the @ symbol is equivalent to calling the decorator on the function it wraps and assigns the return value to the original name in the same scope.
390
What is the first problem with using decorators?
The problem with using decorators is the value that's returned (the function that's called) doesn't think it goes by the function name it goes by.
391
Why does this problem occur with decorators?
This is because the wrapping function is what's assigned to the normal function name because of the decorator.
392
Why is this problematic?
This is problematic because it undermines tools that do introspection, like debuggers.
393
What is another problem decorators cause?
Another problem decorators cause is that they break object serializers because they can't determine the location of the original function that was decorated.
394
What is the solution to decorator problems?
The solution to these problems is to use the wraps helper function from the functools built-in module.
395
What is the wraps helper function?
It's a decorator that helps you write decorators.
396
What does wraps do when you apply it to a function?
When you apply it to a function, it copies all the important metadata about the inner function to the outer function.
397
Does the pickle object serializer work with wraps?
The pickle object serializer also works.
398
What else does using wraps ensure?
Using wraps also ensures that you'll be able to preserve all the Python attributes that must be maintained in order to maintain the interface functions of the language.
399
“What are many programs built around?”
“Many programs are built around processing lists
400
“What special syntax does Python provide for iterating through lists
dictionaries
401
“How can comprehensions benefit code?”
“Comprehensions can significantly increase the readability of code performing these common tasks and provide a number of other benefits.”
402
“How is comprehension-style processing extended to functions?”
“This style of processing is extended to functions with generators
403
“Where can generator function results be used?”
“The result of a call to a generator function can be used anywhere an iterator is appropriate (e.g. for loops
404
“What benefits do generators provide?”
“Generators can improve performance
405
“What does Python provide for deriving a new list from another sequence or iterable?”
“Python provides a compact syntax for deriving a new list from another sequence or iterable.”
406
“What are these expressions called?”
“These expressions are called list comprehensions.”
407
“How do list comprehensions compare to the map built-in function?”
“Unless you’re applying a single-argument function
408
“Why is map visually noisy?”
“map requires the creation of a lambda function for the computation
409
“How do list comprehensions handle filtering compared to map?”
“Unlike map
410
“How can you achieve the same outcome as list comprehensions using filter and map?”
“The filter built-in function can be used along with map to achieve the same outcome
411
“What equivalents do dictionaries and sets have for list comprehensions?”
“Dictionaries and sets have their own equivalents of list comprehensions (called dictionary comprehensions and set comprehensions).”
412
“What do dictionary and set comprehensions make easy to do?”
“They make it easy to create other types of derivative data structures when writing algorithms.”
413
“Why should wrapping map and filter calls with constructors be avoided?”
“Achieving the same outcome is possible with map and filter if you wrap each call with a corresponding constructor. These statements get so long that you have to break them up across multiple lines
414
“What does comprehensions support beyond basic usage?”
“Beyond basic usage
415
“What is the order of subexpressions in comprehensions?”
“These subexpressions run in the order provided
416
“What types of conditions do comprehensions support?”
“Comprehensions support multiple if conditions.”
417
“How are multiple conditions at the same loop level represented?”
“Multiple conditions at the same loop level have an explicit and expressions.”
418
“Where can conditions be specified in comprehensions?”
“Conditions can be specified at each level of looping after the for subexpression.”
419
“When might complex comprehensions seem like a good fit?”
“Sometimes you’ll see situations where this looks like a good fit.”
420
“Is it advisable to use complex list
dict
421
“Why is the resulting code from complex comprehensions problematic?”
“The resulting code is very difficult for new readers to understand.”
422
“Why is confusion worse for dict comprehensions?”
“The potential for confusion is even worse for dict comprehensions since they already need an extra parameter to represent both the key and the value for each item.”
423
“What is the rule of thumb for comprehension control subexpressions?”
“The rule of thumb is to avoid using more than two control subexpressions in a comprehension (e.g. two conditions
424
“What should you do when comprehensions become more complex?”
“As soon as it gets more complicated than that
425
“What is a common pattern with comprehensions?”
“A common pattern with comprehensions (including list
426
“Should you assign values to dictionaries using loops?”
“Instead of assigning values to dictionaries by using loops
427
“How can you increase readability and reduce bugs in comprehensions?”
“One way to increase readability by reducing unnecessary visual noise and reduce the likelihood of bugs occurring if the two expressions aren’t kept in sync is to use the walrus operator in the assignment expression of the comprehension.”
428
“Is it valid to use assignment expressions in the value part of a comprehension?”
“It’s valid syntax to define an assignment expression in the value expression for a comprehension
429
“What happens if a comprehension uses the walrus operator in the value part without a conditional?”
“If a comprehension uses the walrus operator in the value part of the comprehension and doesn’t have a conditional
430
“Does variable leakage happen for loop variables in comprehensions?”
“Variable leakage doesn’t happen for the loop variables in a comprehension like it does in a for loop.”
431
“Where should you use assignment expressions in comprehensions?”
“To avoid leaking loop variables
432
“How do assignment expressions work in generator expressions?”
“Using an assignment expression also works the same way in generator expressions.”
433
“What is the simplest choice for a function that produces a sequence of results?”
“The simplest choice for a function that produces a sequence of results is to return a list of items.”
434
“What is a better alternative to returning a list?”
“A better thing to do is to use a generator (functions that use yield expressions).”
435
“What happens when a generator function is called?”
“When called
436
“What does each call to the next built-in function do?”
“With each call to the next built-in function
437
“What happens to each value passed to yield?”
“Each value passed to yield by the generator is returned by the iterator to the caller.”
438
“Why is using generator functions easier than returning a list?”
“Using generator functions instead of returning a list is significantly easier because all interactions with a list have been eliminated.”
439
“Can you convert an iterator from a generator to a list?”
“You can also convert the iterator returned by the generator to a list by using the list built-in function if you need to.”
440
“What problem can storing a huge input in a list cause?”
“Another problem is that if you have to store a huge input in a list
441
“How do generators handle arbitrary length inputs?”
“In contrast
442
“What must callers be aware of with generators?”
“The only thing you have to watch out for when you define generators is that the callers must be aware that iterators returned are stateful and can’t be re-used.”
443
“When is it important to iterate over a list parameter multiple times?”
“When a function takes a list of objects as a parameter
444
“When do generators yield empty results?”
“Sometimes generators yield empty results.”
445
“Why does this happen?”
“This happens because an iterator produces its results only a single time.”
446
“What happens when you iterate over an exhausted iterator?”
“If you iterate over an iterator or generator that has already raised a StopIteration exception
447
“What happens when you iterate over an already exhausted iterator without raising an error?”
“You won’t get any errors when you iterate over an already exhausted iterator.”
448
“Which Python features expect the StopIteration exception?”
“for loops
449
“What can’t these functions distinguish?”
“These functions can’t tell the difference between an iterator that has no output and an iterator that had no output and is now exhausted.”
450
“What is the first solution to the multiple iteration problem?”
“To solve the above problem
451
“What can you do after exhausting and copying an iterator?”
“You can then iterate over the list version of the data as many time as you need to.”
452
“What is the problem with exhausting and copying?”
“The problem with this approach is the copy of the input iterator’s contents could be extremely large.”
453
“What could large copies cause?”
“Copying the iterator could cause the program to run out of memory and crash.”
454
“What is one way around the size problem?”
“One way around this is to accept a function that returns a new iterator every time it’s called.”
455
“Can you include what type of function as an argument?”
“You can also include a lambda function as an argument.”
456
“What is the second solution to the multiple iteration problem?”
“A better solution to the above problem is to provide a new container class that implements the iterator protocol.”
457
“What is the iterator protocol?”
“The iterator protocol is how Python for loops and related expressions traverse the contents of a container type.”
458
“What does Python actually call when seeing ‘for x in foo’?”
“When Python sees a statement like for x in foo
459
“What function does iter call?”
“The iter built-in function calls the foo.**iter** special method in turn.”
460
“What must the **iter** method return?”
“The **iter** method must return an iterator object (which itself must implement the **next** special method).”
461
“What does the for loop do with the iterator object?”
“Then
462
“How can you implement this behavior for your classes?”
“This sounds complicated
463
“How can you ensure parameters aren’t just iterators?”
“Now that you know how containers work
464
“What does the iterator protocol state about passing iterators to iter?”
“The protocol states that when an iterator is passed to the iter built-in function
465
“What happens when a container type is passed to iter?”
“In contrast
466
“How can you test for this behavior?”
“Thus
467
“What alternative exists in the collections.abc module?”
“Alternatively
468
“When is the container approach ideal?”
“The approach of using a container is ideal if you don’t want to copy the full input iterator
469
“Can the container approach be used for other iterables?”
“The same approach can be used for asynchronous iterators.”
470
“What is the problem with lost comprehensions?”
“The problem with lost comprehensions is that they may create new list instances containing one item for each value in input sequences.”
471
“When is this fine?”
“This is fine for small inputs
472
“What does Python provide to solve this issue?”
“To solve this issue
473
“What don’t generator expressions do?”
“Generator expressions don’t materialize the whole output sequence when they’re run.”
474
“What do generator expressions do instead?”
“Instead
475
“How do you create a generator expression?”
“You create a generator by putting list-comprehension-like syntax between () characters.”
476
“How can you advance a generator expression iterator?”
“An iterator returned by a generator expression can be advanced one step at a time to produce the next output from the generator expression
477
“What risk do you avoid by using generator expressions?”
“You can consume just as much of the generator expression as you want without risking a blowup in memory usage.”
478
“What is a powerful outcome of generator expressions?”
“Another powerful outcome of generator expressions is that they can be composed together (roots = ((x
479
“What happens each time the composed iterator gets advanced?”
“Each time the iterator above gets advanced
480
“How fast does chaining generators execute in Python?”
“Chaining generators together like this executes very quickly in Python.”
481
“When are generator expressions a great choice?”
“When you’re looking for a way to compose functionality that’s operating on a large stream of input
482
“What is the only problem with generator expressions?”
“The only problem is that the iterators returned by generator expressions are stateful
483
“What benefits do generators provide in general?”
“Generators provide a variety of benefits and solutions to common problems.”
484
“Why are generators so useful?”
“Generators are so useful that many programs start to look like layers of generators strung together.”
485
“What does multiple for statements with yield expressions do?”
“Multiple for statements with their own yield expressions for each statement adds noise and reduces readability.”
486
“What is the solution to this problem?”
“The solution to the above problem is to use the yield from expression.”
487
“What does yield from allow you to do?”
“This advanced generator feature allows you to yield all values from a nested generator before returning control to a parent generator.”
488
“How does yield from improve code?”
“It makes code that uses the bad pattern above cleaner and more intuitive. yield from essentially causes the Python interpreter to handle the nested for loop and yield expression boilerplate for you
489
“When should you consider using yield from?”
“If you compose generators
490
“What do yield expressions provide?”
“yield expressions provide generator functions with a simple way to produce an iterable series of output values.”
491
“What appears to be the nature of this channel?”
“However
492
“Why would bidirectional communication be valuable?”
“Having such bidirectional communication could be valuable for a variety of use cases.”
493
“What does Python generators support?”
“Python generators support the send method
494
“What can the send method do?”
“The send method can be used to provide streaming inputs to a generator at the same time it’s yielding outputs.”
495
“What is the normal value of a yield expression?”
“Normally
496
“What happens when you use the send method?”
“When you use the send method instead of iterating the generator with a for loop or the next built-in function
497
“What is the only valid value for send if the generator hasn’t reached yield yet?”
“However
498
“Why is yield on the right side of an assignment expression problematic?”
“Using a yield on the right side of the assignment expression (var = value) is problematic because it isn’t intuitive.”
499
“What happens after a yield from statement finishes iterating?”
“If a yield from statement finishes iterating over a nested generator
500
“What does a bare yield expression cause?”
“If a nested generator starts with a bare yield expression (one without a value)
501
“What is problematic about using yield from and send together?”
“Assumptions about how the yield from and send features will behave individually if you try to use them together. Although it’s possible to work around the None problem by increasing the complexity of any functions that have these issues
502
“Why is the complexity not worth it?”
“It’s already difficult for new readers of the code to understand how send works. This surprising problem with yield from makes it even worse.”
503
“What is the easiest solution?”
“The easiest solution is to pass an iterator to functions that would use yield from and send that returns the next value that would have been returned otherwise every time the next built-in function is called on it.”
504
“What does this arrangement ensure?”
“This arrangement ensures that each generator is progressed in a cascade as inputs and outputs are processed.”
505
“Can you pass iterators to multiple generator functions?”
“You can pass iterators to several different generator functions that you chain together
506
“How are stateful iterators beneficial here?”
“Iterators are stateful
507
“Where can the iterator come from?”
“The best part about the above approach is that the iterator can come from anywhere and could be completely dynamic (e.g. implemented using a generator function).”
508
“What is the only downside?”
“The only downside is that this code assumes that the input generator is completely thread-safe
509
“What might be better for crossing thread boundaries?”
“If you need to cross thread boundaries
510
“What other advanced generator feature exists?”
“In addition to yield from expressions and the send method
511
“How does the throw method work?”
“The way throw works is simple: when the method is called
512
“How can throw exceptions be handled?”
“When you call throw
513
“What does throw provide?”
“The functionality provides a two-way communication channel between a generator and its caller that can be useful in certain situations.”
514
“What should you avoid using with generators?”
“Don’t use try/except clauses with generators
515
“What is a solution to throw problems?”
“A solution to the above problem is to define a stateful closure using an iterable container object.”
516
“How does the container object approach help?”
“Using this approach makes your code easier to read
517
“What is often a better way to accomplish complex generator patterns?”
“Often
518
“What should you use instead of throw?”
“You should avoid using throw entirely and instead using an iterable class if you need this type of exceptional behavior.”
519
“What does the itertools built-in module contain?”
“The itertools built-in module contains a large number of functions that are useful for organizing and interacting with iterators.”
520
“What should you do when dealing with tricky iteration code?”
“Whenever you find yourself dealing with tricky iteration code
521
“What does the itertools module include for linking iterators?”
“The itertools built-in module includes a number of functions for linking iterators together.”
522
“What does chain do?”
“You can use chain to combine multiple iterators together into a single sequential iterator.”
523
“What does repeat do?”
“Use repeat to output a single value forever
524
“What does cycle do?”
“Use cycle to repeat an iterator’s items forever.”
525
“What does tee do?”
“Use tee to split a single iterator into the number of parallel iterators specified by the second parameter.”
526
“When does tee’s memory usage grow?”
“The memory usage of this function will grow if the iterators don’t progress at the same speed since buffering will be required to enqueue the pending items.”
527
“What is zip_longest?”
“This variant of the zip built-in function returns a placeholder value when an iterator is exhausted
528
“What does the itertools module include for filtering?”
“The itertools built-in module includes a number of functions for filtering items from an iterator.”
529
“What does islice do?”
“Use islice to slice an iterator by numerical indexes without copying it.”
530
“What parameters can islice take?”
“You can specify the end
531
“What does takewhile do?”
“takewhile returns items from an iterator until a predicate function returns False for an item.”
532
“What does dropwhile do?”
“dropwhile
533
“What does filterfalse do?”
“filterfalse
534
“What does the itertools module include for producing combinations?”
“The itertools built-in module includes a number of functions for producing combinations of items from iterators.”
535
“What does accumulate do?”
“accumulate folds an item from the iterator into a running value by applying a function that takes two parameters.”
536
“What does accumulate output?”
“It outputs the current accumulated result for each input value.”
537
“What does product return?”
“product returns the Cartesian product of items for one or more iterators
538
“What does permutations return?”
“permutations returns the unique ordered permutations of length N with items from an iterator.”
539
“What does combinations return?”
“combinations returns the unordered combinations of length N with unrepeated items from an iterator.”
540
“What does combinations_with_replacements do?”
“combinations_with_replacements is the same as combinations