[Edu-sig] Topics for CS2

kirby urner kirby.urner at gmail.com
Sun Jan 18 05:21:21 CET 2009


Hi David --

I've been looking at your PythonOOP.

Why use classes?  All programming aside, I think it's a fairly strong
grammatical model of how people think, basically in terms of
noun.adjective (data attribute) and noun.verb() (callable method).
All talk of computer languages aside, we're very noun-oriented, think
in terms of "things" and these things either "are" or "have"
attributes and "do" verby stuff.

OOP is about making the language talk about the problem domain, help
us forget that under the hood nightmare of chips and registers,
needing to allocate memory... all that stupid computer stuff that
nobody cares about (smile).

Of course I like your nomenclature of a Cat inheriting from Animal as
I'm always tying "hierarchy" back to "zoology" and "taxonomy" as those
were original liberal arts tree structures (class hierarchies,
kingdoms, domains, namespaces).  We like "astral bodies" subclassed
into stars, planets, planetoids (like Pluto), and moons.  We like
"Reptiles" including "Snakes" which of course includes "Pythons"
(everything is a python in Python, i.e. an object with a __rib__
cage).

Having a Dog and a Monkey motivates why ancestor classes are
important:  generic shared stuff, like digestion, might be handled in
a shared eat() method, each with its own self.stomach of course.  With
a younger set (pre-college), those parentheses connote lips, with args
as oral intake.  In the class of classes though... we give birth.

Per a recent PPUG, I'm these days thinking to use a collections.deque
for my digestive tract maybe:

>>> class Animal:
	def __init__(self):
		self.stomach = deque()
	def eat(self, item):
		self.stomach.append(item)
	def poop(self):
		if len(self.stomach)>0:
			return self.stomach.popleft()

		
>>> zebra = Animal()
>>> zebra.eat('straw')
>>> zebra.stomach
deque(['straw'])
>>> zebra.poop()
'straw'
>>> zebra.stomach
deque([])
>>>

Some will want to say digestive_tract instead of stomach.

Now you can develop your Dog and Cat, inheriting eat() and __init__
from Animal, yet each subclass providing its own __repr__ methods.
"Hello world, I'm a Cat at %s" % id(self).  Yes, you could make the
__repr__ invoke __class__.__name__ and share it -- show that later....
?

>>> class Animal:
	def __init__(self):
		self.stomach = deque()
	def eat(self, item):
		self.stomach.append(item)
	def poop(self):
		if len(self.stomach)>0:
			return self.stomach.popleft()
	def __repr__(self):
		return "I'm a %s at %s" % (self.__class__.__name__, id(self))

	
>>> class Dog(Animal):
	pass

>>> class Cat(Animal):
	pass

>>> thing1 = Dog()
>>> thing2 = Cat()
>>> thing1
I'm a Dog at 138223820
>>> thing2
I'm a Cat at 138223852

Students see how inheritance means specializing as you go down the
tree (consistent with most introductory treatments).

Your spin seems to tilted towards Cats with not enough other
subclasses of Animal to make inheritance seem all that necessary.
Your ancestor is mostly for "herding cats" (counting instances), isn't
so much a "blueprint" for different subclasses of the Animal idea
(aardvark versus eel).

More generally I think using an ancestor class to do instance counting
is a little on the "too difficult" side for a core introductory
running example.  It leads you to introduce an interception of __del__
as your first example of operator over-riding.  This seems rather
unpythonic, as the __del__ method is rather rarely intercepted,
compared to say __set__ and __get__ (per Alex Martelli in this lecture
@ Google:  http://controlroom.blogspot.com/2009/01/oop-in-hour.html
).

I was also struck by how often you compare classes to modules (modules
in Chapter 16 right?), suggesting a Perlish upbringing -- as did your
suggestion to use '_' in place of 'self' for "maximal uncluttering"
(paraphrase).

When Perl decided to make the leap to OO, it was "the module" that got
blessed for this purpose yes? Are you a closet Perl Monger then?

I notice you tend to favor your private terminology and don't resort
to the CS vocabulary as often, e.g. "polymorphic" and "polymorphism"
are not included.  If you're wanting your students to gain fluency
with the surrounding literature, I think at least that one deserves
more focus, in conjunction with inheritance.

I think the a first class could be all data (like a C struct).  Like,
this example says a lot:

>>> class Foo:
	bar = 1

	
>>> f = Foo()
>>> g = Foo()
>>> f.bar = 1
>>> f.bar = 2
>>> g.bar
1
>>> f.bar
2
>>> f.__dict__
{'bar': 2}
>>> g.__dict__
{}
>>> g.bar
1

however once you start adding methods, I don't think postponing the
appearance of __init__ for so long is a good idea.  I would focus on a
Dog and a Cat (or any other two animals), both with __init__
constructors and eat methods, then (as a next step) introduce the
Animal superclass as a case of "refactoring" by inheritance -- a good
time to mention the "is a" abstraction (a Dog "is an" Animal).  Show
how you're economizing on code by having an ancestor, make OO seem
like a revelation (which it is/was).

I don't think you're alone in finding __ribs__ somewhat intimidating,
strange-looking (a hallmark of Python), but I think these should be
tackled right away, perhaps with built-in data types first, i.e. that
2 .__add__(2) example.  How about a function call ribs() that prints
the special names in any object...

>>> import re
>>> ex = re.compile("__[a-z]+__")

>>> def ribs(it):
	return re.findall(ex, " ".join(dir(it)))

I think of __init__ as being triggered by a "birth syntax" i.e. to
call a class directly, as in Animal(), is to call for an instance of
that class, and that invokes __init__ (__new__ first though).

>>> class Foo:
	def __init__(self):
		print("I am born!")

	@staticmethod
	def __call__():
		print("What?")

		
>>> f = Foo()
I am born!
>>> f()
What?
>>> Foo.__call__()
What?

I like your point that intercepting __add__ is just like
"intercepting" an Animal's 'talk' method in a subclass, i.e.
interception is happening in both cases, it's just that some names are
special (as you say) in being triggered by *syntax* rather than their
actual names -- although that form is also usable (as you point out
using __add__)  -- plus some special names *don't* have special
triggering syntax, i.e. just use the __rib__ directly, as in "if
__name__ == '__main__':"

I like this section:

Background on Languages
- languages poster
- progression of languages              1     2
  - domain-specific (FORTRAN, COBOL)
  - general-purpose, high-level (C)
    - one step above assembler
    - problem was complexity, one big pile of data
  - object-oriented (C++)
    - data now contained within independent objects
  - human oriented (Java, Python)
    - garbage collection
    - dynamic typing

... and your focus on Mandelbrot / fractals.

Lots of substance.

Kirby

On Thu, Jan 15, 2009 at 3:09 PM, David MacQuigg
<macquigg at ece.arizona.edu> wrote:
> I'm putting together a list of topics for a proposed course entitled "Programming for Scientists and Engineers".  See the link to CS2 under http://ece.arizona.edu/~edatools/index_classes.htm.  This is intended as a follow-on to an introductory course in either Java or C, so the students will have some exposure to programming, but the Java students won't know machine-level programming, and the C students won't have any OOP.  For the proposed course, we will use the example programs as a way to introduce these topics.
>
> As you can see from the very few links to completed examples, this is just a start.  Many of the links are only to discussions on this list, and I really appreciate the suggestions I have received so far.  Also, it is far from a representative survey or optimum sample, rather just a random sample of topics that I found interesting.  Some of the topics may be out of reach for students at this level, but that is the challenge.  Figure out a way to present a complex or theoretically difficult topic in a way that is simple and intuitive and will whet the students appetite for further study.
>
> Additional suggestions are welcome.
>
> -- Dave
>
>
> _______________________________________________
> Edu-sig mailing list
> Edu-sig at python.org
> http://mail.python.org/mailman/listinfo/edu-sig
>


More information about the Edu-sig mailing list