Thursday, November 20, 2008

Strong types, weakly bound

Reading Strong opinions, somewhat weakly held on Jason Cohen's excellent A Smart Bear blog this morning, I was quoting this excellent soundbite (you really need to simplify it down to "strong opinions, weakly held" to make it work as a soundbite) out loud to Anna and musing about it -- and exactly at the same time she and I chorused about the analogy this has with Python's approach to typing... objects with strong, precise types, but "weakly held" (i.e., weakly bound) via names or slots in containers that might just as well hold objects of other (also strong) types.

This analogy may actually be the least "obvious" thing she and I found ourselves "chorusing" about, though such "choruses" happen more and more often and so it's becoming hard to tell;-). Anyway, I'll be sure to use this next time I need to present Python's typing approach -- now if I can only find a way to work ducks into it, too...

Wednesday, November 19, 2008

Get your blog typealyzed!

Fun URL to try: Typealizer (HT Greg Mankiw).

What Typealizer has to say about Aleaxity (quoted verbatim, including punctuation/grammar errors and typoes)...:
"""
The analysis indicates that the author of http://aleaxit.blogspot.com is of the type:
ISTP - The Mechanics
[ISTP]
The independent and problem-solving type. They are especially attuned to the demands of the moment are masters of responding to challenges that arise spontaneously. They generelly prefer to think things out for themselves and often avoid inter-personal conflicts.

The Mechanics enjoy working together with other independent and highly skilled people and often like seek fun and action both in their work and personal life. They enjoy adventure and risk such as in driving race cars or working as policemen and firefighters.
"""
The "enjoy adventure and risk" is as off-base as it could possibly be (if anything, I enjoy reducing and controlling risks and adventures by carefully and prudently balancing solid architectures, sound methodologies, best practices, ...), but other bits do appear rather spot-on;-).

Friday, November 14, 2008

Python tips: pickling it right

Here's an often-seen Python snippet...:

pickle.dump(stuff, open('foo.pik', 'w'))

What's wrong with this? Well, several things, as it turns out...!
  1. Use cPickle, not pickle: that will speed things up by 5 or 6 times, effortlessly.

  2. The common, sloppy use of open without a corresponding close is theoretically OK in today's cPython, but there's really no good reason to support it. Be neat instead, and write (after a from __future__ import with_statement if you're still using Python 2.5):

    with open('foo.pik', 'w') as f:
    cPickle.dump(stuff, f)

  3. Unless there's a very special reason to make you want the pickle dump to be in ASCII (and I've hardly ever seen a good one), don't just use pickle's default, legacy protocol! Rather, explicitly request protocol 2, or better still, unless you need pickle files loadable by older releases of Python, request "the best protocol available".

So, the best equivalent of that little sloppy but alas-too-common idiom is:

with open('foo.pik', 'wb') as f:
cPickle.dump(stuff, f, cPickle.HIGHEST_PROTOCOL)

Don't forget the little b in 'wb', by the way — it won't matter under Linux, OSX, or Solaris, but it will matter in Windows... and, anyway, as we all know, explicit is better than implicit!-)

Python: introspecting for generator vs function

At Baypiggies yesterday evening, Fernando Perez asked how to tell by introspection whether you're dealing with a "plain old Pythjon-coded function", like, say,

def f(): return 1

or rather a generator function, like, say,

def y(): yield 1

Apparently, he needs that info to perfect some decorator they're using as part of a nose-based test framework for scipy.

I don't think there's any other way except by looking at the bytecode for Yield vs Return opcodes; so, I jotted down on the spot the quick-and-dirty approach based on that idea:


import dis, sys
def is_generator(f):
save_stdout = sys.stdout
fake_stdout = cStringIO.StringIO()
try:
sys.stdout = fake_stdout
dis.dis(f)
finally:
sys.stdout = save_stdout
return ' YIELD_VALUE ' in fake_stdout.getvalue()

Of course, this does much more work than necessary (AND can be fooled by a function containing a peculiar string literal... like itself!-) . So, early this morning, I prepped a somewhat better performing and more solid version:

import opcode
YIELD_OP = opcode.opmap['YIELD_VALUE']
RETURN_OP = opcode.opmap['RETURN_VALUE']
HAVE_ARG = opcode.HAVE_ARGUMENT

def isgen(f):
code = f.func_code.co_code
n = len(code)
i = 0
while i < n:
op = ord(code[i])
i += 1
if op >= HAVE_ARG:
i += 2
elif op == YIELD_OP:
return True
elif op == RETURN_OP:
return False
return False


Hope this can prove useful to someone else!-)


Alex

Wednesday, November 12, 2008

Meme spotted on Steve Holden's blog:
  • Grab the nearest book.
  • Open it to page 56.
  • Find the fifth sentence.
  • Post the text of the sentence in your journal along with these instructions.
  • Don’t dig for your favorite book, the cool book, or the intellectual one: pick the CLOSEST.

Closest to me on the couch is Barry Cunliffe's Europe Between the Oceans: 9000 BC to AD 1000, which I just bought and haven't gotten around to reading yet. 5th sentence on p. 56 is: "The fame of early Troy owed much to its command of this favoured location.". (I got lucky: other sentences around this one, explaining in detail about the bay that is the location in question, and its importance, are way longer;-).