

The Evolution of a Python Programmer - jimhoff11
https://gist.github.com/289467

======
nkh
Here is the discussion from the last time this was posted (90 Comments):

<http://news.ycombinator.com/item?id=1087068>

~~~
ward
On the other hand, that was 769 days ago.

Edit: Just realized you might be pointing this out to help the interested
reader, I first assumed you were reprimanding for reposting.

------
chewxy
If anyone's interested (I am because I found myself to be a 'Lazier
programmer') -

Timeit's time for three functions:

Lazy Programmer - 0.907521744301

Lazier Programmer - 1.0473810545812512

Using math.factorial - 0.12187403971609001

~~~
Mavyrk
A 'lazier programmer' who actually checked the optimization of various
factorial methods?

There's a joke in there somewhere...

~~~
lani
a lazy programmer is one who will write a shell script in an hour to generate
three lines of boilerplate...

~~~
prakashk
It's worth it, if you have to type the boilerplate code hundreds of times.
Consider the time wasted in debugging errors due to typos etc. It's even more
worth if that shell script (or, in my case an emacs yasnippet) is
parameterized.

------
tomku
The "Python expert" version doesn't run, but it's not hard to fix:

    
    
      import operator as op
      import functools as f
      fact = lambda x: f.reduce(op.mul, range(1, x + 1))
      print(fact(6))
    

If you're using Python 2.x, you can make it a bit shorter due to reduce being
in the default namespace:

    
    
      import operator as op
      fact = lambda x: reduce(op.mul, xrange(1, x + 1))
      print fact(6)

------
tzs
If you can live with floating point results:

    
    
       from math import gamma
       def factorial(x):
          return gamma(x+1)
    

This has the advantage of working correctly for non-integer arguments.

~~~
tomku
The factorial itself is only defined for non-negative integers. This may seem
pedantic, but what you've defined there is actually Gauss's pi function, which
has many interesting mathematical properties, but is not equivalent to the
factorial because it has a larger domain. The results that it gives for non-
integer arguments aren't any more "correct" than a factorial function throwing
an exception, because they're both behaving appropriately for their defined
domain.

Edit: The math module has a factorial() function anyways, so it's a bit of a
moot point. Use that :)

Edit Edit: Thanks for the catch, I did mean non-negative integers instead of
positive.

~~~
JeanPierre
As far as I know, 0! = 1, so I assume you meant non-negative integers instead
of positive integers?

------
lclarkmichalek
A true hackerish version perhaps:

    
    
        bc = [124, 0, 0, 114, 37, 0, 116, 0, 0, 124, 0, 0, 106, 2, 0, 100, 1, 0, 131, 1,
              0, 124, 1, 0, 106, 1, 0, 124, 0, 0, 131, 1, 0, 131, 2, 0, 83, 124, 1, 0,
              83]
        fact = type(lambda:0)(type((lambda:0).func_code)(2, 2, 7, 0,
                       ''.join(map(chr, bc)), (None, 1), ('fact', '__mul__', '__sub__'),
                       ('x', 'acc'), "n/a", "fact", 0, ""),
                  globals(), "fact", (1,))

~~~
codesuela
while I know this is a joke I would argue that this is in no way hackerish,
this is an asshole version. Basically a middle finger to anyone who wants to
work with your code. Also anything but pythonic. (please note this not meant
to be an insult to the parent commenter)

~~~
lclarkmichalek
It is hackerish to the extent it demonstrates a knowledge of python's
internals, however maybe it would better be described as being written by a
former assembly programmer. Also, you might be interested in the fact that
Paul Graham argues that his dream language would have inline bytecode. It
probably wouldn't be written as a list of integers though.

As for this not being pythonic, at least its not self modifying or anything
fun. I did once see a talk on obsfucated python that used decorators to
implement a Turing complete language, so this is hardly the worst abuse of
python ever.

------
nchuhoai
The original: <http://www.willamette.edu/~fruehr/haskell/evolution.html>

(Haskell)

~~~
klez
The (actual) original:
[http://www.ariel.com.au/jokes/The_Evolution_of_a_Programmer....](http://www.ariel.com.au/jokes/The_Evolution_of_a_Programmer.html)

------
NameNickHN
The webdesigner version absolutely nailed it.

------
e-dard
I prefer "short but to the point". This is instinctively what I threw in
iPython before looking past first snippet:

    
    
        print reduce(lambda x, y: x*y, xrange(2, 6+1))
    

As a newish Python guy (5 months), I'm interested as to why the preferable
solution seems to be to import operator and use the multiplication function?
(I'm purposely ignoring the more preferable call to the C library)

~~~
tomku
Two answers, really.

1) The Python community doesn't really like lambdas. It's almost always
considered better style to declare a named function, even if it's a short one-
liner. If it's already available in the standard library, use that instead of
re-implementing it as an unnecessary lambda.

2) This is an adaptation of jokes that have been made about many languages
before Python, so the code isn't very Pythonic to start with. Most of the
complex ones have errors that prevent them from running, they're just for
comedic effect.

------
dustingetz
related educational stuff: here's three different ways to do lazy sequences
(infinite seqs) in python: generators, closures, and classes. provides
implementations of lazy-map and lazy-filter for each style. (the generator
implementations are equivalent to those in itertools.) uses fib instead of
fac.
[https://github.com/dustingetz/sandbox/blob/master/etc/lazy.p...](https://github.com/dustingetz/sandbox/blob/master/etc/lazy.py)

we can use these ideas to elegantly solve the second greplin challenge
question: "find the smallest prime fibonacci, X, greater than 227,000; compute
sum of prime divisors of X+1"

    
    
      pred = lambda x: x > 227000 and is_prime(x)
      X = take(lazy_filter(pred, fib_gen()), 1)[0]
      print sum(filter(is_prime, divisors(X+1)))
    

[https://github.com/dustingetz/sandbox/blob/master/etc/grepli...](https://github.com/dustingetz/sandbox/blob/master/etc/greplin2.py)

------
alexholehouse
Ha - I like the [English] expert programmer. When I started coding I spent one
evening looking for a maths.h bug...

~~~
TazeTSchnitzel
I've had the reverse experience. My exposure to programming language libraries
and American media has resulted in me accidentally saying "math" sometimes.

------
eipi
Memoized version:

    
    
      class Factorial(object):
        def __init__(self):
            self.n = 0
            self.fact_n = 1
    
        def next_fact(self):
            self.fact_n *= (self.n + 1)
            self.n += 1
    
        def prev_fact(self):
            self.fact_n /= self.n
            self.n -= 1
    
        def fact(self, n):
            if n == self.n:
                return self.fact_n
            elif n > self.n:
                # start from self.n working forward
                self.next_fact()
                return self.fact(n)
            else:
                # start from fact_n working backwards
                self.prev_fact()
                return self.fact(n)
    
    
      fobj = Factorial()
      print fobj.fact(6)
      print fobj.fact(8)
      print fobj.fact(3)

------
devy
Apparently, #EXPERT PROGRAMMER wins for efficiency ;)

~~~
chimeracoder
Not surprising - many Python built-ins are implemented in C. And for any
numerical or computational libraries, doing it in C is all but essential.

Tangential, but this is why NumPy totally changed my workflow. I can use all
of the benefits of Python, including its libraries and syntax, and still have
a program that executes at the speed of C, rather than Python[1].

[1] Not _literally_ the speed of C, but you get the idea.

~~~
sukuriant
Programs as fast as the speed of light!

------
JVIDEL
I'm really digging the last 5 examples, specially the web designer and
enterprise programmers parts.

So true...

------
lclarkmichalek

        #Python hacker
        <function omitted>
        sys.stdout.write(str(fact(6)) + '\n')
    

The call to str is unneeded. For consistency, it should be

    
    
        sys.stdout.write(fact(6).__str__() + "\n")
    

And if that example want's to be really "hacker"ish, then every function call
should actually be a call to the __call__ method of each object.

------
lani
good lord !! I am an enterprise programmer !!! *self-flagellation everyday...

------
vmmenon
lol :) i loved the 'enterprise programmer' version ...

------
giulivo
i can clearly see me in the first few trials :P

------
cheatercheater
Half of those are incorrect implementations that junk the stack and most of
the rest are idiotic rebaked jokes from the late 90s. Nowhere near to
<http://www.willamette.edu/~fruehr/haskell/evolution.html> which is not only
enlightening but actually funny when it tries to; or even to
[http://www.ariel.com.au/jokes/The_Evolution_of_a_Programmer....](http://www.ariel.com.au/jokes/The_Evolution_of_a_Programmer.html)
which was funny when it started and still is the original. Can we stop making
HN into the next xkcd?

~~~
AznHisoka
I actually thought this was the best thing I read today. So please don't stop
posting these.

~~~
cheatercheater
If you want to see multiple interesting solutions to the same problem, and use
Vim as your text editor, then check out <http://vimgolf.com>

------
waldrews
And friggin' nobody thought to range or even type-check the inputs?
preconditions? overflow?

