# HG changeset patch
# User Atul Varma
# Date 1212778821 25200
# Node ID f1e8805a9666cc289b67e5866a8a3f9937973661
# Parent 3179304015bfa4505e7ccee4514e86d1a1c2d86e
Added more docs on classes, made docs on borrowed goods more accurate.
diff -r 3179304015bf -r f1e8805a9666 PythonForJsProgrammers.html
--- 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'
+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.
@@ -589,9 +600,6 @@
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
@@ -605,6 +613,90 @@
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().
+
+
@@ -667,10 +759,9 @@
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.
diff -r 3179304015bf -r f1e8805a9666 PythonForJsProgrammers.txt
--- 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(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
============