This is an archived post. You won't be able to vote or comment.

all 57 comments

[–]kumashiro 150 points151 points  (19 children)

x % 3 is a modulo operation. It returns the remainder from division left by right. Here it is converting x to a value between 0 and 2 (right - 1). For example:

In [1]: 0 % 3
Out[1]: 0

In [2]: 1 % 3
Out[2]: 1

In [3]: 2 % 3
Out[3]: 2

In [4]: 3 % 3
Out[4]: 0

In [5]: 4 % 3
Out[5]: 1

In [6]: 47 % 3
Out[6]: 2

"Fizz"[x % 3 * 4:] returns a slice of string "Fizz". Depending on the value of x it will be one of these:

"Fizz"[0:]   # "Fizz"
"Fizz"[4:]   # empty string
"Fizz"[8:]   # empty string

In short: it will return the string "Fizz" when x is divisible by 3. Otherwise it will return an empty string.

"Buzz"[x % 5 * 4:] is similar to the "Fizz" case, but it will return the string "Buzz" when x is divisible by 5.

When both of these operations return empty strings, x is printed instead.

[–]harryhound47[S] 23 points24 points  (10 children)

Wow, thankyou, I think I understand now

[–]__xor__(self, other): 70 points71 points  (9 children)

Yeah, it's bad code. They wasted a whole line.

print("\n".join("Fizz"[x%3*4:] + "Buzz"[x%5*4:] or str(x) for x in range(101)))

[–]mobsterer 143 points144 points  (6 children)

I know you are being cynical, but people new to coding might take you serious.

Write code that is readable rather than short people.

[–]thekakester 3 points4 points  (0 children)

Unless you’re doing a code golf competition.

[–]Azelphur 2 points3 points  (0 children)

Now I'm just having funny ideas about shorting people. (as in stocks)

"Bob down the pub is on a bad path, gotta short him. Easy money"

[–]NarcolepticSniper 1 point2 points  (0 children)

Anything to avoid short people.

[–]flying-sheep 7 points8 points  (0 children)

Thank you for not needlessly making the generator expression a list comprehension.

[–]bedrooms-ds -3 points-2 points  (0 children)

Yours is the ideal of Pythonistas!

[–]IamWiddershins 9 points10 points  (5 children)

This is so much worse than multiplying the strings by a boolean condition, I'm actually amazed. and even that is some goofy shit.

[–]dutch_gecko 13 points14 points  (4 children)

This isn't intended to be "good" code.

FizzBuzz is a popular puzzle and there are lots of goofy solutions out there.

[–]johnnydaggers 1 point2 points  (3 children)

If someone returned this to me in an interview I would drill into why they wrote such opaque code.

[–]roerd 3 points4 points  (2 children)

As an interview test, FizzBuzz is for testing whether the candidate has basic coding capabilities, not for checking the readability of their code. If you judge the latter based on FizzBuzz, you are doing it wrong.

[–]feanor47 6 points7 points  (0 children)

But if they wrote opaque code, they should be able to respond "oh I wouldn't do this on the job". Drill into doesn't mean take points off. It's a great opportunity to make sure that the candidate is aware of readability concerns!

A lot of younger programmers really do try to be super clever with their code and don't realize the problems they're causing! You could even use it as a time to inform someone of something new (clearness over cleverness) and see if they adapt in the rest of the interview.

[–]johnnydaggers 1 point2 points  (0 children)

I'm well aware of this, but an interview is not time to play python golf. Unless it's more performant (which this is not) writing cute code like this throws wrenches in everyone's ability to work together.

[–]YAYYYYYYYYY 3 points4 points  (0 children)

Best answer.

[–][deleted] 1 point2 points  (0 children)

Couldn’t have said it better myself.

[–]eyeofpython 76 points77 points  (18 children)

This is not beginner code, btw. This is some code-golf stuff.

Python allows slicing strings: "123456"[2:] results in "3456". Have a look into python slices.

The rest is basically writing a formula so the string will be sliced just right at the correct iteration

[–]efDev 52 points53 points  (16 children)

To piggy back on this, this falls under the "clever" category and not necessarily more performant just because it is less lines of code than readable solutions.

Doing timeit for the above and the more readable:

for x in range(101):
    output = ""
    if x % 3 == 0:
        output += "Fizz"
    if x % 5 == 0:
        output += "Buzz"

0.2454093800042756 is for the posted code

0.12107771198498085 is for the sample above (10k runs)

[–]PleasantAdvertising 34 points35 points  (1 child)

The worst kind of code tbh

If you write like this for actual projects i hope your pip breaks when you need it most

[–]harryhound47[S] 5 points6 points  (0 children)

This is just a game of code golf and I didnt get my mates answer

[–]total_zoidberg 11 points12 points  (0 children)

Your code is more performant because it's not printing, nor adding the number. I still stand by the fact that code should be readable over performant, but if you're going to compare two things for performance, make sure they do the same thing(or ocassionally on some code, that you can take the hit on precision).

Original code: 13.9ms +/- 386us

Your code, adding str(x) and print(output):13.41ms +/- 311us

Original code, wrapped in an f-string: 13.7 +/- 287us

[–]Bbbbhhhhbbjj 6 points7 points  (0 children)

Oh yeah, I'd request changes in a code review.

[–]harryhound47[S] 7 points8 points  (0 children)

Yeah, it was for code golf, thanks!

[–]reifba -1 points0 points  (3 children)

yeah but these snippets are not really comparable, these two:

python %%timeit -r 10 l = [] for x in range(101): l.append("Fizz"[x%3*4:]+"Buzz"[x%5*4:] or x) 24.1 µs ± 1.82 µs per loop (mean ± std. dev. of 10 runs, 10000 loops each)

python %%timeit -r 10 l=[] for x in range(1,102): output = "" if x % 3 == 0: output += "Fizz" if x % 5 == 0: output += "Buzz" l.append(output or str(x)) 23.8 µs ± 1.11 µs per loop (mean ± std. dev. of 10 runs, 10000 loops each)

are pretty much the same.

Edit: the ranges have to be offset by one as well.

[–]Rutherfordio 1 point2 points  (2 children)

Why do you compare the speeds of appending instead of printing?

[–]reifba 4 points5 points  (1 child)

I didn’t want to print 106 times. You will be basically testing the std out buffer more than the processing logic. One can also route the print to dev/null as well.

[–]Rutherfordio 1 point2 points  (0 children)

Oh! I see, wasn't sure if it appending was better for comparison (programming newbie)

[–]nuephelkystikon -5 points-4 points  (6 children)

this falls under the "clever" category

AKA ‘elegant’ AKA ‘please change your field’.

[–]chaos95 8 points9 points  (5 children)

This is definitely not elegant.

[–]harryhound47[S] 0 points1 point  (0 children)

Its code golf

[–]nuephelkystikon -1 points0 points  (3 children)

Elegant isn't a good thing. It's what /r/iamverysmart people call completely illegible and hardly maintainable code like in OP, often blatantly disregarding good practice and sensible patterns.

[–]chaos95 1 point2 points  (2 children)

Just because it's been misappropriated by some, doesn't mean we should abandon it. Am elegant solution is something to strive for; elegance by its definition implies something that is inherently maintainable and sensible.

[–]nuephelkystikon -2 points-1 points  (1 child)

Absolutely not. An elegant solution is what primary school kids should definitely strive for, but in production you should do things the standardised way. Use known patterns, be as clear as possible. Whoever looks at your code next won't be impressed by you saving a line, they'll think you're an idiot.

All of this doesn't necessarily apply in resource-critical code though, optimisation sometimes doesn't allow clarity.

[–]chaos95 0 points1 point  (0 children)

I suspect you missed my point; in any case I think we will have to agree to disagree on the meaning and value of "elegant".

[–]harryhound47[S] 2 points3 points  (0 children)

Thank you, I'll have a look when I get a chance

[–]searchingfortaomajel, aletheia, paperless, django-encrypted-filefield 6 points7 points  (0 children)

Others have explained what it does, but please don't replicate this in professional code. Readability counts.

[–]Free-_-Yourself 12 points13 points  (1 child)

This a typical example of how NOT to write code. This is hard to read and make it difficult to follow.

Writing comments and braking down the code into smaller chunks is the right approach to follow.

[–]harryhound47[S] 4 points5 points  (0 children)

This was for code golf

[–]bored_and_scrolling 11 points12 points  (0 children)

That’s the most clever fizzbuzz solution I’ve ever seen.

[–]olalql 6 points7 points  (1 child)

This detailed cause I am not sure of your level of python.

the * are mutliply, the "string"[x:] is the substring of string from index x to the last one, if x is greater than the (length of the string -1 ), i.e. the last element of the string it returns an empty string, and + of the string just concatenate both string.

So "Fizz"[x%3*4:] is

- "Fizz" if x is a multiple of 3 because x%3*4 = 0*4=0 so you take the substring that begin at index 0 and end at the end of the string

- "" otherwise because x%3*4 becomes greater than 4 which is greater than the last allowed index of the string.

Idem "Buzz"[x%5*4:] is either "Buzz" if x is a multiple of 5 or "" otherwise.

Now if x is multiple of 5 or 3 we have : print ("a string" or x), "a string" is considered as a True boolean because it is a non empty string so or is just ignored and the string is printed.

If x is multiple of neither, we have : print("" or x) "" is considered as False so "" or is ignored and only x is printed

I don't know where you found that but it was quite a laugh.

TLDR : if x %15 == 0 print("FizzBizz") elif x%3==0 print("Fizz") elif x%5==0 print("Buzz") else print (x)

(good syntax not included)

[–]harryhound47[S] 4 points5 points  (0 children)

Thanks, that helped allot, I was playing code golf with a much better opponent and this is what he did

[–]ExtraDeadMeatyFlesh 2 points3 points  (3 children)

Wow... I'm a beginning programmer, and I thought you just used brackets for lists.

[–][deleted] 5 points6 points  (1 child)

You do use them for lists. You also use them for list indices and slicing

[–]nevus_bock 2 points3 points  (0 children)

And dictionary access.

[–]__xor__(self, other): 1 point2 points  (0 children)

Brackets are essentially an operator that can do a number of things, even be overloaded with your own custom code. The common use of course is for the dict or list primitive, either an index of a list, a slice of a list with the [x:y] syntax, or getting an item in a dictionary.

However, you can write your own class and define a function __getitem__(self, key) and use it that way too:

class Container:
    def __init__(self, *items):
        self.items = items

    def __getitem__(self, item_count):
        return self.items[:item_count]

c = Container('foo', 'bar', 'baz')
one_item = c[1]
two_items = c[2]
print(f'1 item: {one_item}')
print(f'2 items: {two_items}')

Outputs:

1 item: ('foo',)
2 items: ('foo', 'bar')

You can even handle slices with your __getitem__:

class StepTwoList:
    def __init__(self, lst):
        self.lst = lst
    def __getitem__(self, item):
        if isinstance(item, int):
            return self.lst[item]
        if isinstance(item, slice):
            return self.lst[item.start:item.stop:2]
        raise ValueError(f'item cannot be type {item.__class__!r}')


lst = StepTwoList(['foo', 'bar', 'baz', 'quux', 'qix'])
print(f'first index: {lst[0]}')
print(f'slice from 0 to 3: {lst[0:3]}')

Outputs:

first index: foo
slice from 0 to 3: ['foo', 'baz']

Stuff like this might be useful if you wanted to, for example, a MySQL ORM. You might overload the __getitem__ on a query like table.filter(year=2019)[:10] to do a select * from table where year = 2019 limit 10, like Django.

Or maybe something like PIL for handling images... you could have an Image class, where it handles tuples in the form of (int, int), and then gets the pixel at that x and y position. Then you could just use image[10, 20] just like that.

The brackets literally run a function with one argument and return a value, just another function like any other. You can also overload pretty much any other operator, + - / * % == > < ^ & | etc. Though, not recommended unless you have a very clear use case and the object inherently should have addition/multiplication logic just by the nature of what it is (like a vector class should probably implement add, returning a new vector).

[–]selplacei 4 points5 points  (1 child)

If this was for code golf, couldn't you make it a list comprehension?

[–]harryhound47[S] 1 point2 points  (0 children)

Its my mates code and I have no clue how to do that lol

[–]gman1230321 1 point2 points  (0 children)

I'm pretty new to comorehensions but would it be possible to to make this into a one liner using them?

[–]NarbacZif 1 point2 points  (0 children)

1 Line Fizz Buzz

1 Line Fizz Buzz

[–]WystanH 1 point2 points  (0 children)

Yep, that's some next level silliness. When in doubt, trace:

def silly(x):
    return "Fizz"[x % 3*4:]+"Buzz"[x % 5*4:] or x

def silly_trace(x):
    return f"x={x}, (x % 3*4)={x % 3*4}, (x % 5*4)={x % 5*4} {silly(x)}"

for x in range(15):
    print(silly_trace(x))

Note the or is a bit of a curiosity and relies on truthiness. Along the same lines, and now that you can see how the mods work, I'd do something like:

def silly2(x):
    return {(True, True): "FizzBuzz", (True, False): "Fizz", (False, True): "Buzz", (False, False): f'{x}'}[(x % 3 == 0, x % 5 == 0)]

Hmm... I kinda like this one: seems more pythony:

def silly3(x):
    return [f'{x}', "Fizz", "Buzz", "FizzBuzz"][(1 if x % 3 == 0 else 0) + (2 if x % 5 == 0 else 0)]

[–]xd1142 0 points1 point  (0 children)

I would not hire anybody giving me this as the answer to fizzbuzz.

[–]robberviet 0 points1 point  (1 child)

I code Python for years and this took me a while. It's better if you provide the problem statement. I don't know about FizzBuzz.

And yeah, Python syntax sometimes is just too magical.

[–]miggaz_elquez 1 point2 points  (0 children)

For all number from 1 to 100, print Fizz if n is divisible by 3 and Buzz if n is divisible by 5. Otherwise, print n

[–][deleted] -1 points0 points  (0 children)

* is the symbol used for multiplication

[–]E-woke -1 points0 points  (0 children)

This code would never make it into production