Return to Home Page
      Blog     Consulting     Seminars     Calendar     Books     CD-ROMS     Newsletter     About     FAQ      Search
 

Could you say just a little bit more about lists and dictionaries, with a couple more examples of how to use them?

f  e  x


I would talk a bit more about method overloading. Since
Python is dynamically typed and late binding, it can't
validate function invocations by function prototype and
return type (or signature). It can't do this because the
parser/compiler (yes, Python byte compiles --- actually
writing the byte compiled code to disk when possible)
doesn't have any way to identify the code (function) to
which a given identifier (including a method name) will
be bound at run time).

So, method overloading is done dynamically. You can
have your code use the type() function to test the
type to which an argument or variable is currently
bound and then act accordingly. This is done via
straightforward if type(a) == type(""): ... elif: ...
constructs.

I'd also talk a little more about sequences and
iteration (especially that strings, lists and tuples
are all sequence types).


def iter(a_sequence):
	for each in a_sequence:
		print each 

a="A string"
b=[1, 2, 3, 1000]
c=(0,)  ## a single item tuple, the "trailing comma" 
	## disambiguates this from a parenthesized 
	## expression: (0).
iter(a)
iter(b)
iter(c)

... this code isn't robust. If I pass iter() a
non-sequence I'll get an TypeError exception
(with an error of: "attempt to loop over non-sequence").

I can easily fix that with Python's exception handling:


def printeach(a):
	try:
		for i in a:
			print i
	except TypeError:
		for i in (a,):
			print i

Here I simply try to loop over the sequence; if that
gives a type error than I wrap my argument in a single
element tuple.

It's hard to give even a rudimentary introduction to Python
without cover its object oriented exception handling
features. For example one would create an abstract
class by defining the class with each of the requisite
(but virtual) functions defined to raise NotImplementedError
which would document the need for each of them, but
provide a reasonable behavior for any subclass that
failed to implement (over-ride) any of those requisite
functions.

It would be nice to describe some of Python's introspection
features like the dir() built-in, and the __dict__
dictionary of attributes (in instances, classes, etc)
and the type(), isinstance(), and __class__ attribute
of instances, and issubclass() built-in.

It's also hard to talk about Python 2.x without mentioning
list comprehensions. They can make for incredibly
elegant initializations for lists.

I'd also talk about more about argument passing to
Python functions. The ability to include optional
arguments (with defaults) and the "*args" and "**kwargs"
(keyword arguments) features.

Here's a little snippet of code for playing with *args
and **kwargs:


def arrg(*args,**kwargs):
	print "Args:"
	for i in args:
		print i
	print "KWArgs:"
	for i in kwargs.keys():
		print i, ":", kwargs[i]

I'd also point out that Python has many binary modules
and that it makes no syntactical distinction between
loading a binary module, a Python module or a package
module (from a directory on PYTHONPATH containing an
__init__.py file). They are all loaded with the
import statement, and they all provide members and
methods. A Python source module can be converted to a
package or to a binary and all the code that used it can
continue to run without changes. (This is in sharp
contrast to Perl's notion of modules, where the programmer
is constantly aware of the difference between using
one or the other).

It's probably also worth mentioning that Python didn't
allow one to subclass from the built-in types (list, tuple,
int, etc) until the release of the new 2.2 (and that this
feature was just added to the language as part of an
overall effort to "unify" types and classes). You might
also want to mention the "in" operator as in:



def merge(self, other):
	for key in other:
		if key not in self:
			self[key] = other[key]

(that code snippet is right from the "Unifying Types
and Classes" tutorial on the Python.org web site).

This makes code even more readable than:


def oldmerge(self, other):
	for key in other.keys():
		if not self.has_key(key):

[which wasn't too bad when you got used to it; but
starts to look more "Jargon-y" than the first example.
This makes the language harder to learn]. However,
if you talk about in you have to talk about the
iterators and generators (since it's invoking them
under the hood).

It also seems that you need to mention nested scoping
(also new in 2.1/2.2) and multiple inheritance
(especially the change from the old depth first,
left-to-right search rule to the 2.2 sweep first order).

Finally it would be a really *good* idea to warn new
Python people, jumping right into TIPython without
reading the Python tutorial because they're experts in
Perl, Java, and a dozen other languages, that they should
beware of integer division in Python. x/2 is different
for 5 and 5.0 and should probably usually be written as
float(x)/2 (to guarantee a real result, so to speak).

f  e  x


As if I hadn't said enough, it occurs to me that the
new "generators" (which can be thought of as C
static functions, sort of) uses the "yield" keyword
in an unconventional way. Other programming languages
that I've seen with a 'yield' statement have used it
for scheduling nicety. In other words we have our process
or thread "yield" to the system so that we're explicitly
(or co-operatively) giving up CPU cycles.

Of course this is not the sense in which Python 2.2
generators use the term. In Python 2.2 "yield" is used
more in the agricultural sense. What was the "yield" of
that corn field? Despite this initial confusion, I really
like the addition to the language. I think that generators
might be ideal for many cases where the state pattern
is called for.

In

f  e  x


[Oops, hit the [Key] for a case of premature form submission]

In explaining OODP (patterns) perhaps you could start
with explaining how Python natively exhibits some design
patterns. For example every class (and in 2.2 all of
the types) are factories. All of the sequences (and in
2.2 file objects and dictionaries) offer iterators. I
guess mementos can be implemented with pickle, cpickle,
shelve/marshall etc.

Unfortunately my lack of expertise in Python and my
ignorance of Patterns prevents me from offering additional
examples (and worries me that my examples may already be
flawed). However, I'm sure you get the idea.

Another thing that might accelerate development on this
book would be a survey of some existing Python code that
is in production (things like fsh, the fast/ssh proxy,
and pytris (curses Tetris), pysol (Tkinter Solitaire
game, implementing hundreds of solitaire rules sets,
and lots of features including sound, pluggable card
set graphics, selectable background color and tiles, etc).

I did a search at
freshmeat
and found about 400 projects that could be
surveyed.

The idea would be to survey some of the most popular
"real world" Python code for examples where Patterns are
being used --- and for examples where the application of
a pattern could be used to simplify or dramatically improve
an existing program. (Of course any suggested improvements
might be submitted back to the appropriate maintainers).

I'm already studying Python and reading through these
bits of code. However, I lack the expertise to spot
patterns (unless they have comments that point them out)
and I sure as heck don't understand Patterns well enough
to spot cases where existing Python code could be refactored
using them. That's why I'm reading your book online, and
Thomas W. Christopeher's Python Progrmming Patterns
(© 2002, Prentice-Hall/PTR) in print.

f  e  x


I'd chuck in a mention of the PPython standard library (maybe compare it to Perl's CPAN or something).

f  e  x


I have 2 comments:

1) Dicts are one of the most useful features in Python. Introduce them early.

2) When I am teaching people Python, one of the first things I show them is the "dir()" function, which is incredibly useful in interactive mode just to "poke around" and see what's available.


>>> l = [1,2,3]
>>> dir(l)
['append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
>>> dir(l.count)
['__doc__', '__name__', '__self__']
>>> print l.count.__doc__
L.count(value) -> integer -- return number of occurrences of value

One of the many things I like so much about Python is that once you understand how to use the introspective features, you suddenly have very little need to refer to the documentation. I don't use "dir()" all that much in actual programs, but for "poking around" and exploring the language it's a great way to start. Knowing how to get more information is quite useful.

(Reminds me of when I was first learning Unix 20-some-odd years ago, somebody showed me how to log in, then told me to type "man man", then left me alone for the rest of the day...)

f  e  x


since all methods are virtual, are inner classes then also?

f  e  x


What about access modifiers(public, private, protected..)? Do they exist, like in Java or C++?

f  e  x


Perhaps multiple inheritance would be useful here too.

f  e  x


interesting for everyone

dlskajfkasjfakslfjlkasjf-0wikqopkewqpjdnasdfoias[kfaolsmfaslkfmalksfmas

f  e  x



Add your comment below. Use an empty line between each paragraph. Paragraphs will be automatically formatted, and single carriage returns will be respected. Use <code> to begin a code block, and </code> to end a code block. Your email address will not be visible to spam harvesters or used in any way except to contact you with further questions.

Your Email Address:

Search     Home     WebLog     Consulting     Seminars     Calendar     Books     CD-ROMS     Newsletter     About     Contact     Site Design     Server Maintenance     Powered by Zope
©2007 MindView, Inc.