mirror of
https://github.com/kennethreitz/dive-into-python3.git
synced 2026-06-05 15:00:18 +00:00
you wouldn't believe me if I told you
This commit is contained in:
@@ -29,7 +29,7 @@ th{text-align:left}
|
||||
1024: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']}
|
||||
|
||||
def approximate_size(size, a_kilobyte_is_1024_bytes=True):
|
||||
"""Convert a file size to human-readable form.
|
||||
'''Convert a file size to human-readable form.
|
||||
|
||||
Keyword arguments:
|
||||
size -- file size in bytes
|
||||
@@ -38,7 +38,7 @@ def approximate_size(size, a_kilobyte_is_1024_bytes=True):
|
||||
|
||||
Returns: string
|
||||
|
||||
"""
|
||||
'''
|
||||
if size < 0:
|
||||
raise ValueError('number must be non-negative')
|
||||
|
||||
@@ -46,11 +46,11 @@ def approximate_size(size, a_kilobyte_is_1024_bytes=True):
|
||||
for suffix in SUFFIXES[multiple]:
|
||||
size /= multiple
|
||||
if size < multiple:
|
||||
return "{0:.1f} {1}".format(size, suffix)
|
||||
return '{0:.1f} {1}'.format(size, suffix)
|
||||
|
||||
raise ValueError('number too large')
|
||||
|
||||
if __name__ == "__main__":
|
||||
if __name__ == '__main__':
|
||||
print(approximate_size(1000000000000, False))
|
||||
print(approximate_size(1000000000000))</code></pre>
|
||||
<p>Now let’s run this program on the command line. On Windows, it will look something like this:
|
||||
@@ -82,7 +82,7 @@ if __name__ == "__main__":
|
||||
<p><span>☞</span>In some languages, functions (that return a value) start with <code>function</code>, and subroutines (that do not return a value) start with <code>sub</code>. There are no subroutines in Python. Everything is a function, all functions return a value (even if it’s <code>None</code>), and all functions start with <code>def</code>.
|
||||
</blockquote>
|
||||
<p>The <code>approximate_size()</code> function takes the two arguments — <var>size</var> and <var>a_kilobyte_is_1024_bytes</var> — but neither argument specifies a datatype. In Python, variables are never explicitly typed. Python figures out what type a variable is and keeps track of it internally.
|
||||
<blockquote class="note compare java">
|
||||
<blockquote class='note compare java'>
|
||||
<p><span>☞</span>In Java and other statically-typed languages, you must specify the datatype of the function return value and each function argument. In Python, you never explicitly specify the datatype of anything. Based on what value you assign, Python keeps track of the datatype internally.
|
||||
</blockquote>
|
||||
|
||||
@@ -99,7 +99,7 @@ if __name__ == "__main__":
|
||||
<p>Now look at the bottom of the script:
|
||||
|
||||
<pre><code>
|
||||
if __name__ == "__main__":
|
||||
if __name__ == '__main__':
|
||||
<a> print(approximate_size(1000000000000, False)) <span>①</span></a>
|
||||
<a> print(approximate_size(1000000000000)) <span>②</span></a></code></pre>
|
||||
<ol>
|
||||
@@ -138,7 +138,7 @@ SyntaxError: non-keyword arg after keyword arg</samp></pre>
|
||||
<h3 id=docstrings>Documentation Strings</h3>
|
||||
<p>You can document a Python function by giving it a documentation string (<code>docstring</code> for short). In this program, the <code>approximate_size()</code> function has a <code>docstring</code>:
|
||||
<pre><code>def approximate_size(size, a_kilobyte_is_1024_bytes=True):
|
||||
"""Convert a file size to human-readable form.
|
||||
'''Convert a file size to human-readable form.
|
||||
|
||||
Keyword arguments:
|
||||
size -- file size in bytes
|
||||
@@ -147,10 +147,10 @@ SyntaxError: non-keyword arg after keyword arg</samp></pre>
|
||||
|
||||
Returns: string
|
||||
|
||||
"""</code></pre>
|
||||
'''</code></pre>
|
||||
<aside>Every function deserves a decent docstring.</aside>
|
||||
<p>Triple quotes signify a multi-line string. Everything between the start and end quotes is part of a single string, including carriage returns, leading white space, and other quote characters. You can use them anywhere, but you’ll see them most often used when defining a <code>docstring</code>.
|
||||
<blockquote class="note compare perl5">
|
||||
<blockquote class='note compare perl5'>
|
||||
<p><span>☞</span>Triple quotes are also an easy way to define a string with both single and double quotes, like <code>qq/.../</code> in Perl 5.
|
||||
</blockquote>
|
||||
<p>Everything between the triple quotes is the function’s <code>docstring</code>, which documents what the function does. A <code>docstring</code>, if it exists, must be the first thing defined in a function (that is, on the next line after the function declaration). You don’t technically need to give your function a <code>docstring</code>, but you always should. I know you’ve heard this in every programming class you’ve ever taken, but Python gives you an added incentive: the <code>docstring</code> is available at runtime as an attribute of the function.
|
||||
@@ -182,7 +182,7 @@ SyntaxError: non-keyword arg after keyword arg</samp></pre>
|
||||
<li>When you want to use functions defined in imported modules, you need to include the module name. So you can’t just say <code>approximate_size</code>; it must be <code>humansize.approximate_size</code>. If you’ve used classes in Java, this should feel vaguely familiar.
|
||||
<li>Instead of calling the function as you would expect to, you asked for one of the function’s attributes, <code>__doc__</code>.
|
||||
</ol>
|
||||
<blockquote class="note compare perl5">
|
||||
<blockquote class='note compare perl5'>
|
||||
<p><span>☞</span><code>import</code> in Python is like <code>require</code> in Perl. Once you <code>import</code> a Python module, you access its functions with <code><var>module</var>.<var>function</var></code>; once you <code>require</code> a Perl module, you access its functions with <code><var>module</var>::<var>function</var></code>.
|
||||
</blockquote>
|
||||
<h3 id=importsearchpath>The <code>import</code> Search Path</h3>
|
||||
@@ -212,7 +212,7 @@ SyntaxError: non-keyword arg after keyword arg</samp></pre>
|
||||
<ol>
|
||||
<li>Importing the <code>sys</code> module makes all of its functions and attributes available.
|
||||
<li><code>sys.path</code> is a list of directory names that constitute the current search path. (Yours will look different, depending on your operating system, what version of Python you’re running, and where it was originally installed.) Python will look through these directories (in this order) for a <code>.py</code> file whose name matches what you’re trying to import.
|
||||
<li>Actually, I lied; the truth is more complicated than that, because not all modules are stored as <code>.py</code> files. Some, like the <code>sys</code> module, are "built-in modules"; they are actually baked right into Python itself. Built-in modules behave just like regular modules, but their Python source code is not available, because they are not written in Python! (The <code>sys</code> module is written in <abbr>C</abbr>.)
|
||||
<li>Actually, I lied; the truth is more complicated than that, because not all modules are stored as <code>.py</code> files. Some, like the <code>sys</code> module, are <i>built-in modules</i>; they are actually baked right into Python itself. Built-in modules behave just like regular modules, but their Python source code is not available, because they are not written in Python! (The <code>sys</code> module is written in <abbr>C</abbr>.)
|
||||
<li>You can add a new directory to Python’s search path at runtime by adding the directory name to <code>sys.path</code>, and then Python will look in that directory as well, whenever you try to import a module. The effect lasts as long as Python is running.
|
||||
<li>By using <code>sys.path.insert(0, <var>new_path</var>)</code>, you inserted a new directory as the first item of the <code>sys.path</code> list, and therefore at the beginning of Python’s search path. This is almost always what you want. In case of naming conflicts (for example, if Python ships with version 2 of a particular library but you want to use version 3), this ensures that your modules will be found and used instead of the modules that came with Python.
|
||||
</ol>
|
||||
@@ -234,18 +234,18 @@ SyntaxError: non-keyword arg after keyword arg</samp></pre>
|
||||
<a> for suffix in SUFFIXES[multiple]: <span>⑤</span></a>
|
||||
size /= multiple
|
||||
if size < multiple:
|
||||
return "{0:.1f} {1}".format(size, suffix)
|
||||
return '{0:.1f} {1}'.format(size, suffix)
|
||||
|
||||
raise ValueError('number too large')</code></pre>
|
||||
<ol>
|
||||
<li>Code blocks are defined by their indentation. By "code block," I mean functions, <code>if</code> statements, <code>for</code> loops, <code>while</code> loops, and so forth. Indenting starts a block and unindenting ends it. There are no explicit braces, brackets, or keywords. This means that whitespace is significant, and must be consistent. In this example, the function code is indented four spaces. It doesn’t need to be four spaces, it just needs to be consistent. The first line that is not indented marks the end of the function.
|
||||
<li>Code blocks are defined by their indentation. By “code block,” I mean functions, <code>if</code> statements, <code>for</code> loops, <code>while</code> loops, and so forth. Indenting starts a block and unindenting ends it. There are no explicit braces, brackets, or keywords. This means that whitespace is significant, and must be consistent. In this example, the function code is indented four spaces. It doesn’t need to be four spaces, it just needs to be consistent. The first line that is not indented marks the end of the function.
|
||||
<li>In Python, an <code>if</code> statement is followed by a code block. If the <code>if</code> expression evaluates to true, the indented block is executed, otherwise it falls to the <code>else</code> block (if any). (Note the lack of parentheses around the expression.)
|
||||
<li>This line is inside the <code>if</code> code block. This <code>raise</code> statement will raise an exception (of type <code>ValueError</code>), but only if <code>size < 0</code>.
|
||||
<li>This is <em>not</em> the end of the function. Completely blank lines don’t count. They can make the code more readable, but they don’t count as code block delimiters. The function continues on the next line.
|
||||
<li>The <code>for</code> loop also marks the start of a code block. Code blocks can contain multiple lines, as long as they are all indented the same amount. This <code>for</code> loop has three lines of code in it. There is no other special syntax for multi-line code blocks. Just indent and get on with your life.
|
||||
</ol>
|
||||
<p>After some initial protests and several snide analogies to Fortran, you will make peace with this and start seeing its benefits. One major benefit is that all Python programs look similar, since indentation is a language requirement and not a matter of style. This makes it easier to read and understand other people’s Python code.
|
||||
<blockquote class="note compare java">
|
||||
<blockquote class='note compare java'>
|
||||
<p><span>☞</span>Python uses carriage returns to separate statements and a colon and indentation to separate code blocks. <abbr>C++</abbr> and Java use semicolons to separate statements and curly braces to separate code blocks.
|
||||
</blockquote>
|
||||
<p class=a>⁂
|
||||
@@ -254,10 +254,10 @@ SyntaxError: non-keyword arg after keyword arg</samp></pre>
|
||||
<aside>Everything in Python is an object.</aside>
|
||||
<p>Python modules are objects and have several useful attributes. You can use this to easily test your modules as you write them, by including a special block of code that executes when you run the Python file on the command line. Take the last few lines of <code>humansize.py</code>:
|
||||
<pre><code>
|
||||
if __name__ == "__main__":
|
||||
if __name__ == '__main__':
|
||||
print(approximate_size(1000000000000, False))
|
||||
print(approximate_size(1000000000000))</code></pre>
|
||||
<blockquote class="note compare clang">
|
||||
<blockquote class='note compare clang'>
|
||||
<p><span>☞</span>Like <abbr>C</abbr>, Python uses <code>==</code> for comparison and <code>=</code> for assignment. Unlike <abbr>C</abbr>, Python does not support in-line assignment, so there’s no chance of accidentally assigning the value you thought you were comparing.
|
||||
</blockquote>
|
||||
<p>So what makes this <code>if</code> statement special? Well, modules are objects, and all modules have a built-in attribute <code>__name__</code>. A module’s <code>__name__</code> depends on how you’re using the module. If you <code>import</code> the module, then <code>__name__</code> is the module’s filename, without a directory path or file extension.
|
||||
@@ -280,7 +280,7 @@ if __name__ == "__main__":
|
||||
<li><a href=http://www.python.org/dev/peps/pep-0008/>PEP 8: Style Guide for Python Code</a> discusses good indentation style.
|
||||
<li><a href=http://docs.python.org/3.0/reference/><cite>Python Reference Manual</cite></a> explains what it means to say that <a href=http://docs.python.org/3.0/reference/datamodel.html#objects-values-and-types>everything in Python is an object</a>, because some people are <a href=http://www.douglasadams.com/dna/pedants.html>pedants</a> and like to discuss that sort of thing at great length.
|
||||
</ul>
|
||||
<p class=nav><a rel=prev class=todo><span>☜</span></a> <a rel=next href=native-datatypes.html title="onward to “Native Datatypes”"><span>☞</span></a>
|
||||
<p class=v><a rel=prev class=todo><span>☜</span></a> <a rel=next href=native-datatypes.html title='onward to “Native Datatypes”'><span>☞</span></a>
|
||||
<p class=c>© 2001–9 <a href=about.html>Mark Pilgrim</a>
|
||||
<script src=j/jquery.js></script>
|
||||
<script src=j/dip3.js></script>
|
||||
|
||||
Reference in New Issue
Block a user