The Zen of Python by Example
artifex.org
artifex.org
For example, explicit isn't always better than implicit. I mean, by that standard alone, the idea of a garbage collector going around implicitly freeing memory would be terrible.
And then, in our very first example, there is a use of lambda, a misnomer of a concept Python doesn't really support? My brow furrowed slightly more.
I can't help but feel like these people are celebrating their investment in their tools rather than the virtues of the tools themselves.
Yes, but this practically is the Python manifesto.
Python 2.6.5 (r265:79063, Oct 28 2010, 20:56:23)
[GCC 4.5.0 20100604 [gcc-4_5-branch revision 160292]] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
...
There's an import statement that will print it I believe, but I'm not sure exactly what it is.
numbers.filter( _ % 2 == 0 )
This document is old, so we can probably excuse it... but how many Python folks know that? numbers.filter( _ % 2 == 0 ).map( _ / 2 )
Zen of Python doesn't contain any lambdas (the link from the grandparent http://www.python.org/dev/peps/pep-0020/ ). List Comprehensions are 10 years old http://www.python.org/dev/peps/pep-0202/How do you write:
lambda x, y=1: x+y
lambda *args: reduce(lcm, args)
lambda **kwargs: kwargs.get('a') or kwargs.get('b')
def lcm(a, b):
return a*b // gcd(a, b)
def gcd(a, b):
while b:
a, b = b, a % b
return aIt does indeed mention a lambda in the very first example, if only as a competition with list comprehension syntax. But even Python's list comprehensions look a little dated now.
What do you mean by dated? What new ideas have come up for List comprehension syntax?
(I agree that Lambda should be call fun or fn or \. An implicit _ might also work, though that's somewhat against Python's spirit---c.f. the explicit self in methods.)
The part that bothers me about the list comprehension section is that conflating list comprehension and lambda. Is it telling me that list comprehension is better than map/filter or better than lambda? I don't know. Quiet honestly, in many situations I find:
halves_evens = lambda nums : [i/2 for i in nums if nums % 2 == 0]
to be the cleanest.
def halves_of_evens(nums):
for i in nums:
div, mod = divmod(i, 2) #NOTE: it might be slower
if mod == 0: #NOTE: `not mod` is not explicit enough
yield div
#2: Function level import is a bad practice though it might be justified in this case.#3: `users` is not defined. `sqlalchemy` names are not defined. The file should be opened for writing in the json example.
#5 It is simpler to allow the animal to know its kind:
def identify(animal):
return animal.__class__.__name__
or just: animal.kind
#6 `elem.xpath('./a/@href')` is simpler than [a.attrib[’href’]
for a in elem.find(’./a’)
if ’href’ in a.attrib]
Also `elem.iterlinks()` could be used
http://codespeak.net/lxml/lxmlhtml.html#working-with-linksThere is no `lxml.CSSSelector` (python-lxml 2.2.6-1). Use `elem.cssselect`
#7 You don't need to add `ifmain` stub in every module:
$ python -mdoctest module_with_doctests.py
$ python -munittest module_with_unittests.py
# 8 & 9: The first variant of `make_counter()` won't work without `nonlocal i` -- it leads to `UnboundLocalError` otherwise.Despite the fact that it works on my machine on all available Python implementations such code should be avoided:
assert float(’0.20000000000000007’) == 1.1 - 0.9 #XXX horror!
# 10 & 11: Use stdlib's version: try: import json
except ImportError:
import simplejson as json
It is a matter of preference but it makes testing more predictable.#13 `__builtins__` is not defined on jython:
try: import __builtin__ as builtins
except ImportError:
import builtins # py3kIn general globals should be written at a global level.
> #2: Function level import is a bad practice though
> it might be justified in this case.
Ah, but: > Special cases aren't special enough to break the rules.
;-)This isn't meant to detract from the truth that "Beautiful [code] is better than ugly," I merely thought the implementation should be correct.
I think i % 2 is just straight up incorrect.
If we're talking about style, I think i % 2 == 0 is much more clear than (not i % 2). It says explicitly that the remainder of i divided by 2 is 0.
$ python3
>>> not 0
True
Python doesn't have Perl-like contexts, but it does treat lots of values as True or False. I do agree that i % 2 == 0
is more explicit here. if foo:
do_stuff()
over if len(foo) > 0:
do_stuff() class ExtendedBool t where
toBool :: t -> Bool
instance ExtendedBool Int where
toBool = (0/=)
instance ExtendedBool [a] where
toBool = not . null
if' v a b =
if (toBool v)
then a
else b
main = if' "String"
(print "True")
(print "False")That said, I'm having quite a hard time grappling with section 4.
First, what is the 'users' keyword all about in the "bad" area?
Second, why is ORM the "bad" approach, and manual construction of SQL strings the "good" one? It seems to me that the abstraction and centralization of query language is paramount (examples: to afford oneself an easy one-day migration to GQL/BigTable, or to a document-oriented database like MongoDB or the upcoming Couchbase).
You could argue "between Python and C"... but most certainly NOT assembler
http://www.wefearchange.org/2010/06/import-this-and-zen-of-p... , a blog post written by Barry warsaw.
On a side note, other eggs are :
>>> from __future__ import braces
>>> import antigravity
I agree with several commenters that, like any collection of aphorisms, the lines in PEP 20 are not real rules but rather rules of thumb. Nevertheless, rules of thumb, or heuristics, are surprisingly important to the practice of engineering,* and perhaps even more so to the work of writing software. As such, nothing in PEP 20 should be followed hard and fast, but almost all of it is worth considering. Also as such, there's nothing (except for the comment on Guido) that makes PEP 20 relevant only to Python. It happens that these rules have a particular currency in the Python community (i.e., when people talk about being Pythonic, they're often talking about something described in the Zen of Python). But if you work in a different language, there's probably something worthwhile in it there, too.
On a different note, it is flattering to find this code, hacked out such as it was, has been reviewed by a far larger number of peers than the (comparably) few, albeit exceptional, engineers I work with at Monetate. Although it was hardly intended to be read on its own, or to run beyond the feeble purpose of generating its own slides, I have tried to correct what errors people have found. Ambiguities, of course, remain, but you can find an updated document at the original URL, or a diff of the changes at:
http://artifex.org/~hblanks/talks/2011/pep20_by_example_2011_02_10_edits.patch
To respond to a few specific or general points:- Yes, of course, importing from within in a function is almost always a bad idea (the only exception I've ever seen is Google App Engine, and that's obviously just a performance hack). Nor would you ever want to actually convert your floats to strings and back -- my only point there was to illustrate the fact that yes, those are the rules of floating point, and so you can't expect Python to break them for repr().
- The order of examples is not necessarily bad first, good second. (Alas for inconsistency!) So, for instance, ORMs may be complex, but they're often much better than writing your own SQL, which even in this trivial example starts to get complicated. Similarly, doctests often make code more readable than unit tests hiding in some other file -- although in honesty the doctest/unittest split is probably a false dichotomy; for some things, doctest is much cleaner, for others (like things that require setting up a DB schema first), unit tests are.
- Finally, I still didn't have the wherewithal to call pygments directly (it's certainly easy and better; I just knew the command already). But I did add HTML output, since this the web, after all, to:
http://artifex.org/~hblanks/talks/2011/pep20_by_example.html
* Cf. Billy Koen's enjoyable discussion of engineering heuristics,
Discussion of the Method or Discussion of the Engineering Method.
(Some chronicle is available at
http://www.me.utexas.edu/~koen/OUP/HeuristicHistory.html)We've finally accepted that web developers can expect visitors to have a higher resolution than VGA, and those are potentially non-tech-savvy users. Can't we expect developers to have more than 80 character width editors? Plus, I think splitting lines is pretty ugly.
Finally, in some cases, it's just more readable. Take the following code:
some_list = [a_long_variable, with_contrived_names, for_an_example, insert_your, own_parallel, if_it_bothers_you]
versus some_list = [
a_long_variable,
with_contrived_names,
for_an_example,
insert_your,
own_parallel,
if_it_bothers_you
](Of course I have a second monitor, but that usually has documentation and a terminal and IRC on it.)
When text stretches to take up the entire width I don't use full-screen windows. I adjust them to have about 10 words per line, and I can scan down really fast. Similarly for programming. Don't make me scroll through a 6000 line function, and don't make me read along a 6000 character line.
Yes, 6000 characters may be an exaggeration, but where is the limit? Where is the point where the line is simply "too long". Answer? It's where readability drops off, and for me, that's about 10 words, or about 60 characters.
Also, the restriction to something around 80 characters stemmed from technical considerations---but it may be good for readability, too. After all 66 characters per line is the rule of thumb for type setting books. Newspapers also divide their pages into narrow columns.
However, since everyone is shipping widescreen monitors (which I think means UI design should stop making tall toolbars, but I digress), I find that a width of 100 characters suits my code better.
Can somebody please enlighten me on how using raw sql is preferable?
ORMs are not a panacea. Especially when the database schema gets more complicated they require more setup and tuning, and there's always the problem of how much data the ORM should suck in vs. how lazy it can behave.
Go Hunter!
evens_only = lambda nums: [n/2 for n in nums if n%2==0]
seems to work just as well. >>> evens_only([1,2,3,4,5])
[1, 2]
If you want a generator instead: evens_only = lambda nums: (n/2 for n in nums if n%2==0)
So you'll get: >>> evens_only([1,2,3,4,5])
<generator object <genexpr> at 0x7f2ef79eaa00>
I don't know which one would be more Pythonic, clean and simple lambda one-liner or two-lined simple function.http://en.wikipedia.org/wiki/Shuhari
I do not claim to be a master