Mercurial > python-for-js-programmers
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"> +>>> "a" in {"a" : 1, "b" : 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"> +>>> 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) +</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 "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 <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"> +>>> class OldStyle: # No superclass! +... pass +>>> class NewStyle(object): +... pass +>>> type(OldStyle()) +<type 'instance'> +>>> type(NewStyle()) +<class 'NewStyle'> +</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"> +>>> 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(). +</pre> +</blockquote> +<p>Overriding superclass methods is a bit odd syntactically, though:</p> +<blockquote> +<pre class="doctest-block"> +>>> class C(B): +... def foo(self): +... super(C, self).foo() +... print "In C.foo()." +>>> c = C() +>>> 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 ============