# 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.

Classes

@@ -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().
+
+

Properties

@@ -667,10 +759,9 @@

Borrowed Goods

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.

Coding Style

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 ============