# HG changeset patch # User Atul Varma # Date 1212783322 25200 # Node ID 741b0e6cd9acff4891bcd9ce2f596aded622ea04 # Parent b3fdf83125c272431649adb6e4308cfa37db1272 Moved some sections around. diff -r b3fdf83125c2 -r 741b0e6cd9ac PythonForJsProgrammers.html --- a/PythonForJsProgrammers.html Fri Jun 06 12:54:07 2008 -0700 +++ b/PythonForJsProgrammers.html Fri Jun 06 13:15:22 2008 -0700 @@ -52,10 +52,10 @@ something it should already be able to infer from the use of whitespace?

This is actually a violation of the Don't Repeat Yourself (DRY) -principle popularized by Andy Hunt and Dave Thomas. Because unneeded -extra work is required when moving from a single-line clause to a +principle popularized by Andy Hunt and Dave Thomas. Because extra +work is required when moving from a single-line clause to a multiple-line clause, it's a constant source of errors in C-like -languages, and many stylistic rules and arguments have been spawned as +languages, and stylistic rules and arguments have been spawned as a result of this mistake in language design.

Python is one of the few languages that takes the simpler and more humane approach: whitespace has a consistent semantic meaning to the @@ -110,7 +110,8 @@

If there's a function you're interested in learning more about, you can look at the built-in documentation metadata associated with the object--known as the docstring--by querying the object's __doc__ -attribute:

+attribute. For instance, here's how to get help on the string +object's join() method:

 >>> print "a string".join.__doc__
@@ -120,8 +121,7 @@
 sequence.  The separator between elements is S.
 
-

This makes it very easy and fun to explore the language and its -environs.

+

This makes it easy and fun to explore the language and its environs.

Batteries Included

@@ -152,59 +152,28 @@

Strings

-

Strings are, unfortunately, the bane of Python programming. Unlike -JavaScript, in which every string is unicode, strings in Python are -really more like immutable arrays of bytes. Unicode strings are an -entirely different type, and unicode literals must be prepended with a -u, like so:

+

Strings in Python work a lot like they do in JavaScript, but with some +added benefits.

+

Strings--or any sequence-like object in Python, for that matter--can +be indexed by character like they can in JavaScript, with the addition +that negative indexes may be used to denote items from the end of the +sequence:

->>> u"I am a unicode string."
-u'I am a unicode string.'
->>> "I am a non-unicode string."
-'I am a non-unicode string.'
-
-
-

The non-intuitiveness of this is due to historical reasons: Python is -an older language than JavaScript and dates back to 1991, so the -language didn't originally support unicode. When support was added, -it was added in a way that didn't break backwards compatibility. This -situation will be resolved in Python 3000, the first version of -Python to break backwards compatibility with previous versions.

-

A string with a character encoding may be converted to a unicode -object through the decode() method, like so:

-
-
->>> "Here is an ellipsis: \xe2\x80\xa6".decode("utf-8")
-u'Here is an ellipsis: \u2026'
+>>> "Hello"[-1]
+'o'
 
-

Conversely, you can convert a unicode object into a string via the -encode() method:

-
-
->>> u"Here is an ellipsis: \u2026".encode("utf-8")
-'Here is an ellipsis: \xe2\x80\xa6'
-
-
-

An exception will be raised if there are characters that aren't -supported by the encoding you specify, though:

+

Any indexable item can generally also be sliced; this is similar to +String.slice in JavaScript, only built-in to the language:

->>> u"hello\u2026".encode("ascii")
-Traceback (most recent call last):
-...
-UnicodeEncodeError: 'ascii' codec can't encode character u'\u2026' in position 5: ordinal not in range(128)
-
-
-

As such, it's a good idea to optionally specify an algorithm to deal -with characters that aren't supported by the encoding:

-
-
->>> u"hello\u2026".encode("ascii", "ignore")
-'hello'
->>> u"hello\u2026".encode("ascii", "xmlcharrefreplace")
-'hello…'
+>>> "hello"[2:4]     # Just like "hello".slice(2,4) in JS
+'ll'
+>>> "hello"[2:]      # Just like "hello".slice(2) in JS
+'llo'
+>>> "hello"[:4]      # Just like "hello".slice(0,4) in JS
+'hell'
 

It's also easy to format strings in Python. If you're familiar with @@ -355,7 +324,7 @@ forth.

-

Global Variables

+

Variables

Python, like JavaScript, is lexically scoped when it comes to reading variables.

However, Python's scoping rules for assignment to undefined variables @@ -385,41 +354,6 @@ explicitly told otherwise.

-

Closures

-

Function closures are available in Python:

-
-
->>> def myfunc():
-...     a = 1
-...     def wrapped():
-...         return a
-...     return wrapped
->>> myfunc()()
-1
-
-
-

Unlike Javascript, however, the variable bindings in the closure are -"read-only":

-
-
->>> def myfunc():
-...     a = 1
-...     def wrapped():
-...         a += 1                 # Doesn't work!
-...         return a
-...     return wrapped
->>> myfunc()()
-Traceback (most recent call last):
-...
-UnboundLocalError: local variable 'a' referenced before assignment
-
-
-

This means that closures can't be used to access private variables -like they can in JavaScript; instead, everything is visible, and -implementation-specific variables are conventionally preceded with one -or two underscores.

-
-

Sequences

Lists are a lot like JavaScript arrays:

@@ -475,6 +409,28 @@ [1, 3]
+

It's also possible to index and slice lists and tuples, just like you +can with strings:

+
+
+>>> ["hello", "there", "dude"][-1]
+'dude'
+
+
+>>> [1, 2, 3][1:2]
+[2]
+
+
+

In fact, if the datatype is mutable like lists are, you can even +assign to slices:

+
+
+>>> a = [1, 2, 3, 4]
+>>> a[1:3] = [5]
+>>> a
+[1, 5, 4]
+
+

Control Flow

@@ -513,41 +469,6 @@
-

Indexing and Slicing

-

Any item that is a sequence can be indexed as expected, but unlike -Javascript, negative indexes may be used to denote items from the end -of the sequence:

-
-
->>> ["hello", "there", "dude"][-1]
-'dude'
-
-
-

Any indexable item can generally also be sliced; this is similar to -String.slice in JavaScript, only built-in to the language:

-
-
->>> "hello"[2:4]     # Just like "hello".slice(2,4) in JS
-'ll'
->>> "hello"[2:]      # Just like "hello".slice(2) in JS
-'llo'
->>> "hello"[:4]      # Just like "hello".slice(0,4) in JS
-'hell'
->>> [1, 2, 3][1:2]   # Works on lists, too!
-[2]
-
-
-

If the datatype is mutable, you can even assign to slices:

-
-
->>> a = [1, 2, 3, 4]
->>> a[1:3] = [5]
->>> a
-[1, 5, 4]
-
-
-
-

Dictionaries

Dictionaries are a bit like Object literals in JavaScript:

@@ -658,31 +579,7 @@

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 means it's old-style.
-...     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.

+unfortunate.

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 @@ -779,6 +676,41 @@

+

Closures

+

Function closures are available in Python:

+
+
+>>> def myfunc():
+...     a = 1
+...     def wrapped():
+...         return a
+...     return wrapped
+>>> myfunc()()
+1
+
+
+

Unlike Javascript, however, the variable bindings in the closure are +"read-only":

+
+
+>>> def myfunc():
+...     a = 1
+...     def wrapped():
+...         a += 1                 # Doesn't work!
+...         return a
+...     return wrapped
+>>> myfunc()()
+Traceback (most recent call last):
+...
+UnboundLocalError: local variable 'a' referenced before assignment
+
+
+

This means that closures can't be used to access private variables +like they can in JavaScript; instead, everything is visible, and +implementation-specific variables are conventionally preceded with one +or two underscores.

+
+

Borrowed Goods

As mentioned at the beginning of this document, some of JavaScript's latest features have been borrowed directly from Python.

@@ -787,6 +719,99 @@ 1.7 counterparts.

+

Caveats

+

As with any language, there's a few wrinkles in Python's design and +history that any newcomer should be aware of. I'll try to outline the +most important ones below.

+
+

Unicode

+

Sometimes, strings are the bane of Python programming. Unlike +JavaScript, in which every string is unicode, strings in Python are +really more like immutable arrays of bytes. Unicode strings are an +entirely different type, and unicode literals must be prepended with a +u, like so:

+
+
+>>> u"I am a unicode string."
+u'I am a unicode string.'
+>>> "I am a non-unicode string."
+'I am a non-unicode string.'
+
+
+

The non-intuitiveness of this is due to historical reasons: Python is +an older language than JavaScript and dates back to 1991, so the +language didn't originally support unicode. When support was added, +it was added in a way that didn't break backwards compatibility. This +situation will be resolved in Python 3000, the first version of +Python to break backwards compatibility with previous versions.

+

A string with a character encoding may be converted to a unicode +object through the decode() method, like so:

+
+
+>>> "Here is an ellipsis: \xe2\x80\xa6".decode("utf-8")
+u'Here is an ellipsis: \u2026'
+
+
+

Conversely, you can convert a unicode object into a string via the +encode() method:

+
+
+>>> u"Here is an ellipsis: \u2026".encode("utf-8")
+'Here is an ellipsis: \xe2\x80\xa6'
+
+
+

An exception will be raised if there are characters that aren't +supported by the encoding you specify, though:

+
+
+>>> u"hello\u2026".encode("ascii")
+Traceback (most recent call last):
+...
+UnicodeEncodeError: 'ascii' codec can't encode character u'\u2026' in position 5: ordinal not in range(128)
+
+
+

As such, it's a good idea to optionally specify an algorithm to deal +with characters that aren't supported by the encoding:

+
+
+>>> u"hello\u2026".encode("ascii", "ignore")
+'hello'
+>>> u"hello\u2026".encode("ascii", "xmlcharrefreplace")
+'hello&#8230;'
+
+
+
+
+

Old-Style Classes

+

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 means it's old-style.
+...     pass
+>>> class NewStyle(object):
+...     pass
+>>> type(OldStyle())
+<type 'instance'>
+>>> type(NewStyle())
+<class 'NewStyle'>
+
+
+

A number of the class mechanisms outlined in this tutorial, such as +the property() and super() built-in functions, 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.

+
+
+

Coding Style

Python has a coding convention that's generally been embraced throughout the community; almost all libraries use it. It's contained diff -r b3fdf83125c2 -r 741b0e6cd9ac PythonForJsProgrammers.txt --- a/PythonForJsProgrammers.txt Fri Jun 06 12:54:07 2008 -0700 +++ b/PythonForJsProgrammers.txt Fri Jun 06 13:15:22 2008 -0700 @@ -154,51 +154,26 @@ Strings ======= -Strings are, unfortunately, the bane of Python programming. Unlike -JavaScript, in which every string is unicode, strings in Python are -really more like immutable arrays of bytes. Unicode strings are an -entirely different type, and unicode literals must be prepended with a -``u``, like so: +Strings in Python work a lot like they do in JavaScript, but with some +added benefits. - >>> u"I am a unicode string." - u'I am a unicode string.' - >>> "I am a non-unicode string." - 'I am a non-unicode string.' - -The non-intuitiveness of this is due to historical reasons: Python is -an older language than JavaScript and dates back to 1991, so the -language didn't originally support unicode. When support was added, -it was added in a way that didn't break backwards compatibility. This -situation will be resolved in `Python 3000`_, the first version of -Python to break backwards compatibility with previous versions. - -A string with a character encoding may be converted to a ``unicode`` -object through the ``decode()`` method, like so: +Strings--or any sequence-like object in Python, for that matter--can +be indexed by character like they can in JavaScript, with the addition +that negative indexes may be used to denote items from the end of the +sequence: - >>> "Here is an ellipsis: \xe2\x80\xa6".decode("utf-8") - u'Here is an ellipsis: \u2026' - -Conversely, you can convert a ``unicode`` object into a string via the -``encode()`` method: + >>> "Hello"[-1] + 'o' - >>> u"Here is an ellipsis: \u2026".encode("utf-8") - 'Here is an ellipsis: \xe2\x80\xa6' - -An exception will be raised if there are characters that aren't -supported by the encoding you specify, though: +Any indexable item can generally also be sliced; this is similar to +``String.slice`` in JavaScript, only built-in to the language: - >>> u"hello\u2026".encode("ascii") - Traceback (most recent call last): - ... - UnicodeEncodeError: 'ascii' codec can't encode character u'\u2026' in position 5: ordinal not in range(128) - -As such, it's a good idea to optionally specify an algorithm to deal -with characters that aren't supported by the encoding: - - >>> u"hello\u2026".encode("ascii", "ignore") - 'hello' - >>> u"hello\u2026".encode("ascii", "xmlcharrefreplace") - 'hello…' + >>> "hello"[2:4] # Just like "hello".slice(2,4) in JS + 'll' + >>> "hello"[2:] # Just like "hello".slice(2) in JS + 'llo' + >>> "hello"[:4] # Just like "hello".slice(0,4) in JS + 'hell' It's also easy to format strings in Python. If you're familiar with C's ``sprintf()`` function, Python's string interpolation operator, @@ -210,7 +185,6 @@ You can find out more in the `String Formatting Operations`_ section of the Python Library Reference. -.. _`Python 3000`: http://www.python.org/dev/peps/pep-3000/ .. _`String Formatting Operations`: http://docs.python.org/lib/typesseq-strings.html Expressions @@ -332,8 +306,8 @@ .. _`arbitrary argument lists`: http://docs.python.org/tut/node6.html#SECTION006730000000000000000 -Global Variables -================ +Variables +========= Python, like JavaScript, is lexically scoped when it comes to reading variables. @@ -362,38 +336,6 @@ interpreter to assume that all new assignments are local unless explicitly told otherwise. -Closures -======== - -Function closures are available in Python: - - >>> def myfunc(): - ... a = 1 - ... def wrapped(): - ... return a - ... return wrapped - >>> myfunc()() - 1 - -Unlike Javascript, however, the variable bindings in the closure are -"read-only": - - >>> def myfunc(): - ... a = 1 - ... def wrapped(): - ... a += 1 # Doesn't work! - ... return a - ... return wrapped - >>> myfunc()() - Traceback (most recent call last): - ... - UnboundLocalError: local variable 'a' referenced before assignment - -This means that closures can't be used to access private variables -like they can in JavaScript; instead, everything is visible, and -implementation-specific variables are conventionally preceded with one -or two underscores. - Sequences ========= @@ -439,6 +381,23 @@ >>> a [1, 3] +It's also possible to index and slice lists and tuples, just like you +can with strings: + + >>> ["hello", "there", "dude"][-1] + 'dude' + + >>> [1, 2, 3][1:2] + [2] + +In fact, if the datatype is mutable like lists are, you can even +`assign` to slices: + + >>> a = [1, 2, 3, 4] + >>> a[1:3] = [5] + >>> a + [1, 5, 4] + Control Flow ============ @@ -470,35 +429,6 @@ 1 2 -Indexing and Slicing -==================== - -Any item that is a sequence can be indexed as expected, but unlike -Javascript, negative indexes may be used to denote items from the end -of the sequence: - - >>> ["hello", "there", "dude"][-1] - 'dude' - -Any indexable item can generally also be sliced; this is similar to -``String.slice`` in JavaScript, only built-in to the language: - - >>> "hello"[2:4] # Just like "hello".slice(2,4) in JS - 'll' - >>> "hello"[2:] # Just like "hello".slice(2) in JS - 'llo' - >>> "hello"[:4] # Just like "hello".slice(0,4) in JS - 'hell' - >>> [1, 2, 3][1:2] # Works on lists, too! - [2] - -If the datatype is mutable, you can even assign to slices: - - >>> a = [1, 2, 3, 4] - >>> a[1:3] = [5] - >>> a - [1, 5, 4] - Dictionaries ============ @@ -594,29 +524,7 @@ 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 means it's old-style. - ... 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. +unfortunate. Because classes in Python aren't really prototype-based, it's not easy to dynamically add or remove methods to existing objects @@ -709,6 +617,38 @@ .. _`built-in ones`: http://docs.python.org/lib/module-exceptions.html +Closures +======== + +Function closures are available in Python: + + >>> def myfunc(): + ... a = 1 + ... def wrapped(): + ... return a + ... return wrapped + >>> myfunc()() + 1 + +Unlike Javascript, however, the variable bindings in the closure are +"read-only": + + >>> def myfunc(): + ... a = 1 + ... def wrapped(): + ... a += 1 # Doesn't work! + ... return a + ... return wrapped + >>> myfunc()() + Traceback (most recent call last): + ... + UnboundLocalError: local variable 'a' referenced before assignment + +This means that closures can't be used to access private variables +like they can in JavaScript; instead, everything is visible, and +implementation-specific variables are conventionally preceded with one +or two underscores. + Borrowed Goods ============== @@ -725,6 +665,92 @@ .. _`list comprehensions`: http://docs.python.org/tut/node7.html#SECTION007140000000000000000 .. _`counterparts`: http://wiki.ecmascript.org/doku.php?id=proposals:iterators_and_generators +Caveats +======= + +As with any language, there's a few wrinkles in Python's design and +history that any newcomer should be aware of. I'll try to outline the +most important ones below. + +Unicode +------- + +Sometimes, strings are the bane of Python programming. Unlike +JavaScript, in which every string is unicode, strings in Python are +really more like immutable arrays of bytes. Unicode strings are an +entirely different type, and unicode literals must be prepended with a +``u``, like so: + + >>> u"I am a unicode string." + u'I am a unicode string.' + >>> "I am a non-unicode string." + 'I am a non-unicode string.' + +The non-intuitiveness of this is due to historical reasons: Python is +an older language than JavaScript and dates back to 1991, so the +language didn't originally support unicode. When support was added, +it was added in a way that didn't break backwards compatibility. This +situation will be resolved in `Python 3000`_, the first version of +Python to break backwards compatibility with previous versions. + +A string with a character encoding may be converted to a ``unicode`` +object through the ``decode()`` method, like so: + + >>> "Here is an ellipsis: \xe2\x80\xa6".decode("utf-8") + u'Here is an ellipsis: \u2026' + +Conversely, you can convert a ``unicode`` object into a string via the +``encode()`` method: + + >>> u"Here is an ellipsis: \u2026".encode("utf-8") + 'Here is an ellipsis: \xe2\x80\xa6' + +An exception will be raised if there are characters that aren't +supported by the encoding you specify, though: + + >>> u"hello\u2026".encode("ascii") + Traceback (most recent call last): + ... + UnicodeEncodeError: 'ascii' codec can't encode character u'\u2026' in position 5: ordinal not in range(128) + +As such, it's a good idea to optionally specify an algorithm to deal +with characters that aren't supported by the encoding: + + >>> u"hello\u2026".encode("ascii", "ignore") + 'hello' + >>> u"hello\u2026".encode("ascii", "xmlcharrefreplace") + 'hello…' + +.. _`Python 3000`: http://www.python.org/dev/peps/pep-3000/ + +Old-Style Classes +----------------- + +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 means it's old-style. + ... pass + >>> class NewStyle(object): + ... pass + >>> type(OldStyle()) + + >>> type(NewStyle()) + + +A number of the class mechanisms outlined in this tutorial, such as +the ``property()`` and ``super()`` built-in functions, 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. + Coding Style ============