Live data from Hacker News

New Ways to Be Told That Your Python Code Is Bad

nickdrozd.github.io

81–90 of 262 posts

Re: New Ways to Be Told That Your Python Code Is Bad

#81
post #73

While I appreciate the idea of bounded loops, it's a mistake to think that a `for` loop is necessarily bounded. It's pretty easy to write a generator that produces an infinite sequence. That generator, of course, would need a `while` loop, but that loop can be in an external dependency which the linter is not checking. You also can read way more than you expected if you use a `for` loop to read from a socket, or a fi…

You should be able to create an unbounded for loop as well. After all, a python process has mutable state, so it should be fairly simple to increment the length of your loop inside the loop body.

Re: New Ways to Be Told That Your Python Code Is Bad

#82
post #81
post #73

While I appreciate the idea of bounded loops, it's a mistake to think that a `for` loop is necessarily bounded. It's pretty easy to write a generator that produces an infinite sequence. That generator, of course, would need a `while` loop, but that loop can be in an external dependency which the linter is not checking. You also can read way more than you expected if you use a `for` loop to read from a socket, or a fi…

You should be able to create an unbounded for loop as well. After all, a python process has mutable state, so it should be fairly simple to increment the length of your loop inside the loop body.

  >>> x = [0]
  >>> for x in xs:
  ...   print(x)
  ...   xs.append(x+1)

Re: New Ways to Be Told That Your Python Code Is Bad

#83
post #72

> You know what else doesn’t have unbounded loops? Excel. Right, one of the many reasons why nobody (with half a brain) hosts a web server in Excel. I wonder how much "boring web app" experience the author had. If I'm debugging on 11 pm why the webserver is timing out talking to microservice A, but only if it first opened connection to service B, and someone strolls along saying "Hey, your code is bad because it's us…

That's why you want to start thinking macro and holding your code to a high standard early. You can, for the most part, avoid firefighting if you don't let things fester.

If you're in charge, that is...

Re: New Ways to Be Told That Your Python Code Is Bad

#84
post #45

Earlier quoted context omitted.

Exactly. I prefer this a lot more to at least avoid using else: x = 5 if condition(): x = 4

My favorite way to write that is with expression oriented langauges. Example in OCaml: x = if condition() then 5 else 4 I dislike how the regular order of if is changed when used as an expression. I don't know how you could retrofit that into existing Python tough. Probably a consequence of defining blocks with whitespaces.

It is simply a design choice, the common value is given first. Comprehensions in Py are the same.

Re: New Ways to Be Told That Your Python Code Is Bad

#85
post #56

Earlier quoted context omitted.

Even clearer: scale = 5 # The alternative would be exponentials with range(), # but it's clearer to use 'while' # pylint: disable=[while-used] while (scale > 0.1): do_stuff(scale) scale = scale/2 Less sarcastically, how about: scales = itertools.takewhile( lambda n: n > 0.1, functools.reduce(lambda x, y: x / y, itertools.repeat(2), 5) ) map(do_stuff, scales) This would be even easier with an 'iterate(x, f)' function…

I shouldn't need to read the code extremely closely or repeatedly to have to figure out what it does when the while loop does it clearly (and in a bounded way that you can literally mathematically prove). Also, I would scream if some opinionated dev gone crazy with their linter added pylint disables and comments explaining it every time we use a while loop in our codebase. Why does the linter rule not, instead, check…

> Why does the linter rule not, instead, check if the while loop is unbounded and warn the user of that?

Indeed, the linter only needs to incorporate of the many known solutions to the halting problem.

Re: New Ways to Be Told That Your Python Code Is Bad

#86
post #6

Earlier quoted context omitted.

Exactly. I pretty much love everything about Python except its ternary operator. I also prefer C’s.

When I first started using python, I assumed it had a normal (c-like) ternary operator and was a little surprised to discover the syntax we're talking about. But after some time, it actually feels very natural to me, and is arguably more intuitive than ?: syntax. I assume this is where the author is coming from.

Arguably? It can be read like a sentence. ;-)

Re: New Ways to Be Told That Your Python Code Is Bad

#87

Python doesn't have a do..while loop, so when you want to do a thing at least once, the simplest replacement is starting the loop with "while 1:" and ending the loop with "if ... break". I disapprove of any linter that flags this idiom.

why "while 1:" and not "while true:"?

It used to be slightly faster in Python 2, because True could be reassigned, so its value had to be loaded and checked with every iteration.

Re: New Ways to Be Told That Your Python Code Is Bad

#89
post #4

> less code is better than more code Not when it's at the cost of readability. The example "better" code fails my readability test horribly. I'd gladly take C's ternary operator over this monstrosity: > x = 4 if condition() else 5

What's so monstrous about it? It's practically English: cssClass = 'selected' if isCurrentTab else 'deselected'

Probably b/c Python abuses the same keywords way too much. (But that shouldn't be such a surprise already to oppose this particular case.)

Re: New Ways to Be Told That Your Python Code Is Bad

#90

So is the author suggesting that a while loop like this: while not quitRequested: processNextEvent() Should be rewritten to this? for i in range(999999): if quitRequested: break processNextEvent() Because that's supposedly guaranteed to halt? If so he's either joking or crazy. And his program will crash for his poor users after 999999 events.

In practice, quitRequested and processNextEvent are probably both members of some managerial object; perhaps like this:

  while not loop.quit_requested:
      process(loop.next_event())
And when you see it like that, then it becomes more apparent there’s an obvious way for it to be an iterator:

  for event in loop.run():
      process(event)
This is typically harder to get wrong, and generally matches the semantics of what you’re trying to do more closely: process a stream of events. You didn’t actually care about quit_requested, you cared about the events.

And so in this you can start to see why iterator-based for loops are normally better than while loops (and C-style for loops, which Python doesn’t support): while loops (and C-style for loops) are generic bookkeeping, with no specific semantics on the while condition (or for init/condition/increment clauses); but iterator-based for loops operate on actual data.

This principle can be seen in resource locking also; you don’t want a lock object beside the data that it locks, like this:

  with lock.acquire():
      queue.append(item)
That style is just asking for trouble; sooner or later you’ll touch the queue without acquiring the lock, and everything will fall apart. Instead, you want to lock the actual data so that you can’t even access the locked thing without acquiring the lock:

  with queue.lock() as q:
      q.append(item)
P.S. If you deal with something like the original loop without a run() method, you can write a generator to convert a while loop into a for loop:

  def run(loop):
      while not loop.quit_requested:
          yield loop.next_event()

  for event in run(loop):
      process(event)
Most of the time the difference won’t be significant or worth it, but sometimes this can really help to clarify things, by extracting the loop bookkeeping into one place so that you can do what you were semantically trying to do, processing a stream of events.

P.P.S. Instead of range(999999), use itertools.count() when you want unbounded iteration. Or itertools.repeat(None) if you don’t care about the number—but in that unused number or None see that a for loop is probably not the right tool for what you’ve written: you would be better either shifting back to while loops, or iterating over the data as I’ve demonstrated.

Post reply on HN