Python 3.1, you shouldn’t have!
I highly appreciate the presents that the Python 3.1 team (unwittingly) got me for my birthday this year. This morning I wrote the following snippet to determine the day-frequency of birthday occurrences: [*]
#!/usr/bin/env python3.1 import collections import datetime from operator import itemgetter birthday = {part: int(input('Enter birth {}: '.format(part))) for part in 'year month day'.split()} now = datetime.datetime.now() days = [] for year in range(birthday['year'], now.year + 1): iter_birthday = dict(birthday) iter_birthday['year'] = year date = datetime.date(**iter_birthday) days.append(date.strftime('%A')) counter = collections.Counter(days) fmt = '{:15} {:>3}' for day, frequency in sorted(counter.items(), key=itemgetter(1), reverse=True): print(fmt.format(day, frequency)) print(fmt.format('Total', sum(counter.values())))
Check out the Python 3.1 goodness: automatically numbered format strings and collections.Counter. It’s also a relief that I no longer have to type iter, x, or raw — Python is even prettier without the 2.x cruft.
Turns out that my original day of birth is still in the lead!
Updates
- Added dict comprehensions per astute comments. :-)
- Replaced lambda argument to sorted with the more readable operator.itemgetter, which I didn’t realize exists! Thanks @xtian.
Footnotes
| [*] | Note that the script assumes your birthday has already occurred this year. |
July 1st, 2009 at 14:54
Ough, the obfuscation! It hurtz!
There, I fixed it. ;-)
July 1st, 2009 at 17:07
You’re missing dict comprehensions :)
July 1st, 2009 at 18:05
Instead of
what about
July 1st, 2009 at 21:35
@Lennart: I’m willing to accept that the dict comprehension may be better written as a for loop (due to stdin side effects), but I don’t agree with the elimination of the lambda. Really simple one-statement operations (like sequence indexing in a throw-away sort invocation) are the few cases where I’ll actually prefer an anonymous function — I’m pretty sure that’s the use case that caused lambdas to remain in the language in the transition to Py3k.
@Roberto @rgz: You guys are totally right. Been writing too much 2.x compatible code lately. ;-) Updated to reflect your correction!
July 2nd, 2009 at 00:27
itemgetter(1) is much nicer than lambda t: t[1] (it lives in the operator module).
July 2nd, 2009 at 03:01
Lennart’s version is much more readable, which is entirely what counts.
July 2nd, 2009 at 04:14
@Malthe: I think it has distilled down to a difference of opinion. As I see it, frequency_key is a meaningless function outside of the context where you have a sequence with the second element being a frequency value. I personally find that function more objectionable because its name implies some sort of generality, whereas the anonymous function is intentionally throw-away in the (temporary) item-iteration context.
Overall, I’m partial to an inline “itemgetter(1)“, as mentioned by @xtian — less ugly than a lambda, plus stdlib-approved and -documented.
July 2nd, 2009 at 04:21
I agree; either one of them. Certainly “itemgetter“ is more efficient, too.