Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Unpythonic Python (skien.cc)
267 points by bluedino on April 9, 2014 | hide | past | favorite | 146 comments


When you write too much Haskell, your Python code starts to look like this:

    print('\n'.join(
        'FizzBuzz' if x%5==0 and x%3==0
        else 'Fizz' if x%3==0
        else 'Buzz' if x%5==0
        else str(x)
        for x in range(1, 101)))
I would really like to have a "let" expression in Python to avoid having to write a new function with a def statement when you could get away with a simple lambda or generator expression.


And when you write C carefully, the C code looks like this (thanks seanjensengrey and rhth54656 for ideas):

    int i; static char* a[] = { "%d\n", "Fizz\n", "Buzz\n", "FizzBuzz\n" };
    for ( i = 1; i < 101; i++ )
        printf( a[ (i%5==0)*2 + (i%3==0) ], i );
The loosely similar Python:

   for i in range( 1, 101 ):
        print( [ i,'Fizz','Buzz','FizzBuzz' ][ (i%5==0)*2 + (i%3==0) ] )


And my Visual C 6 compiles the above C to this x86 asm with a single conditional jump, just for the loop:

    mov	edi, DWORD PTR __imp__printf
    mov	esi, 1
   L1:
    mov	eax, esi
    cdq
    mov	ecx, 5
    idiv	ecx
    mov	eax, esi
    mov	ebx, 3
    push	esi
    mov	ecx, edx
    neg	ecx
    sbb	ecx, ecx
    cdq
    idiv	ebx
    inc	ecx
    neg	edx
    sbb	edx, edx
    inc	edx
    lea	edx, DWORD PTR [edx+ecx*2]
    mov	eax, DWORD PTR arr[edx*4]
    push	eax
    call	edi
    add	esp, 8
    inc	esi
    cmp	esi, 101
    jl	SHORT L1
The magic is in the neg sbb combination: The neg changes reg to two's complement but also sets or clears the CF if the argument was != 0 then sbb reg,reg effectively moves CF to the reg avoiding conditional jump for != 0.


Taking that a little further,

  const char *fb[][2] = {{"%d\n", "Fizz\n"}, {"Buzz\n", "FizzBuzz\n"}};
  int i;
  for (i = 1; i <= 100; ++i)
          printf(fb[i % 5 == 0][i % 3 == 0], i);
(It's a pity we have to specify the second dimension manually . . .)


In the generator case you can define a poor man's let like this:

    def let(x):
        yield x
And use it by "iterating":

    ...
    for x in range(1, 101)
    for divisible_by_5 in let(x % 5 == 0)
Still not as nice as having actual syntax for it.


You can also hack the with statement to get a let block:

    import contextlib

    @contextlib.contextmanager
    def let(*values):
        yield values

    with let(1, 2, 3) as (a, b, c):
        print(a, b, c)


I also tend to wrap loops in expressions like that. Then, in almost every interesting loop, I suddenly want to log something or add intermediary computation, and have to refactor into the good old boring for loop.


Pipeline your generator through a logging generator :)


"let = lambda" would be the same thing, wouldn't it?


Yes, but in an incredibly verbose way. And a simple let->lambda conversion can't express things that Scheme's let* or letrec expressions let you do (in Haskell, a "let" or "where" expression is a "letrec").


    >>> let = lambda
      File "<stdin>", line 1
        let = lambda
               ^
    SyntaxError: invalid syntax
Am I misunderstanding you?


>>> let = lambda x: 2*x

>>> print let(4)

8

Edit: Awesome, downvoted for helping.


That's not what they mean. The usage they are discussing is more like this, I believe. In a functional context, instead of doing:

    print expensive_computation(), expensive_computation()
You can do:

    (lambda x: print x, x)(expensive_computation())
Which would be equivalent to, with an imaginary let syntax:

    (let x be expensive_computation(): print x, x)


Julia:

print([(x%3==0) && (x%5==0) ? "FizzBuzz" : (x%3==0) ? "Fizz" : (x%5==0) ? "Buzz" : x for x in 1:100])


Cool!


I like this one. I don't know enough Haskell to have come up with it on my own (but I should!)


A highly Pythonic, Easier to Ask Forgiveness than Permission[1] version:

    FIZZ=3
    BUZZ=5
    cache = {}
    
    for i in range(FIZZ-1, FIZZ*BUZZ, FIZZ):
        cache[i] = 'Fizz'
        
    for i in range(BUZZ-1, FIZZ*BUZZ, BUZZ):
        try:
            cache[i] += 'Buzz'
        except KeyError:
            cache[i] = 'Buzz'
            
    for i in range(100):
        try:
            print cache[i%(FIZZ*BUZZ)]
        except KeyError:
            print i+1
[1] https://docs.python.org/2/glossary.html#term-eafp

A generator version:

    from itertools import izip, islice
    
    def fizzes():
        i=0
        while True:
            yield '' if i%3 else 'Fizz'
            i += 1
        
    def buzzes():
        i=0
        while True:
            yield '' if i%5 else 'Buzz'
            i += 1
        
    def numbers():
        i=0
        while True:
            yield str(i+1) if i%3 and i%5 else ''
            i += 1
            
    print "\n".join("".join(parts) for parts in islice(izip(fizzes(), buzzes(), numbers()), 100))


Or better yet, don't even bother asking for forgiveness or permission:

    from collections import defaultdict
    FIZZ=3
    BUZZ=5
    cache = defaultdict(str)
 
    for i in xrange(FIZZ-1, FIZZ*BUZZ, FIZZ):
        cache[i] = 'Fizz'
     
    for i in xrange(BUZZ-1, FIZZ*BUZZ, BUZZ):
        cache[i] += 'Buzz'
 
    for i in xrange(100):
        print cache.get(i%(FIZZ*BUZZ), i+1)
But I'm rather partial to the generator versions you and others posted.


I like these. Another generator version:

  def fbgen(text, divisor):
      while True:
          for i in range(1, divisor):
              yield ""
          yield text

  def derrangedBuzz(max):
      fizzer = fbgen("Fizz", 3)
      buzzer = fbgen("Buzz", 5)

      for i in range(1, max + 1):
          s = fizzer.next() + buzzer.next()
          
          if s == "":
              print i
          else:
              print s


One of the solutions in the comments I found quite pythonic and concise. Somehow people have it in their heads that "Pythonic" means long-winded. And yes, you have to read the code and think for a second to understand it, but that's no crime.

  [(not x % 3) * 'Fizz' + (not x % 5) * 'Buzz' or x for x in range(1, 101)]


Things taking longer to read and understand is perhaps the central crime of unmaintainable code, no matter how concise otherwise.


To quote Brian Kernighan, "Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it?"


I think this code is easier to read than the more verbose 12-line version given in the article. It takes longer to read per line, but less time total.


It's not just more complexity per line, it's also a higher level of complexity, using language-specific features that people who aren't fluent in python wouldn't be familiar with (multiplying a string by a boolean)


I'm fairly new to Python, though not to software development, and one of the nice things I find about Python is that when I see something I haven't seen before (in this case multiplying a string by a boolean) I can usually guess correctly what it will do and spend a few seconds with the REPL to confirm.

Of course, this is true to a certain extent of all programming languages, but I do find Python particularly easy in this respect.


By that logic, no one should write anything in idiomatic French because anyone who isn't fluent in French wouldn't be able to read it.


Well, that example is a bit different. You're ignoring who the audience is. When writing code, the audience is usually at least people on the same team, if not the person writing in the first place.

If writing in French for people who are not fluent, I think it would be a good idea to avoid idiomatic language.


It's not different. The audience in this case is people who are fluent in Python. Saying that code sample is bad is like saying Baudelaire is bad because only people fluent in French can read it.


I was curious about that. Is multiplying a string by a boolean idiomatic Python? I don't write nearly enough Python to know, but it strikes me that this might be more like writing French using lots of obscure words.


This starts to get into "what is idiomatic python?" which changes as the language evolves. For example, before Python had an official ternary form, this was a common idiom:

    account.status = ["paid", "unpaid"][amount_due > 0]
This does the same thing as the FizzBuzz example, coercing a bool to int. Here the int is used as an index into the list of the two strings.

Personally, I found this handy and liked it a lot. Others didn't and now there is this, which isn't bad:

   account.status = "unpaid" if amount_due > 0 else "paid"

Maybe it's less like using obscure French and more like speaking in a slightly different dialect, or in a different region with different cultural references.


Multiplying a string by an integer is fine.

Treating a boolean as an integer is iffy

Multiplying a string by a boolean frankly should be a no-no.


This way's easier to read:

    ['FizzBuzz' if 0 == n % 15 else 'Fizz' if 0 == n % 3
        else 'Buzz' if 0 == n % 5 else str(n) for n in range(1,101)]


Very nice.

If you make the generator always return a string, then you can make it print, thus:

    print '\n'.join((not x % 3) * 'Fizz' + (not x % 5) * 'Buzz' or str(x) for x in range(1, 101))


I like the solution, but I usually keep "The Zen of Python" in mind when writing 'Pythonic' code.


I've programmed Python before but I had to fire up a REPL to know that:

    True * "String"
    >"String"
And...

    not 0
    >True
I guess knowing the "truthiness" of all regular Python types is useful.


[concat $ replicate (fromEnum $ x `mod` 3 == 0) "Fizz" ++ replicate (fromEnum $ x `mod` 5 == 0) "Buzz" | x <- [1..101]]

or

let f = (replicate . fromEnum . (==0)) .: mod in [concat $ f x 3 "Fizz" ++ f x 5 "Buzz" | x <- [1..101]]



https://gist.github.com/seanjensengrey/d053e7fa709e0699e291

If free version.

    t = {}
    t[0,0] = lambda x: x
    t[1,0] = lambda x: "Fizz"
    t[0,1] = lambda x: "Buzz"
    t[1,1] = lambda x: "FizzBuzz"
    
    def tests(x):
        return (x % 3 == 0, x % 5 == 0)
    
    for x in range(1,101):
        print t[tests(x)](x)


Good idea. Enhancing:

If, lambda, logical operators except == and string concatenation free version (Python 3)

    for x in range( 1, 101 ):
        print( [ x,'Buzz','Fizz','FizzBuzz' ][ (x%3==0)*2 + (x%5==0) ] )


And also C based on the same idea as my Python (but this has to ? for 0s):

    int i;
    char* a[] = { 0, "Buzz", "Fizz", "FizzBuzz" };
    char* f[] = { "%s\n", "%d\n" };
    for ( i = 1; i < 101; i++ ) {
        char* s = a[ (i%3==0)*2 + (i%5==0) ];
        printf( f[!s], s ? s : i );
    }


Don't ruin that version with an if statement.

Use this and avoid it( and the second array as well ):

  char * a[] = { "%d\n" , "Fizz\n" , "Buzz\n" , "FizzBuzz\n" } ;


Brilliant, thanks! The C version is now:

    int i; char* a[] = { "%d\n", "Fizz\n", "Buzz\n", "FizzBuzz\n" };
    for ( i = 1; i < 101; i++ )
        printf( a[ (i%5==0)*2 + (i%3==0) ], i );


Reminds me of "Evolution of a Python Programmer" https://gist.github.com/fmeyer/289467 ... seems like I've perhaps seen other versions of this?



This was what one of our Java coworkers wrote a while back: https://gist.github.com/1337/8155054


That kind of code could make sense when you're using a very opinionated API, that is designed (for better or worse) with patterns in mind, such as Android. But, when you start bringing that style of coding outside of that environment...

Yuck.


I don't think you need to even explicity say he's used to Java.

Wow... I've never felt the need to the use the factory technique.


I use factories a lot when using Django... But, of course, in Python they are functions that return a class, not classes.

Interfaces instead are completely unpythonic. Or, maybe I should call them antipythonic?


It won't work on py3 because map is a generator. Tell him to use list comprehensions:

  [setattr(self, x, kwargs[x]) for x in kwargs.keys()]
Though of course that is a bit too slow and he should do

  self.__dict__.update(**kwargs)
or for maximum correctness

  import os; os.remove(__file__)


At least they followed the snake_case name convention for method names (albeit getters) ;)


Playing code golf with Python, this is the shortest I could get:

https://gist.github.com/tghw/3702360

Definitely a little unpythonic.


Something annoying about python is that the word "lambda" is so long for what are supposed to be one-off functions.

You have

  f=lambda x,y=1,a='Fizz',b='Buzz': ...
But it's actually shorter to say

  def f(x,y=1,a='Fizz',b='Buzz'): ...
I much prefer Haskell's

  \x -> x
Style lambdas.


I generally don't particularly like giving punctuation meaning that, well, isn't punctuating. The bottleneck when writing code is almost never keypresses.

I think CoffeeScript gets it probably the most right of languages I've worked with, in that the choice of punctuation makes intuitive sense... "Hey! It's an Arrow. It goes from here to here".

FWIW, I don't like the word "lambda" either... Naming things with one letter are generally a bad idea that we'd do better to divest ourselves of, but there is a bit of legacy to deal with. Either way, they make a field (and statistics is a major offender here, with p-values and t-tests and whatnot), terribly inaccessible.


So what about the '*' in C or even better the '.' in so many object oriented language.

> The bottleneck when writing code is almost never keypresses.

No, it's readability and that often comes with terseness. Every line break because I have to spell out lambda or every refactoring that removes the function from its original context so I can avoid a line break is bad for readability. In that aspect the '\' in Haskell does great. Also in Haskell anonymous functions are so important that they definitely deserve their own special character to shorten many expressions.

I only see this becoming a problem if it is used in excess, like in C++ and especially in C++11.


> So what about the '*' in C

I don't like it... I don't what I'd do if starting from scratch, and there might not be better, but it definitely causes readability pain.

> the '.' in so many object oriented language

I have less of a problem with this, because there's some non-programming analog to be found (Section 1.1, Article 3.2, etc.). That said, I think, at some point, it's harmful to OOP in that it makes it hard to sort out properties and messages, and the roles of one or the other.

I agree 100% on readability - the problem for me comes when words get mapped onto abbreviations and symbols that are almost entirely constructed and/or alien to most readers.


The reasoning behind using '\' for lambda in Haskell was because it sort of looks like a lambda character ( λ vs \ ) if you squint hard enough.


I wonder if that explains the Ballmer peak...


That's just horrible. I don't know what more to say about it than that. How did anyone think this would be a good idea on balance?


When you're writing Haskell in emacs (like you should be), you enable haskell-font-lock-symbols in haskell-mode, and it displays the lambda as it should be (plus a bunch of other symbol corrections for ::, ->, =>, (), ||, &&, etc.)

Full list here: https://github.com/haskell/haskell-mode/blob/master/haskell-...


Mmm I suppose it's really just preference. I love that syntax. But I guess there's no arguing about taste.


Well, it's typing-friendly but not (re)learning-friendly. I guess it depends how you weigh those concerns.


It's also very reading friendly.

I normally forgive languages being hard to learn if the bring enough utility.


I cannot agree enough. Someone give me a call when a Haskell-like language with readable syntax appears. I really like the ideas behind Haskell, but the syntax is so unfriendly that I cannot be bothered to really start using it. Less special characters, please.


There really aren't that many special characters (certainly no requirement for non-ascii) in the core language - perhaps the sin is allowing almost unlimited user defined operators in code, which leads to monstrosities like ekmett's lens infix operators: http://hackage.haskell.org/package/lens-4.1.2/docs/Control-L...

As a lisper, I prefer names and prefix operators - there's a few exceptions where infix operators add improvements to the language, but I dislike having user-defined operators (they make searching a pain, although Hayoo eases some of that).


I really like scheme & clojure and I think I have done a lot more scheme and clojure than haskell. (And even a alot more of Python). However, I think that Haskell by itself has a great syntax (with some legacy cruft, granted).

What is really great is how Haskell enables you to write extremely succinct code by providing powerful abstractions and tools. The fact that you have a type annotation already gives enough meta information in the code that you often can omit a long name. The fact that Haskell functions tend to be short in lines gives you something that is closer to an equation than a command language.

I don't know how to put this in words, but I'll try: Naming things well in programming is the most difficult task after mastering the very basics. I think this is because names are not fundamental for algorithms and programs but are like bookmarks for the programmer and their human brain. In C, a function with one-letter argument names is a nightmare, in Haskell, it actually improves readablity over a verbose version with whole-word names. And then, I have seen a lot of functions that were named very specific in terms of a problem the programmer tried to solve at the time, that however where quite generic, or could have been very generic (think of `sort_customers_by_name()` instead of a `sort_by()`.

I share your dislike of extreme operator usage. It is a problem that whatever permutation of +-!@#! are used as operators in libraries for functionality that the user rarely needs. But the general approach of haskell for succinctness is a good one.


I have very limited familiarity with Haskell, but I find the syntax pretty clean and readable - I spend most of my time getting my head around functional/lazy/etc semantics, which make my head hurt (in a good way) - that presumably implies that the syntax is successfully exposing those semantics to my poor OO/duck-typing coddled brain.

I suppose these things are a matter of taste as much as anything else. But when people talk about a Haskell program being 'elegant', I never think to myself "what, that mess?"


> But it's actually shorter

It's not: with def() you have to explicitly write return, while with lambda it is implicit.


You don't need a return, just a print (since we are doing FizzBuzz).

For tghw's solution to work you'd have to have a print outside of the function call (since you can't print from a lambda). With the def, you can print inside of the function (and don't need a return, since you're just printing).


A minor quibble, but in Python 3 you can print in a lambda because print is no longer a keyword.


As a non-Python 3 user, I just opened up the python 3 REPL to try something I always find myself wanting to do in tiny little python scripts:

  map(print, some_list)
Unfortunately, it returned a map object, which I guess is also new in Python 3 (I assume it's a lazy application device).


You can (ab)use iterable unpacking in Py3k, now that print's a real function:

    print(*[1,2,3], sep='\n')


I use this function to force evaluation of elements in a generator:

    def do(gen):
       for x in gen:
          pass
It evaluates all elements of a generator with storing them in memory. If you don't mind generating some garbage, you can just use the list function instead.


Use `list()` to force eager evaluation with Python 3 map / filter.


Yeah, the map builtin is essentially itertools.imap in python 3.


For python golf, exec and string multiplication is usually a good strategy:

https://twitter.com/jooon/status/25054586175

But that isn't a whole lot shorter than the solution pcmonk posted in the thread.


The jury is still out on whether this is a good thing or not.

IMHO, the objective of the crippled `lambda` really is to make the programmer refactor into reusable functions instead of having λs littered everywhere, which would hurt maintainability.


One of the most effective ways to hurt maintainability of code written in any given programming language is to try to make some language features artificially awkward to use in the hope that programmers will then do something else. When has that ever worked?

IMHO, if a feature is useful enough to have in the language, it deserves a good implementation. If it isn't, it shouldn't be there at all. And if it is useful sometimes but doesn't fit well in other situations, providing better alternatives in those situations is a more effective way to avoid dubious code than just artificially crippling the entire feature to discourage its use.


So what's if it's shorter. You'll run out of screen? You'll wear down your keyboard?

If you don't like typing it, have a macro. Otherwise, as Objective C shows, the verbosity of code is not relevant at all. It's what it says and what it does, which is.


You realise the equivilent Objective-C syntax is ^{} right?

And access modifiers are + and - rather than static and nonstatic.

Objective-C definitely isn't above using lightweight syntax. Where it favours verbosity is APIs.


I realize it, right.

But I hoped you'd see beyond the direct comparison of lambdas with Objective C's blocks.

I'm saying that short code doesn't automatically translate to more readable or better code, Objective C's message syntax is the proof (if I have to be painfully specific about it).

I write a lot of JS and typing out "function" or "return" was never on the list of things I found a problem, despite I also work in C#, which uses the short => variation.


The parent wasn't saying code should be short, they were saying the syntax for lambdas should be short.

Yes, short code doesn't automatically translate to readible code. But neither does long code.

You can't wheel out objective-c's fondness for long self-documenting message names as self-evident proof that the syntax for lambdas must be verbose.

Long message names are good because they let you clearly describe what is otherwise a big black box of unknown behaviour.

The syntax for a lambda will always be a lambda, so it doesn't need to be spelt out explicitly each time. Shorter syntaxes such as used by Haskell are easier to visually pattern match on and so can actually aid comprehension.

It's not as simple as longer is always better and anyone who disagrees is obviously foolish and lazy.


In the comments, someone gave this nice solution:

  for x in range(100):
    print x%3/2*'Fizz'+x%5/4*'Buzz' or x+1


That's more like it! First time I heard about Fizzbuzz, I solved it in PHP. I stay amazed at the 100 lines solutions.

for ($i = 1; $i <= 100; $i++) {

    $str = str_repeat('Fizz', !($i%3)&1) . str_repeat('Buzz', !($i%5)&1);

    echo $str ?  "$str\n" : "$i\n";

}


Shorter and more pythonic, but not one per line:

' '.join(["FizzBuzz" if n%15==0 else "Fizz" if n%3==0 else "Buzz" if n%5==0 else str(n) for n in range(1,101)])


join on '\n' instead of ''. Problem solved.


Here's mine:

['Fizz' * (not bool(i % 3)) + 'Buzz' * (not bool(i % 5)) for i in xrange(1,101) if i % 3 == 0 or i % 5==0]

EDIT: I hate lambdas. Also I'm not saying the above is pretty or a good idea, but I had some fun.


Mine with some itertools abuse :)

from itertools import cycle , izip

[(f + b or x) for f, b, x in izip(cycle([''] * 2 + ['Fizz']), cycle([''] * 4 + ['Buzz']), range(1, 100))]

Edit: not sure how to post code in comments. e.g. * is lost


Nicely done.

> Edit: not sure how to post code in comments. e.g. * is lost

Put a couple of blanks before each line. This displays it in a monospace font, too.


Mine is shorter i believe? https://gist.github.com/Foxboron/6643154


Nobody ever seems to go for the general solution:

words = ( (3, 'Fizz'), (5, 'Buzz') )

def fizzbuzz(num): for value, word in words: if i % value == 0: yield word

for i in range(1, 101): print ''.join(fizzbuzz(i)) or i


It works even though it should be:

    words = ((3, 'Fizz'), (5, 'Buzz'))


    def fizzbuzz(num):
        for value, word in words:
            if num % value == 0:
                yield word

    for i in range(1, 101):
        print ''.join(fizzbuzz(i)) or i


I think a list comprehension reads better than a generator (and works the same) in this case:

  def fizzbuzz(num):
      return (word for value, word in words if num % value == 0)
And even dropping the fizzbuzz function altogether reads quite nicely IMHO, though it starts to look a bit golfed:

  words = ((3, 'Fizz'), (5, 'Buzz'))

  for i in range(1, 101):
      print ''.join(s for n, s in words if i % n == 0) or i


Ah. Thanks for pointing that out! Interesting quirk with shared global scope!


Java doesn't have to be written like that you know. Idiomatic code is overrated in my opinion. Make it readable and correct, fuck the rest.


A reminder that Python generator functions let you use multiple yields.

    from __future__ import print_function
    
    
    def fizzbuzzify(integers):
        for i in integers:
            if i % 15 == 0:
                yield 'Fizbuzz'
            elif i % 3 == 0:
                yield 'Fizz'
            elif i % 5 == 0:
                yield 'Buzz'
            else:
                yield str(i)
    
    
    print(', '.join(fizzbuzzify(range(1, 101))))
    
    for i in fizzbuzzify(range(1, 101)):
        print(i)


My short yet readable Python version:

    for i in range(1,101):
        if not i % 15: print 'FizzBuzz'
        elif not i % 5: print 'Buzz'
        elif not i % 3: print 'Fizz'
        else: print i
The same in Bash:

    for i in {1..100}
    do
        let "$i % 15" || { echo "FizzBuzz"; continue; }
        let "$i % 5" || { echo "Buzz"; continue; }
        let "$i % 3" || { echo "Fizz"; continue; }
        echo $i
    done


Here's one in Hy (a homoiconic frontend to Python... it really is just Python™):

   (require hy.contrib.anaphoric)
  
   (ap-each (range 1 101)
    (print (cond [(= (% it 15) 0) "Fizzbuzz"]
                 [(= (% it 5) 0) "Buzz"]
                 [(= (% it 3) 0) "Fizz"]
                 [True it])))
Reads pretty good too, doesn't it?

http://docs.hylang.org/en/latest/


    #include <stdlib.h>
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/mman.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    static char c[9];
    
    int p(int i)
    {
        putchar(c[i++]);
        putchar(c[i++]);
        putchar(c[i+(7-i)]);
        putchar(c[i+(8-i)]);
        return 0;
    }
    
    int f(int i, int x) {
        i -= x;
        if(!i) { return p(x); }
        if(i<0) return i+x;
        return x + (f(i,x)  ?: - x);
    }
    
    int d(int a, int b)
    {
        return a-b?d(--a,b)+1:0;
    }
    
    void x(int i)
    {
        if(f(i,3)&f(i,5))printf("%d",i);
        printf("\n");
    }
    
    int i( int c, int target, void (*fn)(int i) )
    {
        return d(target+1,c)?({ fn(c); i(++c,target,fn); }):0;
    }
    
    int main( int argc, char **argv )
    {
        int fd=open(argv[0], O_RDONLY);
        char *m=mmap(NULL,20000,PROT_READ,MAP_PRIVATE,fd,0);
        c[3] = (char)(0x20|m[3]);
        c[4] = m[342];
        c[5] = m[343];
        c[6] = m[351];
        c[8] = c[7] = (char)(((0x38|m[1])<<1)&~0x80);
        i(1,atoi(argv[1]),&x);
        return 0;
    }


This'd be more fun if it didn't segfault

    printf(n%15 ? n%3 ? n%5 ? "%d\n" : "Buzz\n" : "Fizz\n" : "FizzBuzz\n", n);


Probably segfaults with the shitty ELF hackery :(


Since we are talking about crazy python fizzbuzz, allow me to share a creating I have had sitting around for a while:

    def fbg(s,r):print("\n".join(map(lambda x:str(x[1])if x[0]==''else x[0],zip(("".join(a for a,b in s if n%b==0)for n in range(1,r+1)),range(1,r+1)))))
    fbg((('Fizz',3),('Buzz',5)),100)
Cause, you know, fizzbuzz one-liners need to work for the generic case.


This problem is like Project Euler #1. You don't strictly need to divide. I prefer to skip along the array and put in the new values.

  n,f,b= 100,3,5
  a = [str(i) for i in range(1,n+1)]
  for i in range(n/f):
      a[(i+1)*(f)-1] = 'Fizz'
  for i in range(n/b):
      a[(i+1)*(b)-1] = 'Buzz'
  for i in range(n/(f*b)):
      a[(i+1)*(f*b)-1] = 'FizzBuzz'



Doesn't even touch on my personal pet peeve, people who don't use list and dict literals. I assume they're former Java programmers who got ahold of enough python knowledge to be dangerous. e.g:

  x = dict()
  x['a'] = 'string'
  x['b'] = list()
  x['b'].append('foo')
  x['b'].append('bar')


You can say

    x = dict(a = 'string', b = list(('foo', 'bar')))


Literals are much more readable in any language I've used (or at least can think of right now).


The value in FizzBuzz is the iteration process.

What's the first step? Well, you probably make a stream of numbers. And then a set of if blocks to test and return strings. Why not keep going?

What happens if you want more fizz buzz strings? Does the giant if-or statement seem a little unwieldy? Okay, pull the rules out and see if that's better. Is it easier to test now that it's a function and not a little stateful object? Do you want your fizzbuzz function to concatenate the strings or use explicit replacement? Can you make a switch for that? And so on.

That stuff only scratches the surface. I'm sure there's some brain burning fizz-buzz interviewers out there. It really puts you on the spot to deal with a stateful program.

One thing that seems really weird to me is this: given the first set of rules, why does almost everyone write the program that is the least extensible? Is it the way the question is phrased or scar tissue from imperative programming?


YAGNI.


Since we're all sharing our fizzbuzzes, here's mine (from my blog http://seriously.dontusethiscode.com/2013/04/29/bad-intervie...)

Note that this solution is generalised for any divisors and generates an infinite sequence.

    from itertools import chain, combinations, count
    from operator import mul, add
    fizzbuzz = lambda terms: (lambda terms: ({x%d:w for d,w in terms}.get(0,str(x)) for x in count(1)))(tuple((lambda (d,w):(reduce(mul,d),reduce(add,w)))(zip(*x)) for x in chain.from_iterable(combinations(sorted(terms.iteritems()),s) for s in xrange(1,len(terms)+1))))

    terms = {3:'fizz', 5:'buzz', 7:'baz'}

    from itertools import islice
    print list(islice(fizzbuzz(terms),None,25))


Much better, you didn't have to do manage 15, 35, 21, 105, etc.


I'm not a Java developer, but it seems that the "Javacious Python" example isn't very Javacious.

it looks like the author was trying really-really-really hard to prove a point, thus turned a single function into an OOP architecture.

I know that Java is known for bloat, but that's a bit too much of an exageration


Neat! I'd be interested in seeing pythonic solutions written in other languages (to the extent that those languages may allow 'Pythonic' style), too. I find it fascinating to see how certain languages will, for one reason or another, trend towards certain design patterns and styles.


Actually, most Python I write (influence from reading experienced programmers) tends to the last one, although it's semi-jokingly:

    def fizzbuzz(n):
        return 'FizzBuzz' if n % 3 == 0 and n % 5 == 0 else None

    def fizz(n):
        return 'Fizz' if n % 3 == 0 else None

    def buzz(n):
        return 'Buzz' if n % 5 == 0 else None

    def fizz_andor_maybenot_buzz(n):
        print fizzbuzz(n) or fizz(n) or buzz(n) or str(n)

    map(fizz_andor_maybenot_buzz, xrange(1, 101))

It's pleasing to use HFOs in Python, as long as you don't abuse lambdas. Also, some functional types like `defaultdict` can be used to describe code/business logic with datastructures rather than a bunch of if's, keeping things tidy.


I use defaultdict all the time. Very often when describing graphs.

  g = defaultdict(dict)
Allows you to do

  g[node1][node2] = edge_weight
without checking if node1 exists, and if not, saying g[node1] = {}

Also a neat trick (of dubious use) is:

  def auto_tree(): return defaultdict(auto_tree)
Gives you infinitely nested defaultdicts.


defaultdict is really multipurpose, quick trees is only one of the neat tricks. I like the following definition :)

    >>> Tree = lambda: defaultdict(Tree)


I'm trying very hard to write Python in VB.Net at my job. But I've not been very successful, Python is very flexible.


Two more variants. The first is precomputed without code-based initialization:

  fizzbuzz = ['FizzBuzz', None, None, 'Fizz', None, 'Buzz', 'Fizz', None,
              None, 'Fizz', 'Buzz', None, 'Fizz', None, None]
  for x in xrange(1, 101):
    print fizzbuzz[x % 15] or x
The second is unique in that there are no conditionals at all. (Not efficient, especially for large numbers)

  fizzbuzz = ['FizzBuzz', 1, 1, 'Fizz    ', 1, 'Buzz    ', 'Fizz    ',
              1, 1, 'Fizz    ', 'Buzz    ', 1, 'Fizz    ', 1, 1]
  for x in xrange(1, 101):
    print str(fizzbuzz[x % 15] * x)[:8]


My for-real-not-humor implementation:

    def fizzbuzz(i, n):
        while i <= n:
            yield i%15 and (i%5 and (i%3 and i or 'fizz') or 'buzz') or 'fizzbuzz'
            i += 1

    for x in fizzbuzz(1, 100):
        print x


Tight, but I'd still use multiple yields, all the conditions in the one liner may be difficult to read.


real oldschool, since you don't use the ternary if that's available since Python 2.5.


There's something minor that's always bothered me about the usual description of FizzBuzz:

> If the number is divisible by 3, print Fizz instead of the number. If it’s divisible by 5, print Buzz. If it’s divisible by both 3 and 5, print FizzBuzz.

In a strict interpretation, the first two sentences could be seen as incorrect. If a number is divisible by 3, you cannot just print 'Fizz' and move on. You also have to check if it's divisible by 5.


The description is declarative, there is nothing implied about "moving on".


The particular form of the description at issue can be interpreted (arguably, is most naturally interpreted) to direct a different outcome than is usually expected from FizzBuzz, to wit, it directs that on numbers divisible by 15 "Fizz", "Buzz", and "FizzBuzz" all should be printed, rather than just the last.


The description is underspecified, no surprise there, but that's different from claiming it's incorrect. As far as its purpose as an interview question goes noticing this interpretation would probably be seen as a good sign.


If it can be satisfied in a way that is materially different from what was intended, then it is both under-specified and incorrect. This is a not-uncommon source of errors.

Natural language can be used with precision, and this is an important skill for engineers. Being able to identify ambiguity and inconsistency is an important part of that skill so yes, noticing it within a question should count in favor of the candidate. Dismissing it as being pedantic is the wrong response, because if you are working on something critical (secure communications software, for example) you need to handle ideas with precision.


This is why the description is good.

Sure, it tests whether you can write a set of statements a computer can understand.

But it also tests whether you can understand the intent behind a set of statements a human would make, without going on a diatribe about how the definition is not good enough.

After all, if English was a formal strict language where only one right way existed to express something, we wouldn't need programmers, would we?


> After all, if English was a formal strict language where only one right way existed to express something, we wouldn't need programmers, would we?

If you just solved the fact that one meaning can have many expressions, we'd still need programmers (and, more relevantly, system analysts) just as much.

The relevant problem is that English isn't a formal strict language where a particular expression can only have one meaning (and, more importantly, that, people don't use it that way even when it superficially seems to be.)

That is, the problem that requires specialized work to develop unambiguous requirements for the implementation of (among other things) information systems isn't that English maps (many expressions) -> (one meaning), but that it maps (one expression) -> (many meanings).


I think you could have made this point without subtly referring to my post as a "diatribe." I'm more than aware of what the intended interpretation is. Posting what I felt was a very minor and amusing observation hardly constitutes a "diatribe."

> After all, if English was a formal strict language where only one right way existed to express something, we wouldn't need programmers, would we?

This is very off-topic, but I'm not sure I agree with it. You're assuming that it would be easy to find the one unique way to express a given computation such that anybody could write it down. Even if English had this uniqueness property, I don't think that would be true at all.


We used to have ADA-TRAN code at work. Fortran code migrated to Ada. It was awful, but it worked so we left it.

It been commented the Perl I write, it written like C programmer.


JS version for funsies. I didn't like the idea of specifically checking for simultaneous mod3 and mod5, so I made this.

  for (i=1; i<101; i++) {
  	var result = "";
  	if(i%3 == 0)
  		result += "Fizz";
  	if(i%5 == 0) 
  		result += "Buzz";
  	if(result.length == 0)
  		result = i;
  	document.write(result+"<br>");
  }


Ugly version: for(i=1;i<101;i++)console.log((i%3?"":"fizz")+(i%5?"":"buzz")||i)


C#

Enumerable.Range(1, 100).ToList().ForEach(a =>{if (a%5 == 0 && a%3 == 0){Console.WriteLine("FizzBuzz");}else if (a%3 == 0){Console.WriteLine("Fizz");}else if (a%5 == 0){Console.WriteLine("Buzz");}else{Console.WriteLine(a);}});


The superfluous semicolons on line endings in the C example gave me a chuckle.


He forgot one on the "i += 1" (which would be i++ in a for loop but Python doesn't have that operator).

But that whole line is weird, because I think the C example should use a "for" loop, not increment the main counter at the top of a while loop, even if it has to use "for i in range(1, 101)" like in pythonic python. A C programmer like me (who loves python too) would immediately think "for (i = 1; i <= 100; i++)" for that (although counting from 1 is strange, it's what the problem asks for).


This is what I originally had but I felt that the Python `while` was actually a bit more true to the way a C for loop is constructed (and `range` seems a very not C thing to do.) It's not perfect!


Heh, in the C version I wish that "value = str(i);" was replaced with "value = "%d" % (i);"

Format strings feel like C. And not the fun parts of C.


    [print(("Fizz" * (n % 3 == 0) + "Buzz" * (n % 5 == 0) + str(n) * (0<(n % 3 * n % 5)))) for n in list(range(1,101))]
side effects don't matter right?


i loved this; studying multiple implementations of the same recipe, even if most are not intended to be "exemplary" but rather cautionary, is a great way to learn.

This reminds me of a similar effort called "evolution of a python programmer" and published in this gist:

https://gist.github.com/ghoseb/25049

something like 30 different implementations of factorial; my favorites are the 'expert programmer' and the "web designer"


for i in range(1, 101): print (i if i%3 else "Fizz") if i%5 else "Buzz" if i%15 else "FizzBuzz"

[edit: proper place https://news.ycombinator.com/item?id=7564988]


+1 for the pythonic version -1 for the weird rest

this assures me that python is the right language for me :)


Programming language accents.


Not enough factories in the java-ic python...


There's no honest attempt to explain the philosophy behind every language with real-world examples in Python. It's just childish jokes.

It's the equivalent of saying "Ze fish in le river" is "Frenchish English". Ha ha, stupid French people, right?

It's easy to make fun of programming languages like this, but what does that teach us? Aside from to mock what is different than what we use right now?


While I wrote this with tongue in cheek, I also aimed to illuminate the power of Python's flexibility along with the inherent danger therein. I do admit the Javacious example was over the top though ;)


Yes, it's a joke. I know it's against the guidelines of this site, but it's quite a nice joke.


As any French person will tell you, it should be "Ze fish in la river".




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: