Updating python style guide

This commit is contained in:
apicard@google.com 2012-09-18 23:16:02 +00:00
parent 864b0dc238
commit 424ad34281

View File

@ -136,7 +136,7 @@
<H1>Google Python Style Guide</H1>
<p align="right">
Revision 2.29
Revision 2.39
</p>
<address>
@ -165,12 +165,12 @@
<TR valign="top" class="">
<TD><DIV class="toc_category"><A href="#Python_Language_Rules">Python Language Rules</A></DIV></TD>
<TD><DIV class="toc_stylepoint">
<SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#pychecker">pychecker</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Imports">Imports</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Packages">Packages</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Exceptions">Exceptions</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Global_variables">Global variables</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Nested/Local/Inner_Classes_and_Functions">Nested/Local/Inner Classes and Functions</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#List_Comprehensions">List Comprehensions</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Default_Iterators_and_Operators">Default Iterators and Operators</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Generators">Generators</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Lambda_Functions">Lambda Functions</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Default_Argument_Values">Default Argument Values</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Properties">Properties</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#True/False_evaluations">True/False evaluations</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Deprecated_Language_Features">Deprecated Language Features</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Lexical_Scoping">Lexical Scoping</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Function_and_Method_Decorators">Function and Method Decorators</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Threading">Threading</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Power_Features">Power Features</A></SPAN> </DIV></TD>
<SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#pychecker">pychecker</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Imports">Imports</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Packages">Packages</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Exceptions">Exceptions</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Global_variables">Global variables</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Nested/Local/Inner_Classes_and_Functions">Nested/Local/Inner Classes and Functions</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#List_Comprehensions">List Comprehensions</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Default_Iterators_and_Operators">Default Iterators and Operators</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Generators">Generators</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Lambda_Functions">Lambda Functions</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Conditional_Expressions">Conditional Expressions</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Default_Argument_Values">Default Argument Values</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Properties">Properties</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#True/False_evaluations">True/False evaluations</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Deprecated_Language_Features">Deprecated Language Features</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Lexical_Scoping">Lexical Scoping</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Function_and_Method_Decorators">Function and Method Decorators</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Threading">Threading</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Power_Features">Power Features</A></SPAN> </DIV></TD>
</TR>
<TR valign="top" class="">
<TD><DIV class="toc_category"><A href="#Python_Style_Rules">Python Style Rules</A></DIV></TD>
<TD><DIV class="toc_stylepoint">
<SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Semicolons">Semicolons</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Line_length">Line length</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Parentheses">Parentheses</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Indentation">Indentation</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Blank_Lines">Blank Lines</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Whitespace">Whitespace</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Shebang_Line">Shebang Line</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Comments">Comments</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Classes">Classes</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Strings">Strings</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#TODO_Comments">TODO Comments</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Imports_formatting">Imports formatting</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Statements">Statements</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Access_Control">Access Control</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Naming">Naming</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Main">Main</A></SPAN> </DIV></TD>
<SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Semicolons">Semicolons</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Line_length">Line length</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Parentheses">Parentheses</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Indentation">Indentation</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Blank_Lines">Blank Lines</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Whitespace">Whitespace</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Shebang_Line">Shebang Line</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Comments">Comments</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Classes">Classes</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Strings">Strings</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Files_and_Sockets">Files and Sockets</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#TODO_Comments">TODO Comments</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Imports_formatting">Imports formatting</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Statements">Statements</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Access_Control">Access Control</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Naming">Naming</A></SPAN> <SPAN style="padding-right: 1em; white-space:nowrap;" class=""><A href="#Main">Main</A></SPAN> </DIV></TD>
</TR>
</TABLE>
</DIV>
@ -276,7 +276,7 @@
</p>
<DIV class=""><PRE>
<span class="external"></span>def foo(a, unused_b, unused_c, d=None, e=None):
<span class="external"> </span>(d, e) = (d, e) # Silence pychecker
<span class="external"> </span>_ = d, e
<span class="external"> </span>return a
<span class="external"></span>
</PRE></DIV>
@ -406,11 +406,11 @@ from sound.effects import echo
Exceptions must follow certain conditions:
<ul>
<li>Raise exceptions like this: <code>raise MyException("Error
message")</code> or <code>raise MyException</code>. Do not
use the two-argument form (<code>raise MyException, "Error
message"</code>) or deprecated string-based exceptions
(<code>raise "Error message"</code>).</li>
<li>Raise exceptions like this: <code>raise MyException('Error
message')</code> or <code>raise MyException</code>. Do not
use the two-argument form (<code>raise MyException, 'Error
message'</code>) or deprecated string-based exceptions
(<code>raise 'Error message'</code>).</li>
<li>Modules or packages should define their own domain-specific
base exception class, which should inherit from the built-in
Exception class. The base exception for a module should be called
@ -436,6 +436,14 @@ from sound.effects import echo
<li>Use the <code>finally</code> clause to execute code whether
or not an exception is raised in the <code>try</code> block.
This is often useful for cleanup, i.e., closing a file.</li>
<li>When capturing an exception, use <code>as</code> rather than
a comma. For example:
<DIV class=""><PRE>
<span class="external"></span>try:
<span class="external"> </span>raise Error
<span class="external"></span>except Error as error:
<span class="external"> </span>pass</PRE></DIV>
</li>
</ul>
</P>
</DIV></DIV>
@ -547,15 +555,6 @@ from sound.effects import echo
permitted. Use loops instead when things get more complicated.
</P>
<DIV class=""><PRE class="badcode">No<span class="external"></span>:
<span class="external"></span>result = [(x, y) for x in range(10) for y in range(5) if x * y &gt; 10]
<span class="external"></span>return ((x, y, z)
<span class="external"></span> for x in xrange(5)
<span class="external"></span> for y in xrange(5)
<span class="external"></span> if x != y
<span class="external"></span> for z in xrange(5)
<span class="external"></span> if y != z)</PRE></DIV>
<DIV class=""><PRE>Ye<span class="external"></span>s:
<span class="external"></span>result = []
<span class="external"></span>for x in range(10):
@ -578,6 +577,15 @@ from sound.effects import echo
<span class="external"></span>eat(jelly_bean for jelly_bean in jelly_beans
<span class="external"></span> if jelly_bean.color == 'black')</PRE></DIV>
<DIV class=""><PRE class="badcode">No<span class="external"></span>:
<span class="external"></span>result = [(x, y) for x in range(10) for y in range(5) if x * y &gt; 10]
<span class="external"></span>return ((x, y, z)
<span class="external"></span> for x in xrange(5)
<span class="external"></span> for y in xrange(5)
<span class="external"></span> if x != y
<span class="external"></span> for z in xrange(5)
<span class="external"></span> if y != z)</PRE></DIV>
</DIV></DIV>
</DIV>
<DIV class="">
@ -699,6 +707,37 @@ from sound.effects import echo
</DIV></DIV>
</DIV>
<DIV class="">
<H3><A name="Conditional_Expressions" id="Conditional_Expressions">Conditional Expressions</A></H3>
<SPAN class="link_button" id="link-Conditional_Expressions__button" name="link-Conditional_Expressions__button"><A href="?showone=Conditional_Expressions#Conditional_Expressions">
link
</A></SPAN><SPAN class="showhide_button" onclick="javascript:ShowHideByName('Conditional_Expressions')" name="Conditional_Expressions__button" id="Conditional_Expressions__button"></SPAN>
<DIV style="display:inline;" class="">
Okay for one-liners.
</DIV>
<DIV class=""><DIV class="stylepoint_body" name="Conditional_Expressions__body" id="Conditional_Expressions__body" style="display: none">
<P class="">
<SPAN class="stylepoint_section">Definition: </SPAN>
Conditional expressions are mechanisms that provide a shorter syntax
for if statements. For example:
<code>x = 1 if cond else 2</code>.
</P>
<P class="">
<SPAN class="stylepoint_section">Pros: </SPAN>
Shorter and more convenient than an if statement.
</P>
<P class="">
<SPAN class="stylepoint_section">Cons: </SPAN>
May be harder to read than an if statement. The condition may be difficult
to locate if the expression is long.
</P>
<P class="">
<SPAN class="stylepoint_section">Decision: </SPAN>
Okay to use for one-liners. In other cases prefer to use a complete if
statement.
</P>
</DIV></DIV>
</DIV>
<DIV class="">
<H3><A name="Default_Argument_Values" id="Default_Argument_Values">Default Argument Values</A></H3>
<SPAN class="link_button" id="link-Default_Argument_Values__button" name="link-Default_Argument_Values__button"><A href="?showone=Default_Argument_Values#Default_Argument_Values">
link
@ -868,7 +907,7 @@ from sound.effects import echo
<SPAN class="stylepoint_section">Definition: </SPAN> Python evaluates certain values as <code>false</code>
when in a boolean context. A quick "rule of thumb" is that all
"empty" values are considered <code>false</code> so <code>0, None, [], {},
""</code> all evaluate as <code>false</code> in a boolean context.
''</code> all evaluate as <code>false</code> in a boolean context.
</P>
<P class="">
<SPAN class="stylepoint_section">Pros: </SPAN> Conditions using Python booleans are easier to read
@ -963,16 +1002,16 @@ from sound.effects import echo
We do not use any Python version which does not support
these features, so there is no reason not to use the new
styles.
<DIV class=""><PRE class="badcode">No: <span class="external"></span>words = string.split(foo, ':')
<span class="external"></span>map(lambda x: x[1], filter(lambda x: x[2] == 5, my_list))
<span class="external"></span>apply(fn, args, kwargs)</PRE></DIV>
<DIV class=""><PRE>Yes: <span class="external"></span>words = foo.split(':')
<span class="external"></span>[x[1] for x in my_list if x[2] == 5]
<span class="external"></span>fn(*args, **kwargs)</PRE></DIV>
<DIV class=""><PRE class="badcode">No: <span class="external"></span>words = string.split(foo, ':')
<span class="external"></span>map(lambda x: x[1], filter(lambda x: x[2] == 5, my_list))
<span class="external"></span>apply(fn, args, kwargs)</PRE></DIV>
</P>
</DIV></DIV>
</DIV>
@ -1395,16 +1434,16 @@ from sound.effects import echo
long_name = 2 # comment that should not be aligned
dictionary = {
"foo": 1,
"long_name": 2,
'foo': 1,
'long_name': 2,
}</PRE></DIV>
<DIV class=""><PRE class="badcode">No:
foo = 1000 # comment
long_name = 2 # comment that should not be aligned
dictionary = {
"foo" : 1,
"long_name": 2,
'foo' : 1,
'long_name': 2,
}</PRE></DIV>
@ -1469,15 +1508,9 @@ from sound.effects import echo
<p>
Every file should contain the following items, in order:
<ul>
<li>a copyright statement (for example,
<code>Copyright 2008 Google Inc.</code>)</li>
<li>a license boilerplate. Choose the appropriate boilerplate
for the license used by the project (for example, Apache 2.0, BSD,
LGPL, GPL)</li>
<li>an author line to identify the original author of the file</li>
</ul>
Every file should contain license boilerplate.
Choose the appropriate boilerplate for the license used by the project
(for example, Apache 2.0, BSD, LGPL, GPL)
</p>
</P>
<P class="">
@ -1663,17 +1696,6 @@ from sound.effects import echo
from <code>object</code>. This also applies to nested classes.
</DIV>
<DIV class=""><DIV class="stylepoint_body" name="Classes__body" id="Classes__body" style="display: none">
<DIV class=""><PRE class="badcode">No: <span class="external"></span>class SampleClass:
<span class="external"> </span>pass
<span class="external"></span>class OuterClass:
<span class="external"> </span>class InnerClass:
<span class="external"> </span>pass
<span class="external"></span>
</PRE></DIV>
<DIV class=""><PRE>Yes: <span class="external"></span>class SampleClass(object):
<span class="external"> </span>pass
@ -1688,7 +1710,16 @@ from sound.effects import echo
<span class="external"> </span>"""Explicitly inherits from another class already."""
<span class="external"></span>
</PRE></DIV>
<DIV class=""><PRE class="badcode">No: <span class="external"></span>class SampleClass:
<span class="external"> </span>pass
<span class="external"></span>class OuterClass:
<span class="external"> </span>class InnerClass:
<span class="external"> </span>pass
<span class="external"></span>
</PRE></DIV>
<p>Inheriting from <code>object</code> is needed to make properties work
properly, and it will protect your code from one particular potential
incompatibility with Python 3000. It also defines
@ -1710,12 +1741,13 @@ from sound.effects import echo
to decide between <code>+</code> and <code>%</code> though.
</DIV>
<DIV class=""><DIV class="stylepoint_body" name="Strings__body" id="Strings__body" style="display: none">
<DIV class=""><PRE class="badcode">No: <span class="external"></span>x = '%s%s' % (a, b) # use + in this case
<span class="external"></span>x = imperative + ', ' + expletive + '!'
<span class="external"></span>x = 'name: ' + name + '; score: ' + str(n)</PRE></DIV>
<DIV class=""><PRE>Yes: <span class="external"></span>x = a + b
<span class="external"></span>x = '%s, %s!' % (imperative, expletive)
<span class="external"></span>x = 'name: %s; score: %d' % (name, n)</PRE></DIV>
<DIV class=""><PRE class="badcode">No: <span class="external"></span>x = '%s%s' % (a, b) # use + in this case
<span class="external"></span>x = imperative + ', ' + expletive + '!'
<span class="external"></span>x = 'name: ' + name + '; score: ' + str(n)</PRE></DIV>
<p>
Avoid using the <code>+</code> and <code>+=</code> operators to
@ -1726,15 +1758,15 @@ from sound.effects import echo
substring to a <code>cStringIO.StringIO</code> buffer).
</p>
<DIV class=""><PRE class="badcode">No: <span class="external"></span>employee_table = '&lt;table&gt;'
<span class="external"></span>for last_name, first_name in employee_list:
<span class="external"> </span>employee_table += '&lt;tr&gt;&lt;td&gt;%s, %s&lt;/td&gt;&lt;/tr&gt;' % (last_name, first_name)
<span class="external"></span>employee_table += '&lt;/table&gt;'</PRE></DIV>
<DIV class=""><PRE>Yes: <span class="external"></span>items = ['&lt;table&gt;']
<span class="external"></span>for last_name, first_name in employee_list:
<span class="external"> </span>items.append('&lt;tr&gt;&lt;td&gt;%s, %s&lt;/td&gt;&lt;/tr&gt;' % (last_name, first_name))
<span class="external"></span>items.append('&lt;/table&gt;')
<span class="external"></span>employee_table = ''.join(items)</PRE></DIV>
<DIV class=""><PRE class="badcode">No: <span class="external"></span>employee_table = '&lt;table&gt;'
<span class="external"></span>for last_name, first_name in employee_list:
<span class="external"> </span>employee_table += '&lt;tr&gt;&lt;td&gt;%s, %s&lt;/td&gt;&lt;/tr&gt;' % (last_name, first_name)
<span class="external"></span>employee_table += '&lt;/table&gt;'</PRE></DIV>
<p>
Use <code>"""</code> for multi-line strings rather than
@ -1743,14 +1775,88 @@ from sound.effects import echo
not flow with the indentation of the rest of the program:
</p>
<DIV class=""><PRE class="badcode"> No<span class="external"></span>:
<DIV class=""><PRE>Ye<span class="external"></span>s:
<span class="external"></span>print ("This is much nicer.\n"
<span class="external"></span> "Do it this way.\n")</PRE></DIV>
<DIV class=""><PRE class="badcode"> No<span class="external"></span>:
<span class="external"></span>print """This is pretty ugly.
Don'<span class="external"></span>t do this.
"""<span class="external"></span>
</PRE></DIV>
<DIV class=""><PRE>Ye<span class="external"></span>s:
<span class="external"></span>print ("This is much nicer.\n"
<span class="external"></span> "Do it this way.\n")</PRE></DIV>
</DIV></DIV>
</DIV>
<DIV class="">
<H3><A name="Files_and_Sockets" id="Files_and_Sockets">Files and Sockets</A></H3>
<SPAN class="link_button" id="link-Files_and_Sockets__button" name="link-Files_and_Sockets__button"><A href="?showone=Files_and_Sockets#Files_and_Sockets">
link
</A></SPAN><SPAN class="showhide_button" onclick="javascript:ShowHideByName('Files_and_Sockets')" name="Files_and_Sockets__button" id="Files_and_Sockets__button"></SPAN>
<DIV style="display:inline;" class="">
Explicitly close files and sockets when done with them.
</DIV>
<DIV class=""><DIV class="stylepoint_body" name="Files_and_Sockets__body" id="Files_and_Sockets__body" style="display: none">
<p>
Leaving files, sockets or other file-like objects open unnecessarily
has many downsides, including:
<ul>
<li>They may consume limited system resources, such as file
descriptors. Code that deals with many such objects may exhaust
those resources unnecessarily if they're not returned to the
system promptly after use.</li>
<li>Holding files open may prevent other actions being performed on
them, such as moves or deletion.</li>
<li>Files and sockets that are shared throughout a program may
inadvertantly be read from or written to after logically being
closed. If they are actually closed, attempts to read or write
from them will throw exceptions, making the problem known
sooner.</li>
</ul>
</p>
<p>
Furthermore, while files and sockets are automatically closed when the
file object is destructed, tying the life-time of the file object to
the state of the file is poor practice, for several reasons:
<ul>
<li>There are no guarantees as to when the runtime will actually run
the file's destructor. Different Python implementations use
different memory management techniques, such as delayed Garbage
Collection, which may increase the object's lifetime arbitrarily
and indefinitely.</li>
<li>Unexpected references to the file may keep it around longer than
intended (e.g. in tracebacks of exceptions, inside globals,
etc).</li>
</ul>
</p>
<p>
The preferred way to manage files is using the <a HREF="http://docs.python.org/reference/compound_stmts.html#the-with-statement">
"with" statement</a>:
</p>
<DIV class=""><PRE>
<span class="external"></span>with open("hello.txt") as hello_file:
<span class="external"> </span>for line in hello_file:
<span class="external"> </span>print line</PRE></DIV>
<p>
For file-like objects that do not support the "with" statement, use
contextlib.closing():
</p>
<DIV class=""><PRE>
<span class="external"></span>import contextlib
<span class="external"></span>with contextlib.closing(urllib.urlopen("http://www.python.org/")) as front_page:
<span class="external"> </span>for line in front_page:
<span class="external"> </span>print line</PRE></DIV>
<p>
Legacy AppEngine code using Python 2.5 may enable the "with" statement
using "from __future__ import with_statement".
</p>
</DIV></DIV>
</DIV>
<DIV class="">
@ -2112,7 +2218,7 @@ Don'<span class="external"></span>t do this.
<p align="right">
Revision 2.29
Revision 2.39
</p>