changeset 36:f1e8805a9666

Added more docs on classes, made docs on borrowed goods more accurate.
author Atul Varma <varmaa@toolness.com>
date Fri, 06 Jun 2008 12:00:21 -0700
parents 3179304015bf
children dea2264f872c
files PythonForJsProgrammers.html PythonForJsProgrammers.txt
diffstat 2 files changed, 194 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/PythonForJsProgrammers.html	Fri Jun 06 06:32:56 2008 -0700
+++ b/PythonForJsProgrammers.html	Fri Jun 06 12:00:21 2008 -0700
@@ -552,9 +552,20 @@
 AttributeError: 'dict' object has no attribute 'foo'
 </pre>
 </blockquote>
+<p>Since Python doesn't have a notion of <tt class="docutils literal"><span class="pre">undefined</span></tt>, the easiest way
+to check whether a dictionary has a key is through the <tt class="docutils literal"><span class="pre">in</span></tt> keyword:</p>
+<blockquote>
+<pre class="doctest-block">
+&gt;&gt;&gt; &quot;a&quot; in {&quot;a&quot; : 1, &quot;b&quot; : 2}
+True
+</pre>
+</blockquote>
 <p>Dictionaries generally aren't used to create arbitrary objects like
 they are in Javascript; they don't have prototypes, nor do they have
-meta-methods.  Instead, classes are used to do that sort of thing.</p>
+meta-methods.  Instead, classes are used to do that sort of thing.  In
+some ways, this is unfortunate, since the simplicity of conflating
+objects with dictionaries, as JavaScript and Lua do, makes
+understanding and using them easier.</p>
 </div>
 <div class="section">
 <h1><a id="classes" name="classes">Classes</a></h1>
@@ -589,9 +600,6 @@
 2
 </pre>
 </blockquote>
-<p>Classes in Python get inheritance for free, but because they're not
-really prototype-based, it's not easy to dynamically add or remove
-methods to existing objects on-the-fly.</p>
 <p>An object's methods are also bound to the object itself once it's
 created; that is, the <tt class="docutils literal"><span class="pre">self</span></tt> parameter that's passed to them is
 always the same, unlike the <tt class="docutils literal"><span class="pre">this</span></tt> parameter in JavaScript which
@@ -605,6 +613,90 @@
 6
 </pre>
 </blockquote>
+<p>Do make sure that you always remember to include <tt class="docutils literal"><span class="pre">self</span></tt> as an
+explicit parameter in class methods, though; failure to do so can lead
+to some strange results:</p>
+<blockquote>
+<pre class="doctest-block">
+&gt;&gt;&gt; class Foo(object):
+...     def bar(x):
+...         return x + 1
+&gt;&gt;&gt; f = Foo()
+&gt;&gt;&gt; f.bar()
+Traceback (most recent call last):
+...
+TypeError: unsupported operand type(s) for +: 'Foo' and 'int'
+&gt;&gt;&gt; f.bar(1)
+Traceback (most recent call last):
+...
+TypeError: bar() takes exactly 1 argument (2 given)
+</pre>
+</blockquote>
+<p>As you can see, classes in Python aren't particularly elegant; it's
+hard to understand exactly <cite>why</cite> things work the way they do unless
+you understand how classes are implemented &quot;under the hood&quot;, which is
+unfortunate. There are also some bumps in the history of Python's
+class mechanism: until version 2.2, Python's built-in types weren't
+part of the class heirarchy, and there was no root <tt class="docutils literal"><span class="pre">object</span></tt> class;
+these kinds of classes were known as <cite>old-style classes</cite>, and are
+being mentioned here solely because you may run across them when
+reading old code. They don't support a lot of the things that
+new-style classes do, and should be avoided if at all possible. You
+can tell that an object is an instance of an old-style or new-style
+class by using the <tt class="docutils literal"><span class="pre">type</span></tt> built-in function:</p>
+<blockquote>
+<pre class="doctest-block">
+&gt;&gt;&gt; class OldStyle:            # No superclass!
+...     pass
+&gt;&gt;&gt; class NewStyle(object):
+...     pass
+&gt;&gt;&gt; type(OldStyle())
+&lt;type 'instance'&gt;
+&gt;&gt;&gt; type(NewStyle())
+&lt;class 'NewStyle'&gt;
+</pre>
+</blockquote>
+<p>A number of the class mechanisms outlined in this tutorial don't work
+with old-style classes.  Fortunately, as with the string/unicode
+schism, this confusion will be resolved in Python 3000, which abandons
+old-style classes to their well-deserved fate.</p>
+<p>Because classes in Python aren't really prototype-based, it's not easy
+to dynamically add or remove methods to existing objects
+on-the-fly--though some will probably tell you that doing such a thing
+isn't a good idea in the first place.  In practice, all of Python's
+built-in types come with a well-designed retinue of methods, so
+there's little need for one to want to add methods to them on-the-fly,
+which certainly <a class="reference" href="http://javascript.crockford.com/remedial.html">isn't the case in JavaScript</a>.</p>
+<p>Another advantage of Python's class mechanism is that you get
+inheritance for free:</p>
+<blockquote>
+<pre class="doctest-block">
+&gt;&gt;&gt; class A(object):
+...     def foo(self):
+...         print &quot;In A.foo().&quot;
+&gt;&gt;&gt; class B(A):
+...     def bar(self):
+...         print &quot;In B.bar().&quot;
+&gt;&gt;&gt; b = B()
+&gt;&gt;&gt; b.foo()
+In A.foo().
+&gt;&gt;&gt; b.bar()
+In B.bar().
+</pre>
+</blockquote>
+<p>Overriding superclass methods is a bit odd syntactically, though:</p>
+<blockquote>
+<pre class="doctest-block">
+&gt;&gt;&gt; class C(B):
+...     def foo(self):
+...         super(C, self).foo()
+...         print &quot;In C.foo().&quot;
+&gt;&gt;&gt; c = C()
+&gt;&gt;&gt; c.foo()
+In A.foo().
+In C.foo().
+</pre>
+</blockquote>
 </div>
 <div class="section">
 <h1><a id="properties" name="properties">Properties</a></h1>
@@ -667,10 +759,9 @@
 <h1><a id="borrowed-goods" name="borrowed-goods">Borrowed Goods</a></h1>
 <p>As mentioned at the beginning of this document, some of JavaScript's
 latest features have been borrowed directly from Python.</p>
-<p><a class="reference" href="http://www.python.org/dev/peps/pep-0255/">Generators</a>, <a class="reference" href="http://docs.python.org/lib/typeiter.html">iterators</a>, and <a class="reference" href="http://www.python.org/dev/peps/pep-0289/">generator expressions</a> work almost
-identically to their JavaScript 1.7 counterparts.  And while I'm not
-sure if Python was the inspiration for them, JavaScript 1.7's array
-comprehensions are almost identical to Python's <a class="reference" href="http://docs.python.org/tut/node7.html#SECTION007140000000000000000">list comprehensions</a>.</p>
+<p>In particular, <a class="reference" href="http://www.python.org/dev/peps/pep-0255/">generators</a>, <a class="reference" href="http://docs.python.org/lib/typeiter.html">iterators</a>, <a class="reference" href="http://www.python.org/dev/peps/pep-0289/">generator expressions</a>,
+and <a class="reference" href="http://docs.python.org/tut/node7.html#SECTION007140000000000000000">list comprehensions</a> work almost identically to their JavaScript
+1.7 <a class="reference" href="http://wiki.ecmascript.org/doku.php?id=proposals:iterators_and_generators">counterparts</a>.</p>
 </div>
 <div class="section">
 <h1><a id="coding-style" name="coding-style">Coding Style</a></h1>
--- a/PythonForJsProgrammers.txt	Fri Jun 06 06:32:56 2008 -0700
+++ b/PythonForJsProgrammers.txt	Fri Jun 06 12:00:21 2008 -0700
@@ -499,9 +499,18 @@
     ...
     AttributeError: 'dict' object has no attribute 'foo'
 
+Since Python doesn't have a notion of ``undefined``, the easiest way
+to check whether a dictionary has a key is through the ``in`` keyword:
+
+    >>> "a" in {"a" : 1, "b" : 2}
+    True
+
 Dictionaries generally aren't used to create arbitrary objects like
 they are in Javascript; they don't have prototypes, nor do they have
-meta-methods.  Instead, classes are used to do that sort of thing.
+meta-methods.  Instead, classes are used to do that sort of thing.  In
+some ways, this is unfortunate, since the simplicity of conflating
+objects with dictionaries, as JavaScript and Lua do, makes
+understanding and using them easier.
 
 Classes
 =======
@@ -531,10 +540,6 @@
     >>> f.doThing()
     2
 
-Classes in Python get inheritance for free, but because they're not
-really prototype-based, it's not easy to dynamically add or remove
-methods to existing objects on-the-fly.
-
 An object's methods are also bound to the object itself once it's
 created; that is, the ``self`` parameter that's passed to them is
 always the same, unlike the ``this`` parameter in JavaScript which
@@ -546,6 +551,86 @@
     >>> doThing()
     6
 
+Do make sure that you always remember to include ``self`` as an
+explicit parameter in class methods, though; failure to do so can lead
+to some strange results:
+
+    >>> class Foo(object):
+    ...     def bar(x):
+    ...         return x + 1
+    >>> f = Foo()
+    >>> f.bar()
+    Traceback (most recent call last):
+    ...
+    TypeError: unsupported operand type(s) for +: 'Foo' and 'int'
+    >>> f.bar(1)
+    Traceback (most recent call last):
+    ...
+    TypeError: bar() takes exactly 1 argument (2 given)
+
+As you can see, classes in Python aren't particularly elegant; it's
+hard to understand exactly `why` things work the way they do unless
+you understand how classes are implemented "under the hood", which is
+unfortunate. There are also some bumps in the history of Python's
+class mechanism: until version 2.2, Python's built-in types weren't
+part of the class heirarchy, and there was no root ``object`` class;
+these kinds of classes were known as `old-style classes`, and are
+being mentioned here solely because you may run across them when
+reading old code. They don't support a lot of the things that
+new-style classes do, and should be avoided if at all possible. You
+can tell that an object is an instance of an old-style or new-style
+class by using the ``type`` built-in function:
+
+    >>> class OldStyle:            # No superclass!
+    ...     pass
+    >>> class NewStyle(object):
+    ...     pass
+    >>> type(OldStyle())
+    <type 'instance'>
+    >>> type(NewStyle())
+    <class 'NewStyle'>
+
+A number of the class mechanisms outlined in this tutorial don't work
+with old-style classes.  Fortunately, as with the string/unicode
+schism, this confusion will be resolved in Python 3000, which abandons
+old-style classes to their well-deserved fate.
+
+Because classes in Python aren't really prototype-based, it's not easy
+to dynamically add or remove methods to existing objects
+on-the-fly--though some will probably tell you that doing such a thing
+isn't a good idea in the first place.  In practice, all of Python's
+built-in types come with a well-designed retinue of methods, so
+there's little need for one to want to add methods to them on-the-fly,
+which certainly `isn't the case in JavaScript`_.
+
+Another advantage of Python's class mechanism is that you get
+inheritance for free:
+
+    >>> class A(object):
+    ...     def foo(self):
+    ...         print "In A.foo()."
+    >>> class B(A):
+    ...     def bar(self):
+    ...         print "In B.bar()."
+    >>> b = B()
+    >>> b.foo()
+    In A.foo().
+    >>> b.bar()
+    In B.bar().
+
+Overriding superclass methods is a bit odd syntactically, though:
+
+    >>> class C(B):
+    ...     def foo(self):
+    ...         super(C, self).foo()
+    ...         print "In C.foo()."
+    >>> c = C()
+    >>> c.foo()
+    In A.foo().
+    In C.foo().
+
+.. _`isn't the case in JavaScript`: http://javascript.crockford.com/remedial.html
+
 Properties
 ==========
 
@@ -607,15 +692,15 @@
 As mentioned at the beginning of this document, some of JavaScript's
 latest features have been borrowed directly from Python.
 
-`Generators`_, `iterators`_, and `generator expressions`_ work almost
-identically to their JavaScript 1.7 counterparts.  And while I'm not
-sure if Python was the inspiration for them, JavaScript 1.7's array
-comprehensions are almost identical to Python's `list comprehensions`_.
+In particular, `generators`_, `iterators`_, `generator expressions`_,
+and `list comprehensions`_ work almost identically to their JavaScript
+1.7 `counterparts`_.
 
-.. _`Generators`: http://www.python.org/dev/peps/pep-0255/
+.. _`generators`: http://www.python.org/dev/peps/pep-0255/
 .. _`iterators`: http://docs.python.org/lib/typeiter.html
 .. _`generator expressions`: http://www.python.org/dev/peps/pep-0289/
 .. _`list comprehensions`: http://docs.python.org/tut/node7.html#SECTION007140000000000000000
+.. _`counterparts`: http://wiki.ecmascript.org/doku.php?id=proposals:iterators_and_generators
 
 Coding Style
 ============