4 ms·
I work with python daily. I find that when I first started I avoid a lot of the "fancy" constructs such as list comprehensions, dynamic arguments, and decorator
by jtchang 15y ago
I work with python daily. I find that when I first started I avoid a lot of the "fancy" constructs such as list comprehensions, dynamic arguments, and decorators as well as meta programming.
The great thing is the bar to being effective in the language is so low. You can pretty much pick up most python code and just read it and get a general feel for what it does. Not only that but it is much easier to read because of whitespace delimiting.
I can generally tell the quality of a python program but how nicely indented it is. If there are lots of indents like 5 or 6 levels deep I know something is wrong. For a newbie if your code is hard to understand and it is in Python you are writing it wrong.
- Luyt 15y agoI find a great way to avoid deep nesting is to move code to functions, and bail out when some conditions are not met. As an example, this deeply nested code: def frob(someargs): if something > 2: ... # do some processing if that == "CONNECT": ... # some more processing if verdict in blessedsolutions: ... # even more processing print "Happy birthday!" I tend to write like this: def frob(someargs): if something <= 2: return # Not our concern. ... # do some processing if that != "CONNECT": return # Not handled here. ... # some more processing if verdict not in blessedsolutions: return ... # even more processing print "Happy birthday!" I do the same thing in loops, using 'continue'. The above second example looks rather flat, but in practice the 'do some processing' statements often need identations due to conditions and loops. I added the processing to demonstrate that it's not always possible to combine conditions. And, of course this way of 'bailing out early' vs. 'nested ifs and processing' is not Python specific. The dogma that a function should have only one exit point (as proposed by 'structured programming' adepts and Pascal afficionados) often leads to deeply nested control structures and convoluted testing. Brian Kernighan has written a paper on this[1]. [1] http://www.cs.virginia.edu/~cs655/readings/bwk-on-pascal.html http://www.cs.virginia.edu/~cs655/readings/bwk-on-pascal.htm...
- rmcclellan 15y agoNeither solution is great. Excessive use of return and continue is an incredibly fast way of making code completely incomprehensible. Such complicated control flows should be treated as a major, fundamental problem. Keeping them in place will cause bugs and prevent future contributors from having confidence that their changes are correct. The problem of complicated control flow is too deep to be solved with a band-aid like this, although perhaps syntactically it looks a bit nicer. In fact, this is exactly what people did before the so-called "structured programming adepts" came around, except using gotos instead of continues. It didn't work so well back then, and it doesn't work so well now.
- Luyt 15y agoHmmm, you have a point there, but what is your proposal to solve it in a correct way, then? Some problems need a deeply nested control flow and arcane business rules, you have to implement that somehow, and in such a case the method I use looks like the lesser of two evils. I'd rather have some flat ecosystem of meaningful functions than one monolithic deeply nested control structure. From time to time I like defensive programming, and when I write a function 'frob' that promises to frob something, that function first makes sure that the thing can indeed be 'frobbed', and if not, bails out. This also works well for programs that should be idempotent (although that is a whole other issue).
- anthonyb 15y agoThe way I would do it is to push the processing out to functions, too. Something like: verdict = get_verdict(the_thing) if verdict not in blessedsolutions: return I'd advise against running returns onto the same line - I find it makes it harder to read, particularly when you have a lot of checks like this.
- Luyt 15y ago"The way I would do it is to push the processing out to functions, too." This is indeed a good idea to isolate code away, but wouldn't alleviate a deeply nested control structure. It would make it somewhat more easier to look at, though. "I'd advise against running returns onto the same line " I usually follow PEP8 and place returns and continues on the next line, but the code examples I posted earlier had to be a bit condensed to conserve screen space, that's why ;-)
- icebraining 15y agoIf there are lots of indents like 5 or 6 levels deep I know something is wrong. "Flat is better than nested" I keep a print-out of PEP-20 above my desk. It serves as an incentive to clean up my messy code ;)
- hcarvalhoalves 15y agoDeeply nested code is usually a symptom of not thinking the problem in advance and solving it with data structures, instead relying on ad-hoc conditionals to solve it. When I find myself testing against too many conditions, I usually refactor code to use a map between values and behaviour (e.g., a dict mapping regexs to function objects). This way you remove business logic from code, and are free to make it more algorithmic, like a simple mapping problem.