The Zen of Python (by example)
artifex.org
artifex.org
To summarize, while switching religions: "The Tao that can be expressed is not the eternal Tao".
But if you're going to try to express the Zen of Python, you can do a hell of a lot better than this.
def identify(animal):
if animal.is_vertebrate():
return identify_vertebrate()
else:
return identify_invertebrate()
should be def identify(animal):
if animal.is_vertebrate():
return identify_vertebrate(animal)
else:
return identify_invertebrate(animal)
Arguably this mix of OO and procedural code is bad as well. But less arguably, the initial example (with a simple identify function) was far better than the rewrite.i dunno if this is valid python but it demonstrates the idea
doSomething(
identify_vertebrate(animal) if animal.is_vertebrate() \
else identify_invertebrate(animal))
doSomething( if( is_vertebrate(animal)
identify_vertebrate(animal)
identify_invertebrate(animal)))
(doSomething (if (is_vertebrate animal)
(identify_vertebrate animal)
(identify_invertebrate animal)))
this is part of "referential transparency", and once you get past "OMG parens" you realize its a Good Thing. parens are caused by a style preferring composition of expressions over executing statements, not lisp.Conclusion: for Hunter Blanks, SQLAlchemy can never win.
I wouldn't be surprised if many people criticizing #3 had no practical experience with NoSQL and the benefits brought by its lack of baggage.
Folks seem to have found a lot of implicit meaning and bugs in what was, at its grandest, a 5 minute talk at RedSnake Philly 2011. I'll just make two comments:
1) This in now up on GitHub at: https://github.com/hblanks/talks/tree/master/2011/zen_of_pyt...
so if you feel strongly about making this better, you should send me a pull request.
2) People seem to have decided that the top (or the bottom?) of every example is the more pythonic one. I suppose I should have kept a consistent order, but, as I noted in the initial HN thread, that just wasn't necessary since this was delivered in the context of a talk.
def make_counter():
i = 0
def count():
""" Increments a count and returns it. """
i += 1
return i
return count ...
def count(i=i):
...
...I'd use itertools.count().
fs = []
for i in range(5):
def f():
print(i)
fs.append(f)
gs = []
for i in range(5):
def g(i=i):
print(i)
gs.append(g)
The functions in `fs` all print 4 because they all refer to the final object assigned to `i` in the `for` loop. The functions in `gs`, on the other hand, print 0 through 4, as they "should" because the `i` in `g` is assigned to the object currently referenced by the `for` loop's `i` each time the `def` statement is evaluated. This distinction in behavior is obscured in the classic function-inside-a-function example of closures because you pass the object to be closed over to the outer function each time you want to create a new closure. So the result is analogous to using the default-argument trick in the example above.Anyway, that's all I meant to point out. I misinterpreted your reference to `nonlocal`, which I'm not very familiar with as I don't really use Python 3 much yet. So sorry for my nonsensical reply.
[0] By "properly" I mean as closures work in pure functional languages, where they originated. I realize a programmer who understands Python's data model shouldn't generally expect them to work that way in Python.
My answers above were really short because I was on a tablet. May have come across as curt.
from menagerie.models import cat as cat_models
This is not recommended at all from menagerie.cat import models as cat_models
from menagerie.dog import models as dog_models
from menagerie.mouse import models as mouse_models
Because otherwise it doesn't match the code in the first example for #3, and also because if your packages are ordered that way, then why not just from menagerie.models import cat, dog, mouse
and forget about changing the local module name.