My Stuff
Email
Twitter
Front Page
Presentations
Projects
Music
Favorite Quotes

Respect
Vincent Foley-Bourgon
Sam Griffith
LeRoy Mattingly
Colin Putney
Matt Secoske
Sam Tesla
Andres Valloud

Admiration
Leo Brodie
Avi Bryant
Alan Cooper
Steve Dekorte
Stephane Ducasse
Doug Engelbart
Eric Evans
Brian Foote
Martin Fowler
Paul Graham
Dan Ingalls
Alan Kay
John McCarthy
Steve McConnell
Peter Norvig
Niall Ross
Randall Smith
Gerald Jay Sussman
David Ungar
Rebecca Wirfs-Brock
...And So Many More...

My Amps
Squeak
JavaScript
Scheme
Java
Corman Lisp
Ruby
Dolphin Smalltalk
Cincom Smalltalk
Self

Archives
05/01/2003 - 06/01/2003
06/01/2003 - 07/01/2003
07/01/2003 - 08/01/2003
08/01/2003 - 09/01/2003
09/01/2003 - 10/01/2003
10/01/2003 - 11/01/2003
11/01/2003 - 12/01/2003
12/01/2003 - 01/01/2004
01/01/2004 - 02/01/2004
02/01/2004 - 03/01/2004
03/01/2004 - 04/01/2004
04/01/2004 - 05/01/2004
05/01/2004 - 06/01/2004
06/01/2004 - 07/01/2004
07/01/2004 - 08/01/2004
08/01/2004 - 09/01/2004
09/01/2004 - 10/01/2004
10/01/2004 - 11/01/2004
11/01/2004 - 12/01/2004
12/01/2004 - 01/01/2005
01/01/2005 - 02/01/2005
02/01/2005 - 03/01/2005
03/01/2005 - 04/01/2005
04/01/2005 - 05/01/2005
05/01/2005 - 06/01/2005
06/01/2005 - 07/01/2005
07/01/2005 - 08/01/2005
08/01/2005 - 09/01/2005
09/01/2005 - 10/01/2005
10/01/2005 - 11/01/2005
11/01/2005 - 12/01/2005
12/01/2005 - 01/01/2006
01/01/2006 - 02/01/2006
02/01/2006 - 03/01/2006
03/01/2006 - 04/01/2006
04/01/2006 - 05/01/2006
05/01/2006 - 06/01/2006
06/01/2006 - 07/01/2006
07/01/2006 - 08/01/2006
08/01/2006 - 09/01/2006
09/01/2006 - 10/01/2006
10/01/2006 - 11/01/2006
11/01/2006 - 12/01/2006
12/01/2006 - 01/01/2007
01/01/2007 - 02/01/2007
02/01/2007 - 03/01/2007
03/01/2007 - 04/01/2007
04/01/2007 - 05/01/2007
05/01/2007 - 06/01/2007
06/01/2007 - 07/01/2007
07/01/2007 - 08/01/2007
08/01/2007 - 09/01/2007
09/01/2007 - 10/01/2007
10/01/2007 - 11/01/2007
11/01/2007 - 12/01/2007
12/01/2007 - 01/01/2008
01/01/2008 - 02/01/2008
02/01/2008 - 03/01/2008
03/01/2008 - 04/01/2008
04/01/2008 - 05/01/2008
05/01/2008 - 06/01/2008
06/01/2008 - 07/01/2008
07/01/2008 - 08/01/2008
08/01/2008 - 09/01/2008
10/01/2008 - 11/01/2008
01/01/2009 - 02/01/2009
09/01/2009 - 10/01/2009
10/01/2009 - 11/01/2009

Feed

Add this feed to a running copy of BottomFeeder

Saturday, October 17, 2009

Devilishly Clever

 
I was doing my usual research on Python when I ran across this recipe to make tail recursive calls not blow the stack in Python: Tail Call Optimization Decorator. I read through the code and thought, "Wow! This is devilishly clever!" As a thought exercise, I think it's awesome. But, it got me thinking about clever and production code. In my opinion, clever is never good or wanted in production code. It's great to learn and understand clever code though. It's a great mental workout to keep you sharp.

So, what's my point with all of this besides to say that clever is bad? The example in the above link is factorial (which as everyone knows is hated by me, but that's another story). But, the amazing thing about factorial examples are that they are dead simple, yet there's several ways to get the answer. Here's a few that I came up with:
def reg_fact(x):
if x is 1:
return 1
return reg_fact(x - 1) * x

def tail_fact(x):
def func(acc, x):
if x is 1:
return acc
return func(acc * x, x - 1)
return func(1, x)

def not_rec_fact(x):
result = 1
for each in range(2, x + 1):
result *= each
return result

def not_rec_fact_fancy(x):
return reduce(lambda result, each: result * each, range(1, x + 1))

import operator
def not_rec_fact_super_fancy(x):
return reduce(operator.mul, range(1, x + 1))


Each of these compute factorial. Amazingly, there's even more ways than what I listed (the math wizards in the audience know what they are). Now, think about this: Computing factorial is dead simple. What happens when we get to harder problems? Being clever can actually get in the way of making the code easy to understand. It might even kill performance. Let's think back to the devilishly clever code. The performance of making Python tail recursive is awful. Sure, it's pure and tail recursive, but in production code that is deadly. What we want is simple and to the point. It's why I generally like solutions that need less code. There's less noise to get in the way of understanding and generally can mean better performance as well.

Real world problems are hardly ever as straightforward as factorial. The balancing act comes when you drop a solution because it's not working for whatever reason. Raising and catching exceptions so you can have a tail recursive factorial is overkill. It took more code than the non-recursive version. It begs for the programmer to know their tool set and to know how to solve problems in that tool set that are straightforward. Tail recursion is powerful in languages like Haskell and Erlang. But, there's always another way of doing things that can make more sense in the language you are using. In our case, the other ways were just as easy yet more scalable for our tool set. Food for thought the next time you go down the path of clever and end up writing more noise than solution.

Labels: , ,


Comments
  • This post reminds me of the all-too-true quote by Brian Kernighan:

    Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.

    By Blogger kesmit, at 9:51 PM   

  • Hey! I wrote an entry about a clever coding too.

    http://squeak.preeminent.org/blog/?p=325

    - Steve

    By Blogger fastfingers, at 10:07 PM   

Saturday, October 10, 2009

Freezing Objects in Python

 
Someone stop me. I like freezing simple objects or what Eric Evans calls "Value Objects" in his excellent "Domain Driven Design" book. Python doesn't have immutable objects (ala freeze in Ruby) explicitly, but we can easily create it. Python gives us the power to get under its covers. Here's my implementation:
class ValueObject(object):
def __setattr__(self, name, value):
if name == 'value' and hasattr(self, 'value'):
raise AttributeError("Can not change value attribute")
else:
self.__dict__[name] = value


Do you have to ask? Yes, I made a test. Here they are:
import unittest
class Test(unittest.TestCase):

def testSimple(self):
class Cents(ValueObject):
def __init__(self, value):
self.value = value
def __str__(self):
return str(self.value) + " cents"
subject = Cents(5)
self.assertEquals(5, subject.value)
def set_value():
subject.value = 6
self.failUnlessRaises(AttributeError, set_value)

Labels: ,


Comments

Monday, October 05, 2009

method_missing in Python

 
OK, I know there is a few implementations of this knocking around on the net already, but I'm in learning mode. So, here's my implementation of Ruby's method_missing:
class PossibleMissingAttribute(object):
def __init__(self, object, name):
self._object = object
self._name = name

def __call__(self, *args, **kwargs):
return self._object._method_missing(self._name, *args, **kwargs)

def __str__(self):
return self.__class__.__name__ + ": " + str(self._object) + "." + self._name

def __getattr__(self, name):
return None

def __nonzero__(self):
return False

class MethodMissingError(Exception):
def __init__(self, object, name, *args, **kwargs):
self.object = object
self.name = name
self.args = args
self.kwargs = kwargs

def __str__(self):
return repr(str(self.object) + "." + self.name)

class Missing(object):
def __getattr__(self, name):
return PossibleMissingAttribute(self, name)
def _method_missing(self, name, *args, **kwargs):
raise MethodMissingError(self, name, *args, **kwargs)


Three objects and that's it! One to be a placeholder when an argument is missing. One object to represent the MethodMissingError and the last to be an abstract class to inherit from. But, you could easily just put these methods anywhere. Here's my tests:
import unittest

class TestMissing(unittest.TestCase):
def test_missing(self):
class TestClass(Missing):
def __str__(self):
return self.__class__.__name__
def existing(self):
return "i am"
def _method_missing(self, name, *args, **kwargs):
return args[0]
self.assertEquals("am not", TestClass().missing("am not"))
self.assertEquals("i am", TestClass().existing())
self.assertEquals(None, TestClass().missing.something_else_missing)
self.assertFalse(TestClass().missing)
self.assertEquals("PossibleMissingAttribute: TestClass.missing", str(TestClass().missing))

def test_exception(self):
class TestClass(Missing):
def __str__(self):
return self.__class__.__name__
self.failUnlessRaises(MethodMissingError, lambda: TestClass().missing())



You've seen my implementation. Here's another one that I found on the net: method_missing in Python
class MethodMissing(object):
def method_missing(self, attr, *args, **kwargs):
“”" Stub: override this function “”"
raise AttributeError(”Missing method %s called.”%attr)

def __getattr__(self, attr):
def callable(*args, **kwargs):
return self.method_missing(attr, *args, **kwargs)
return callable

Um, this version is much shorter than mine. It gets the same job done and is more obvious of what it is doing. Simply returning a function on __getattr__ is the best way to go. It's what my PossibleArgumentMissing was doing. But, where I tried to get all fancy using __call__ to mimic a function which caused my version to be longer. I was also trying to get the argument to come back to return false in if conditions and be almost like None (again, I'm learning and was looking at what was possible). Simplest is best.

This was a fun thought exercise. I love all the hooks Python provides to allow you to get underneath the hood if need be. I will be soon doing a post on descriptors and even decorators. I find Python tends to sway heavier on the functional side of programming versus object-oriented. I'm loving the succinct, yet readable code. Too many languages get into the being so terse that they sacrifice readability or debugability (is that a word? Is now!).

Labels: ,


Comments

Tuesday, September 29, 2009

Prototypes in Python

 
I'm in love with prototype-based languages, but there only a few to play with ECMAScript (Javascript) and Self. Since I'm learning Python, I thought it would be a good experiment to implement prototypes in Python. For one thing, I would get to learn some of the meta capabilities and other advanced features. A pure thought experiment just for learning and seeing how far I could push another paradigm onto Python. Here is what I came up with:
class Prototype(object):
def __init__(self, *args):
self._parents = []
for each in args:
self._parents.append(each)

def clone(self, *args):
return self.__class__(self, *args)

def __getattr__(self, name):
for each in self._parents:
try:
return getattr(each, name)
except AttributeError:
pass
raise AttributeError(name)

The implementation is suprisingly simple: three methods!

The first is the initialize method for new instances. It takes a list of objects that we will use as the parents of our new object. Of course, by simply calling Prototype's constructor with no arguments, we get a clean object. I made the ability to have multiple inheritance simple because of Self.

The second method is the clone method and it simply calls the constructor for another object makes itself the first parent with the rest of the arguments becoming the other parents. Nothing to it!

The last method is the real meat. It only get called by the Python engine when an attribute fails to be looked up. All I do is call each parent and if one succeeds, it returns the answer. This is a depth first search of the parent hierarchy. Simple.

And that's all we need to implement prototypes in Python. Now, I just need to explain some practical uses of this in some later blog entries.

How do I know all of this works? Here's my tests:
import unittest
class Test(unittest.TestCase):

def testSimple(self):
parent = Prototype()
child = parent.clone()

parent.value = 0
self.assertEquals(0, child.value)
child.value = 1

self.assertEquals(1, child.value)
self.assertEquals(0, parent.value)

self.failUnlessRaises(AttributeError, lambda:parent.unknown)

def testMultipleParents(self):
parent1 = Prototype()
parent2 = Prototype()
child = parent1.clone(parent2)

parent2.value = 2
self.failUnlessRaises(AttributeError, lambda:parent1.value)
self.assertEquals(2, child.value)

If anyone sees anything wrong in my implementation or un-Pythonic let me know. I'm still learning, but I thought it would be cool to show my progress.

Labels: ,


Comments
  • You can actually shorten your constructor down to self._parents = list(args).

    By Blogger kesmit, at 9:28 AM   

  • Welcome to the world of Python. You will like it here.

    By Blogger MikeHoss, at 9:48 PM   

  • You shouldn't copy objects so deeply. You have to make a class-like thing. You create a new object with a proto attribute. Then when an attribute is requested you find it in the local attributes. If it's not found you search in the proto, and so on until the proto is None. Your way you always copy the whole object, and it becomes heavy in memory terms.

    By Blogger Luca Bruno aka Lethalman, at 3:43 AM   

  • Thanks Kesmit and MikeHoss!

    To Luca, Where am I copying deeply? The clone method creates a brand new object and it is not a copy. The parents attribute is the proto attribute you were talking of. The __getattr__ is only called when an attribute is not found and then it searches for it in the parents (and if they are Prototypes, then they will do the same.

    How am I copying the entire object? I want to make sure I'm not doing something wrong.

    By Blogger Blaine, at 6:14 AM   

Sunday, September 13, 2009

Constraints in Python

 
With every language that I learn, I pay close attention to my work flow. I take note of anything that gets in the way of getting my task accomplished. In a perfect language, I should never have to worry about the language ever. A free flow of ideas should come out. Whenever I find myself totally immersed in a problem, I keep track of what made it so. Recently, the one feature that surprised me the most was Python's forced indention. At first I thought, how nice not to use curly brackets to denote scope, but what about that white space? But, I put my best foot forward and worked on some code. I must admit that I love it now! It makes code more readable by keeping the rules consistent (you have to be or your code will have bugs). Formatting my code is now one less worry I have. I am forced to indent as I go along. This constraint is liberating in the fact that it allows me concentrate on the problem at hand and is one less thing to worry about. No more worrying about if the curly braces go on the same line or not depending on local coding standards. It makes code easier to read across Python programmers. In fact, I have yet to meet a Python program that I could not understand easily from first glance which is a rare accomplishment in other languages.

I also love the constraint about one line lambdas. I thought it was going to drive me crazy, but I have embraced completely. It keeps your lambda functions short and sweet like they really should be. But, the best side effect is that if that lambda needs to grow, you simply move it out to a named function automatically making your code more readable. Excellent.

Both of the features that I just mentioned are merely constraints that take away thinking about the language and force you to write readable code. I always like and embrace the design decisions to constrain the coder to make more maintainable code. The less I have to think about the language, the more time I spend on the problem I am trying to solve and that's the way it should be. It just amazed me that sometimes I find them in the strangest of ways. I would have never thought that forced indention or one lined lambdas would bring me so much coding pleasure.

Labels:


Comments
  • I had kind of the same feeling you mention here. As Smalltalker, at first I didn't like the indentation, but when I have had to start coding python I discovered that it's useful.

    But, I must say that anyway I believe Smalltalk is always a step ahead. Why? Because you have prettyprint. You can write your code in a faster way and get it automatically formated in a standard way.

    But, also, I think it could be taken forward in this way: Suppose you don't like the prettyprint why of formatting. You can modify the IDE to show you the code prettyprintted in the way you most like, anytime, and save it in the standard formatting for your office standards, for example.

    By Blogger tenuki, at 3:23 PM   

  • I always use automatic formatting in any language I use. I thought it was cool that it is unneeded in Python. It's also nice that the formatting is the same from developer to developer, no more taste wars.

    The more the language takes away mundane issues (formatting), the more time you have to think about your problem at hand which is the whole point of languages.

    By Blogger Blaine, at 7:06 PM   

  • Yes. Your point is clear!

    By Blogger tenuki, at 8:21 PM   

  • Glad to hear from another convert.

    By Blogger Ron Smith, at 10:27 PM   



Web hosting by ICDSoft

Metalheads Against Racism
This page is powered by Blogger. Isn't yours?


My Weekly Top 20 Artists