mirror of
https://github.com/kennethreitz/dive-into-python3.git
synced 2026-06-05 23:10:17 +00:00
merge changes
This commit is contained in:
@@ -76,7 +76,7 @@ pre, kbd, samp, code, var, .b, pre span {
|
||||
.u {
|
||||
font: medium/1.75 'Arial Unicode MS', FreeSerif, OpenSymbol, 'DejaVu Sans', sans-serif;
|
||||
}
|
||||
pre .u, pre .u span, .a {
|
||||
pre .u, td .u, pre .u span, .a {
|
||||
font: medium/1.75 'Arial Unicode MS', 'DejaVu Sans', FreeSerif, OpenSymbol, sans-serif;
|
||||
}
|
||||
.baa {
|
||||
|
||||
+1
-1
@@ -93,7 +93,7 @@ My alphabet starts where your alphabet ends! <span class=u>❞</span><br>&m
|
||||
<samp class=pp>'深入 Python 3'</samp></pre>
|
||||
<ol>
|
||||
<li>To create a string, enclose it in quotes. Python strings can be defined with either single quotes (<code>'</code>) or double quotes (<code>"</code>).<!--"-->
|
||||
<li>The built-in <code><dfn>len</dfn>()</code> function returns the length of the string, <i>i.e.</i> the number of characters. This is the same function you use to <a href=native-datatypes.html#extendinglists>find the length of a list</a>. A string is like a list of characters.
|
||||
<li>The built-in <code><dfn>len</dfn>()</code> function returns the length of the string, <i>i.e.</i> the number of characters. This is the same function you use to <a href=native-datatypes.html#extendinglists>find the length of a list, tuple, set, or dictionary</a>. A string is like a tuple of characters.
|
||||
<li>Just like getting individual items out of a list, you can get individual characters out of a string using index notation.
|
||||
<li>Just like lists, you can <dfn>concatenate</dfn> strings using the <code>+</code> operator.
|
||||
</ol>
|
||||
|
||||
+14
-12
@@ -128,13 +128,13 @@ if __name__ == '__main__':
|
||||
unittest.main()</code></pre>
|
||||
<ol>
|
||||
<li>To write a test case, first subclass the <code>TestCase</code> class of the <code>unittest</code> module. This class provides many useful methods which you can use in your test case to test specific conditions.
|
||||
<li>This is a list of integer/numeral pairs that I verified manually. It includes the lowest ten numbers, the highest number, every number that translates to a single-character Roman numeral, and a random sampling of other valid numbers. The point of a unit test is not to test every possible input, but to test a representative sample.
|
||||
<li>This is a list of integer/numeral pairs that I verified manually. It includes the lowest ten numbers, the highest number, every number that translates to a single-character Roman numeral, and a random sampling of other valid numbers. You don’t need to test every possible input, but you should try to test all the obvious edge cases.
|
||||
<li>Every individual test is its own method, which must take no parameters and return no value. If the method exits normally without raising an exception, the test is considered passed; if the method raises an exception, the test is considered failed.
|
||||
<li>Here you call the actual <code>to_roman()</code> function. (Well, the function hasn’t be written yet, but once it is, this is the line that will call it.) Notice that you have now defined the <abbr>API</abbr> for the <code>to_roman()</code> function: it must take an integer (the number to convert) and return a string (the Roman numeral representation). If the <abbr>API</abbr> is different than that, this test is considered failed. Also notice that you are not trapping any exceptions when you call <code>to_roman()</code>. This is intentional. <code>to_roman()</code> shouldn’t raise an exception when you call it with valid input, and these input values are all valid. If <code>to_roman()</code> raises an exception, this test is considered failed.
|
||||
<li>Assuming the <code>to_roman()</code> function was defined correctly, called correctly, completed successfully, and returned a value, the last step is to check whether it returned the <em>right</em> value. This is a common question, and the <code>TestCase</code> class provides a method, <code>assertEqual</code>, to check whether two values are equal. If the result returned from <code>to_roman()</code> (<var>result</var>) does not match the known value you were expecting (<var>numeral</var>), <code>assertEqual</code> will raise an exception and the test will fail. If the two values are equal, <code>assertEqual</code> will do nothing. If every value returned from <code>to_roman()</code> matches the known value you expect, <code>assertEqual</code> never raises an exception, so <code>test_to_roman_known_values</code> eventually exits normally, which means <code>to_roman()</code> has passed this test.
|
||||
</ol>
|
||||
<aside>Write a test that fails, then code until it passes.</aside>
|
||||
<p>Once you have a test case, you can start coding the <code>to_roman()</code> function. First, you should stub it out as an empty function and make sure the tests fail. If the tests succeed before you’ve written any code, you’re doing it wrong — your tests aren’t testing your code at all! Write a test that fails, then code until it passes.
|
||||
<p>Once you have a test case, you can start coding the <code>to_roman()</code> function. First, you should stub it out as an empty function and make sure the tests fail. If the tests succeed before you’ve written any code, your tests aren’t testing your code at all! Unit testing is a dance: tests lead, code follows. Write a test that fails, then code until it passes.
|
||||
<pre><code class=pp># roman1.py
|
||||
|
||||
def to_roman(n):
|
||||
@@ -166,7 +166,7 @@ Traceback (most recent call last):
|
||||
<li>For each test case, the <code>unittest</code> module will print out the <code>docstring</code> of the method and whether that test passed or failed. As expected, this test case fails.
|
||||
<li>For each failed test case, <code>unittest</code> displays the trace information showing exactly what happened. In this case, the call to <code>assertEqual()</code> raised an <code>AssertionError</code> because it was expecting <code>to_roman(1)</code> to return <code>'I'</code>, but it didn’t. (Since there was no explicit return statement, the function returned <code>None</code>, the Python null value.)
|
||||
<li>After the detail of each test, <code>unittest</code> displays a summary of how many tests were performed and how long it took.
|
||||
<li>Overall, the unit test failed because at least one test case did not pass. When a test case doesn’t pass, <code>unittest</code> distinguishes between failures and errors. A failure is a call to an <code>assertXYZ</code> method, like <code>assertEqual</code> or <code>assertRaises</code>, that fails because the asserted condition is not true or the expected exception was not raised. An error is any other sort of exception raised in the code you’re testing or the unit test case itself.
|
||||
<li>Overall, the test run failed because at least one test case did not pass. When a test case doesn’t pass, <code>unittest</code> distinguishes between failures and errors. A failure is a call to an <code>assertXYZ</code> method, like <code>assertEqual</code> or <code>assertRaises</code>, that fails because the asserted condition is not true or the expected exception was not raised. An error is any other sort of exception raised in the code you’re testing or the unit test case itself.
|
||||
</ol>
|
||||
<p><em>Now</em>, finally, you can write the <code>to_roman()</code> function.
|
||||
<p class=d>[<a href=examples/roman1.py>download <code>roman1.py</code></a>]
|
||||
@@ -461,7 +461,7 @@ OK</samp></pre>
|
||||
<samp class=p>>>> </samp><kbd class=pp>import roman3</kbd>
|
||||
<a><samp class=p>>>> </samp><kbd class=pp>roman3.to_roman(0.5)</kbd> <span class=u>①</span></a>
|
||||
<samp class=pp>''</samp>
|
||||
<a><samp class=p>>>> </samp><kbd class=pp>roman3.to_roman(1.5)</kbd> <span class=u>②</span></a>
|
||||
<a><samp class=p>>>> </samp><kbd class=pp>roman3.to_roman(1.0)</kbd> <span class=u>②</span></a>
|
||||
<samp class=pp>'I'</samp></pre>
|
||||
<ol>
|
||||
<li>Oh, that’s bad.
|
||||
@@ -570,9 +570,9 @@ OK</samp></pre>
|
||||
result = roman5.from_roman(numeral)
|
||||
self.assertEqual(integer, result)</code></pre>
|
||||
|
||||
<p>There’s a pleasing symmetry here. The <code>to_roman()</code> and <code>from_roman()</code> functions are inverses of each other. The first converts integers to specially-formatted strings, the second converts specially-formated strings to integers. In theory, we should be able to “round-trip” a number by passing to the <code>to_roman()</code> function to get a string, then passing that string to the <code>from_roman()</code> function to get an integer, and end up with the same number. In mathematical terms,
|
||||
<p>There’s a pleasing symmetry here. The <code>to_roman()</code> and <code>from_roman()</code> functions are inverses of each other. The first converts integers to specially-formatted strings, the second converts specially-formated strings to integers. In theory, we should be able to “round-trip” a number by passing to the <code>to_roman()</code> function to get a string, then passing that string to the <code>from_roman()</code> function to get an integer, and end up with the same number.
|
||||
|
||||
<pre class=nd><code class=pp>x = f(g(x)) for all values of x</code></pre>
|
||||
<pre class=nd><code class=pp>n = from_roman(to_roman(n)) for all values of n</code></pre>
|
||||
|
||||
<p>In this case, “all values” means any number between <code>1..3999</code>, since that is the valid range of inputs to the <code>to_roman()</code> function. We can express this symmetry in a test case that runs through all the values <code>1..3999</code>, calls <code>to_roman()</code>, calls <code>from_roman()</code>, and checks that the output is the same as the original input.
|
||||
|
||||
@@ -618,6 +618,8 @@ FAILED (errors=2)</samp></pre>
|
||||
def from_roman(s):
|
||||
'''convert Roman numeral to integer'''</code></pre>
|
||||
|
||||
<p>(Hey, did you notice that? I defined a function with nothing but a <a href=your-first-python-program.html#docstrings>docstring</a>. That’s legal Python. In fact, some programmers swear by it. “Don’t stub; document!”)
|
||||
|
||||
<p>Now the test cases will actually fail.
|
||||
|
||||
<pre class='nd screen'>
|
||||
@@ -652,7 +654,7 @@ FAILED (failures=2)</samp></pre>
|
||||
"""convert Roman numeral to integer"""
|
||||
result = 0
|
||||
index = 0
|
||||
for numeral, integer in romanNumeralMap:
|
||||
for numeral, integer in roman_numeral_map:
|
||||
while s[index:index+len(numeral)] == numeral: <span class=u>①</span>
|
||||
result += integer
|
||||
index += len(numeral)
|
||||
@@ -667,7 +669,7 @@ FAILED (failures=2)</samp></pre>
|
||||
"""convert Roman numeral to integer"""
|
||||
result = 0
|
||||
index = 0
|
||||
for numeral, integer in romanNumeralMap:
|
||||
for numeral, integer in roman_numeral_map:
|
||||
while s[index:index+len(numeral)] == numeral:
|
||||
result += integer
|
||||
index += len(numeral)
|
||||
@@ -706,11 +708,11 @@ OK</samp></pre>
|
||||
<p>As you saw in <a href=regular-expressions.html#romannumerals>Case Study: Roman Numerals</a>, there are several simple rules for constructing a Roman numeral, using the letters <code>M</code>, <code>D</code>, <code>C</code>, <code>L</code>, <code>X</code>, <code>V</code>, and <code>I</code>. Let's review the rules:
|
||||
|
||||
<ol>
|
||||
<li>Characters are additive. <code>I</code> is <code>1</code>, <code>II</code> is <code>2</code>, and <code>III</code> is <code>3</code>. <code>VI</code> is <code>6</code> (literally, “<code>5</code> and <code>1</code>”), <code>VII</code> is <code>7</code>, and <code>VIII</code> is <code>8</code>.
|
||||
<li>Sometimes characters are additive. <code>I</code> is <code>1</code>, <code>II</code> is <code>2</code>, and <code>III</code> is <code>3</code>. <code>VI</code> is <code>6</code> (literally, “<code>5</code> and <code>1</code>”), <code>VII</code> is <code>7</code>, and <code>VIII</code> is <code>8</code>.
|
||||
<li>The tens characters (<code>I</code>, <code>X</code>, <code>C</code>, and <code>M</code>) can be repeated up to three times. At <code>4</code>, you need to subtract from the next highest fives character. You can't represent <code>4</code> as <code>IIII</code>; instead, it is represented as <code>IV</code> (“<code>1</code> less than <code>5</code>”). <code>40</code> is written as <code>XL</code> (“<code>10</code> less than <code>50</code>”), <code>41</code> as <code>XLI</code>, <code>42</code> as <code>XLII</code>, <code>43</code> as <code>XLIII</code>, and then <code>44</code> as <code>XLIV</code> (“<code>10</code> less than <code>50</code>, then <code>1</code> less than <code>5</code>”).
|
||||
<li>Similarly, at <code>9</code>, you need to subtract from the next highest tens character: <code>8</code> is <code>VIII</code>, but <code>9</code> is <code>IX</code> (“<code>1</code> less than <code>10</code>”), not <code>VIIII</code> (since the <code>I</code> character can not be repeated four times). <code>90</code> is <code>XC</code>, <code>900</code> is <code>CM</code>.
|
||||
<li>Sometimes characters are… the opposite of additive. By putting certain characters before others, you subtract from the final value. For example, at <code>9</code>, you need to subtract from the next highest tens character: <code>8</code> is <code>VIII</code>, but <code>9</code> is <code>IX</code> (“<code>1</code> less than <code>10</code>”), not <code>VIIII</code> (since the <code>I</code> character can not be repeated four times). <code>90</code> is <code>XC</code>, <code>900</code> is <code>CM</code>.
|
||||
<li>The fives characters can not be repeated. <code>10</code> is always represented as <code>X</code>, never as <code>VV</code>. <code>100</code> is always <code>C</code>, never <code>LL</code>.
|
||||
<li>Roman numerals are always written highest to lowest, and read left to right, so order of characters matters very much. <code>DC</code> is <code>600</code>; <code>CD</code> is a completely different number (<code>400</code>, “<code>100</code> less than <code>500</code>”). <code>CI</code> is <code>101</code>; <code>IC</code> is not even a valid Roman numeral (because you can't subtract <code>1</code> directly from <code>100</code>; you would need to write it as <code>XCIX</code>, “<code>10</code> less than <code>100</code>, then <code>1</code> less than <code>10</code>”).
|
||||
<li>Roman numerals are read left to right, so the order of characters matters very much. <code>DC</code> is <code>600</code>; <code>CD</code> is a completely different number (<code>400</code>, “<code>100</code> less than <code>500</code>”). <code>CI</code> is <code>101</code>; <code>IC</code> is not even a valid Roman numeral (because you can't subtract <code>1</code> directly from <code>100</code>; you would need to write it as <code>XCIX</code>, “<code>10</code> less than <code>100</code>, then <code>1</code> less than <code>10</code>”).
|
||||
</ol>
|
||||
|
||||
<p>Thus, one useful test would be to ensure that the <code>from_roman()</code> function should fail when you pass it a string with too many repeated numerals. How many is “too many” depends on the numeral.
|
||||
@@ -728,7 +730,7 @@ OK</samp></pre>
|
||||
for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'):
|
||||
self.assertRaises(roman6.InvalidRomanNumeralError, roman6.from_roman, s)</code></pre>
|
||||
|
||||
<p>A third test could check that numerals appear in the correct order, from highest to lowest value. For example, <code>CL</code> is <code>150</code>, but <code>LC</code> is never valid, because the numeral for <code>50</code> can never come before the numeral for <code>100</code>.
|
||||
<p>A third test could check that numerals appear in the correct order, from highest to lowest value. For example, <code>CL</code> is <code>150</code>, but <code>LC</code> is never valid, because the numeral for <code>50</code> can never come before the numeral for <code>100</code>. This test includes a randomly chosen set of invalid antecedents: <code>I</code> before <code>M</code>, <code>V</code> before <code>X</code>, and so on.
|
||||
|
||||
<pre class=nd><code class=pp> def test_malformed_antecedents(self):
|
||||
'''from_roman should fail with malformed antecedents'''
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ import sys
|
||||
# These selectors are kept regardless of whether this script thinks they are used.
|
||||
# Most of these match nodes that are dynamically inserted or manipulated by script
|
||||
# after the page has loaded, which is why a static analysis thinks they're unused.
|
||||
SELECTOR_EXCEPTIONS = ('.w', '.b', '.str', '.kwd', '.com', '.typ', '.lit', '.pun', '.tag', '.atn', '.atv', '.dec', 'pre .u', 'pre .u span', 'li ol', 'a.hl:link', 'a.hl:visited', 'a.hl:hover', 'h2[id]:hover a.hl', 'h3[id]:hover a.hl')
|
||||
SELECTOR_EXCEPTIONS = ('.w', '.b', '.str', '.kwd', '.com', '.typ', '.lit', '.pun', '.tag', '.atn', '.atv', '.dec', 'pre .u', 'pre .u span', 'td .u', 'li ol', 'a.hl:link', 'a.hl:visited', 'a.hl:hover', 'h2[id]:hover a.hl', 'h3[id]:hover a.hl')
|
||||
|
||||
filename = sys.argv[1]
|
||||
pqd = pq(filename=filename)
|
||||
|
||||
@@ -275,7 +275,7 @@ SyntaxError: non-keyword arg after keyword arg</samp></pre>
|
||||
<pre class=nd><code class=pp>if size < 0:
|
||||
raise ValueError('number must be non-negative')</code></pre>
|
||||
|
||||
<p>The syntax for raising an exception is simple enough. Use the <code>raise</code> statement, followed by the exception name, and an optional human-readable string for debugging purposes. The syntax is reminiscent of calling a function. (In reality, exceptions are implemented as classes, and this <code>raise</code> statement is actually creating an instance of the <code>ValueError</code> class and passing the string <code>'number must be non-negative'</code> to its initialization method. But <a href=iterators.html#defining-classes>we’re getting ahead of ourselves</a><span class=u> </span><em>!</em><span class=u> </span>)
|
||||
<p>The syntax for raising an exception is simple enough. Use the <code>raise</code> statement, followed by the exception name, and an optional human-readable string for debugging purposes. The syntax is reminiscent of calling a function. (In reality, exceptions are implemented as classes, and this <code>raise</code> statement is actually creating an instance of the <code>ValueError</code> class and passing the string <code>'number must be non-negative'</code> to its initialization method. But <a href=iterators.html#defining-classes>we’re getting ahead of ourselves</a>!)
|
||||
|
||||
<blockquote class=note>
|
||||
<p><span class=u>☞</span>You don’t need to handle an exception in the function that raises it. If one function doesn’t handle it, the exception is passed to the calling function, then that function’s calling function, and so on “up the stack.” If the exception is never handled, your program will crash, Python will print a “traceback” to standard error, and that’s the end of that. Again, maybe that’s what you want; it depends on what your program does.
|
||||
@@ -306,7 +306,7 @@ except ImportError:
|
||||
|
||||
<p>By the end of this <code>try..except</code> block, you have imported <em>some</em> module and named it <var>etree</var>. Since both modules implement a common <abbr>API</abbr>, the rest of your code doesn’t need to keep checking which module got imported. And since the module that <em>did</em> get imported is always called <var>etree</var>, the rest of your code doesn’t need to be littered with <code>if</code> statements to call differently-named modules.
|
||||
|
||||
<h3 id=nameerror>Unbound Variables</h3>
|
||||
<h2 id=nameerror>Unbound Variables</h2>
|
||||
|
||||
<p>Take another look at this line of code from the <code>approximate_size()</code> function:
|
||||
|
||||
@@ -324,6 +324,30 @@ NameError: name 'x' is not defined</samp>
|
||||
|
||||
<p>You will thank Python for this one day.
|
||||
|
||||
<h2 id=case>Everything is Case-Sensitive</h2>
|
||||
|
||||
<p>All names in Python are case-sensitive: variable names, function names, class names, module names, exception names. If you can get it, set it, call it, construct it, import it, or raise it, it’s case-sensitive.
|
||||
|
||||
<pre class='nd screen'>
|
||||
<samp class=p>>>> </samp><kbd class=pp>an_integer = 1</kbd>
|
||||
<samp class=p>>>> </samp><kbd class=pp>an_integer</kbd>
|
||||
<samp class=pp>1</samp>
|
||||
<samp class=p>>>> </samp><kbd>AN_INTEGER</kbd>
|
||||
<samp class=traceback>Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
NameError: name 'AN_INTEGER' is not defined</samp>
|
||||
<samp class=p>>>> </samp><kbd>An_Integer</kbd>
|
||||
<samp class=traceback>Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
NameError: name 'An_Integer' is not defined</samp>
|
||||
<samp class=p>>>> </samp><kbd>an_inteGer</kbd>
|
||||
<samp class=traceback>Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
NameError: name 'an_inteGer' is not defined</samp>
|
||||
</pre>
|
||||
|
||||
<p>And so on.
|
||||
|
||||
<p class=a>⁂
|
||||
|
||||
<h2 id=runningscripts>Running Scripts</h2>
|
||||
|
||||
Reference in New Issue
Block a user