94 comments

[ 4.2 ms ] story [ 198 ms ] thread
The web designer and windows programmer snippets are brilliant.
The enterprise programmer one is pretty good too. Reminds me of EJB (shudder).
Gotta get that LOC count up.
Productivity can only be measured by lines of code-- what a co-worker told me. Reminds me of that dark, evil place.
Likewise, productivity of surgeons can only be measured in numbers of stitches.
I don't know, it doesn't look flexible enough. The classes should be wired up at runtime using an XML config file. I also think it could also split the problem using a pool of threads to achieve better performance. Even better, you could queue up all the factors in a master node and have N slaves pulling from it and multiplying. After the queue is empty, all the master has to do is query each slave and multiply the intermediate results together.
I was a big fan of the: lazy python programmer, lazier python programmer, and python expert programmer series. Having been through that series, and watched many others go through it themselves, I find it to be the best HAHA-only-serious bit in there.

I'm not sure what it is, but at some point every pythonista seems to go through this love affair with functools + itertols + roll your own haskellish modules.

It would seem that the better you get at python, the more you really want a functional language. I know I went through this too (and I have moved onto functional languages for personal projects since..)
I remember that the "Real World Haskell" was one of the first books sold-out at the OReilly booth at Pycon 2009, if you want more supporting (anecdotal) evidence.
To add to the evidence, I'm an experienced Python programmer who is currently waiting very impatiently for his Amazon shipment of "Real World Haskell" and "Purely Functional Data Structures". (Oh, and "Garfield Minus Garfield".)
The last of those books opens with "Objective Caml (OCaml) is a popular, expressive, high-perfomance dialect of ML...". This must be some hitherto unknown usage of the word "popular"...
Popularity is relative -- in this case you must compare OCaml to other forms of ML, in which case the popularity is obvious :)
I write what I believe to be functional style Python, and have great coverage and fairly easy multithreading (normally using 2.6 Queue objects) as a result. I really like the clean syntax of Python, the less I have to look at on screen the better. Do you think there's a functional programming language I'd like? I've looked at Erlang but not been persuaded.
Have you looked at Clojure?

[Huge ramble to follow]

Clojure is a particularly interesting functional language for a python programmer IMO. It shares a number of asthetic and cultural properties with python that other lisps and other functional languages don't provide.

Syntactically they are approximately distantish cousins. Clojure's syntax is much more restricted that pythons (obviously ;) but more prominent than other the other big lisps. Of note there is literal support for Vectors (much closer to pythons lists than the functional singly linked list), Maps, Sets, and these are used in the special forms too. A comparison (lets use identical implementations of factorial - taking some liberties so that the code is actually semantically identical, There are more idiomatic versions down the thread)

  def fac(n):
      "A function to calculate factorial in python"
      return reduce(lambda x, y: x * y, range(1, n + 1))


  (defn fac 
      "A function to calculate factorial in clojure"
      [n]
      (reduce #(* %1 %2) (range 1 (+ n 1)))
In particular there is the vector in the form ([n]) used for the arguments list. The other thing to comment on is the funny looking #(* %1 %2) bit, thats an anonymous function/expression. There are two ways to write functions in clojure, that way and using a fn form. That same expression would look like

  (fn [x y] (* x y))
Clearly this becomes a matter of readability in most cases. Like python it means you have two ways to express a function. In this case you could actually just drop * in instead of the lambda, because it is just a symbol referencing a function like any other name. Python would require importing the operators library to do the same thing.

Both languages are quite opinionated about the right way to do things. You are probably familiar with pythons. Clojure has a strong philosophy behind it, but its still pragmatic. Clojure promotes pure functional programming wherever its possible, and provides an excellent range of tools to break out of that where needed.

Like Python, Clojure has good package management, good core data structures, lazy sequences (much stronger than pythons generators), quite a few batteries included (in particular if you consider clojure.contrib) though not as many as python.

So if there are so many similarities, why would you switch? A number of reasons have made me do more and more of my development in python rather than clojure.

First up i want to do more functional programming. Like many long time python programmers i started using functools and itertools, generators etc more and more, but functional style is not encouraged by certain parts of the community.

Secondly, concurrency. I've written a bit of concurrent code in python (usually in an actor style using the queue objects) but python is ill suited to this, Clojure's persistent datastructures are much stronger here. In addition there is no GIL so concurrent code is able to run fast, not just asynchronously. On top of this, clojures references types provide _many_ options for concurrency which often simplify your design considerably compared to writing a message passing thing in python.

Packaging and deployment is much better. If you are using a unix system http://github.com/technomancy/leiningen is a must get. This is a build tool that manages dependancies for you automatically. It integrates with the clojars.org repository. This pairing replaces pip/easy_install and the cheeseshop as well as tools like virtualenv.

The community is great.

If you want to get started, the following comment by hga might serve you well http://news.ycombinator.com/item?id=1033503 Rich Hickey's various presentations and lectures make a compelling case for the language, and teach you a lot about how to use it at the same time. Even if you never end up writing code in clojure, these videos will teach yo...

Oh, a couple other points:

Clojure is very fast. It generally runs quickly, but then you can profile and add a couple of type hints and watch it run about as fast as java.

It's still a dynamic language, but names can only be defined in specific forms (eg def, let etc). This means that the compiler pulls you up on referencing symbols that don't exist. This is a huge productivity win.

Clojure is actually one of the languages I've moved to, from Python, and is currently my favourite programming language to work in. Functional programming, immutable data structures, great built in data structure support, macros, excellent concurrency support, a good standard library and direct access to Java libraries all make Clojure a beautifully powerful and easy language to work in. The clojure community is also very friendly and growing every day, so if you need it, getting suppor is not hard.

I do still like Python, but theres so much more nice things out there. Besides clojure, I'm playing with Yeti and hope to give F# a look soon too. Maybe some day I'll have some time to play with Haskell also; its been on my todo list for a long time.

Ive dabbled in Haskell and F# myself; I found Haskell to be the amazing mind awakening experience people talk about, but it also frustrates the hell out of my sometimes. All the syntax around types confuses my simple brain.

F# on the other hand felt a lot like a functional python for .Net. Complete with the syntactic whitespace and a light weight class syntax that feels very similar to pythons classes (completely with explicit self).

Both worth exploring IMO. I've not look at yeti, so i'm going to check that out, thanks!

Thanks for the info!

Yeti is a small and simple ML-derived language for the JVM. I found it refreshingly simple (an afternoon with the tutorial and I felt comfortable with it, though I have yet to write anything "real" in it) and the "community" is quick to respond to queries (community is in quotes because theres only about five of us on the mailing list...). I plan on using Yeti as the "formula" language in a spreadsheet type program :-)

It all started with ProjectEuler :)
I'm constantly fighting an internal battle between functional programming and being more pythonic.

For example: I once rolled my own lisp style immutable list type using nested tuples, i.e. (1,(2,(3,None))) for a problem that they were particularly well suited. (http://en.wikipedia.org/wiki/Knapsack_problem#0-1_knapsack_p...) and got about a 10% speedup. In the end though I threw it out because it was far too ugly.

But I always prefer a def and a map to a for loop.

"But I always prefer a def and a map to a for loop."

For those I either go with a list comprehension or a generator expression.

^-- Hear hear.

I started getting pretty deep into the functools until I discovered list comprehensions and generators. You get all the concise goodness of the functools while remaining Pythonic. The list comprehension is a really good, intuitive syntax too, I think.

I had to google the windows one just to make sure it wasn't real.
Doesn't PEP 20 say that there should be only one way to do it? :-)
I know your question is a joke, but it is frequently asked in seriousness, so: No. Not at this granularity. Otherwise the python community would still be using plone, and Django would not exist. Or there would be only blocking (or non-blocking) io. And so on.
;; python programmer who reads HN and Proggit

(defn factorial [n] (reduce * (range 1 (inc n))))

  ;; Any programmer reading HN long enough to experiment with some lisp / clojure ;)
  (defn factorial [n]
    (apply * (range 1 (+ n 1))))
I was torn between those two formulations, but decided on the reduce because the academic purity of an implicit hylomorphism ;) However, your formulation is more idiomatic of a lispy solution.
I'm proud to be a Lazy Python Programmer... but not lazy enough to skip "What's New in Python 2.5":

    def factorial(x):
        return x * factorial(x-1) if x > 1 else 1
(comment deleted)

  # "close enough" programmer
  import math
  def fact(x):
    math.sqrt(2*math.pi*n) * math.pow(n/math.e, n)
  print fact(6)

  # lazy-er programmer
  def fact(x):
    factorials = {6:720} # found on my calculator, add more as they come up
    if factorials.has_key(x):
      return factorials[x]
    else:
      raise NotImplementedError
  print fact(6)
NotImplementedError - that kills me!
The "first year pascal" example has a metasyntax error. It's missing a "#end" token for symmetry with the C example.
Functional programmer:

    import operator
    def factorial(n):
        return reduce(operator.mul, xrange(1, n+1), 1)
    print factorial(6)
Cutting-edge programmer:

   import math
   print(math.factorial(6))
reduce is pretty much the same thing as foldl. The functional programmer is already included as "Expert Python Programmer"...
I believe this Gist is being updated as the thread unfolds.

ahem.

The difference is, the code given here actually works out of the box.
I would have done

    from math import factorial as fact
    print fact(6)
I'm ashamed to admit that I actually learnt something new from this (the @tailcall thing)
You should never be ashamed to admit ignorance, especially after it's been cured. :-)
wait, is @tailcall part of the Python standard library? or just something the author made-up for illustrative purposes?
I just tried typing it into the interpreter in 2.6 and 3, it doesn't appear to exist.
Web 2.0 programmer:

  import urllib
  import json

  def fact(n):
     res = urllib.urlopen('http://math.org/factorial/?' +
         urllib.urlencode({'n':n, 'format':'json'})).read()
     return json.loads(res)['answer']
  fact(6)
Edit: for a "web scale systems guy" throw an @memcache_memoize in there :)

Edit2: fixed a syntax error.

Edit3: general cased it. thanks lolcraft!

  {'n':6, 'format':'json'}
Shouldn't that be:

  {'n':n, 'format':'json'}
why write such a general case, YAGNI
More of a scotty principle type thing: when management comes by and wants to us to figure out combinations of 7 things, we can claim it will take 5 days, get it done in a 1 char fix, play games all week. Come monday morning's meeting, don't drink coffee before hand (to look tired), and claim that for a little extra work (and a looong weekend) you got it to work for combinations of ANY NUMBER of things! Worse that happens: you get credit for taking one for the team, best case: "take the week off, thanks for your heroics!"
If you happen to know of a place where you earnestly hear "take the week off, thanks for your heroics!", please don't be stingy with their URL. I'd be interested in working there.
Unfortunately most of the 'best-case' type things I mention are highly unrealistic. I'll let you know if I do hear something tho. :)
Mmm... It's more like "take forever off". You can efficienc-ize yourself right out of a position.
I actually got a week's worth of PTO after a little crunch time (a month or so) at the last startup I worked for. However, I don't believe they still exist in any substantial form anymore (and couldn't in good faith recommend them anyways, for reasons I don't believe I should go into).
Looks like you're still stuck in the old, boring Web 1.0
I am going to have to go with Lazier Python programmer
Java programmer:

  class FactorialCommand(object):
      def set_num(self, num):
          self.__num = num

      def get_num(self):
          return self.__num

      def execute(self):
          result = 1
          i = 2
          while i <= self.get_num():
              result = result * i
              i = i + 1
          return result

  cmd = FactorialCommand()
  cmd.set_num(6)
  print cmd.execute()
I thought the 'enterprise' programmer was the java programmer.
No, that's the crappy java programmer
So... The FactorialCommand one was the good Java programmer?
More like C# programmers. Java programmers would either not know how to solve this problem (the majority), or write the 3 line static method.

Sarcasm based on interviewing experience =P

I kind of miss an @memoized version
Bored Python programmer:

  def fact(l):
      return sum(map(bool,reduce(lambda I,l:''.join([l for I in I]),
                                 ['+'+'+'*l for l in xrange(l)])))
  assert fact(6)==720
I don't understand. What's wrong with the factorial function that comes with python?

    from math import factorial
done.
You can't amuse thousands of techies with an import from a math library..
But the 'Seasoned Hacker' from the original article does something likewise with the Hello, World program:

  % cc -o a.out ~/src/misc/hw/hw.c
  % a.out
;-)
http://www.willamette.edu/~fruehr/haskell/evolution.html

for all the closet functional programmers around here :)

That's the link I was looking for, I knew had seen this somewhere before. The Python one is entertaining, but the Haskell one is brilliant. "explicit type recursion with functors and catamorphisms", ha. I finally learned what a functor is a few days ago.
(comment deleted)
Where's the one where the Python programmer has to make something go fast and needs to write a C module?
That would be trickier than it looks. Run this in your python interpreter:

    reduce(lambda x, y: x * y, range(1, 100))
Replicating that in C is certainly possible but you're probably not going to do it quickly, unless you're already pretty deep into that sort of thing.
Clearly the answer is -1818210304. My C program told me that really quickly!
I stand corrected.
(comment deleted)
The "I find a way to use list comprehensions for everything" Python programmer:

  def fact(n):
      return eval('*'.join([str(x+1) for x in xrange(n)] + ['1']))
"I've got a lot of memory" or "runtime is more importatant than initialisation" programmer

    fact = init_fact()
    ...
    res = fact[x]
Python one-liner anyone?

    >>> reduce(int.__mul__, range(1,6))
    120
Range should go to 7 if we are doing factorial of 6.
Treat it as gamma function instead :)
Enterprise programmer made me laugh. Especially after spending a few days buried in SAML.