Live data from Hacker News

Python Best Practice Patterns

stevenloria.com

91–97 of 97 posts

Re: Python Best Practice Patterns

#91
post #49
post #11

Earlier quoted context omitted.

I saw this code yesterday: def is_file_for(is_nagyker, type): if type == KIS_ES_NAGYKER: return True elif type == KISKER and not is_nagyker: return True elif type == NAGYKER and is_nagyker: return True At the first glance, I thought it always return True. Would have been more clear an explicit return False at the end!

May I suggest `any` here? def is_file_for(is_nagyker, type): return any([ type == KIS_ES_NAGYKER, type == KISKER and not is_nagyker, type == NAGYKER and is_nagyker]) I know unsolicited code improvements from strangers isn't the coolest thing in the world, but `any` (and `all`) can really improve clarity for stuff like this. I know I use them quite a bit.

You create a list, so this expression won't shortcut like or. Or is definitely the right way to write an expression like this. Any has its place, but mostly when it's input is a generator, e.g.,

    any(k in obj for k in other)

Re: Python Best Practice Patterns

#92
post #73
post #47

Earlier quoted context omitted.

In the case of SQLAlchemy you are not. The cascading methods on query objects create new query objects as it should be. Mutating objects with cascading methods is horrible API design as it suggests immutability where there is none.

the API in some ways comes from that of Hibernate, which does actually mutate in place (see http://docs.jboss.org/hibernate/orm/3.3/reference/en-US/html... ). I felt that keeping the existing object un-mutated is a lot more intuitive. I think the names that you choose for the methods do make a difference, e.g. Hibernate is saying "add()" which for whatever reason seems to imply "mutation" to me, not sure why.

Having used hibernate extensively (and considering many of it's features remain completely unmatched in any other ORM I've encountered), I can say that I strongly dislike the idea of mutating the query in place. There's huge advantages to each chain returning an independent and valid query that can be executed, referenced, and added to. I don't see any upside to the Hibernate approach here, and it violates "Prefer Immutability".

Re: Python Best Practice Patterns

#93

Earlier quoted context omitted.

> Make methods as big as they need to be. Correct, and if you do that, methods will invariably end up small. What you cite above is small no matter how you write it, so that's not the point of the advice to keep methods small. Methods pretty much never need to be long; they're long because they're poorly written code. Well written code tends towards small methods.

Correct, and if you do that, methods will invariably end up small. If you'd said "usually", I'd have agreed with you, but "invariably" is far too strong. Sometimes the logic you need to implement is fundamentally complicated, and so the code you write to implement it must inevitably be at least that complicated. If that means writing a 100 line function, but the function really is doing one job, at one level of abstr…

We agree, I'm fine with usually.

Re: Python Best Practice Patterns

#94
post #9

Several of those patterns are incomplete or frowned upon: * if a method does not use the object's state (no `self` usage) make it a `class-` or `staticmethod`. * Some magic methods are presented. There's more to them[0]. * one should not write `class MyClass:` but `class MyClass(object):` (new style class[1]) * the last one (`return None`) make me very dubious * Cascading methods: that's a big no . The idiom is that…

> * the last one (`return None`) make me very dubious I'm curious, as someone who uses this pattern quite a bit, how would you improve on this?

That line and this one lead me to believe he's full of hot air:

> if a method does not use the object's state (no `self` usage) make it a `class-` or `staticmethod`.

Uh, that's a little too "cookbook" for my tastes. The decision of whether to make something a class / static method or not should be decided based on what the function is doing, rather than some pointless dogma. I'm assuming he means this method:

> def alarm(self): > with open(BUZZER_MP3_FILE) as f: > play_sound(f.read())

It's a design decision, and one that is particularly trivial at that. Let's say the effects an alarm ultimately change, resulting in an internal state read / write on the object. Now you have to go back and update the class despite the fact that it at a higher philosophical level one could argue that an alarm should only be triggered on an individual boiler.

Point being: it's nit-pickery for nit-pickery's sake. I don't personally use `return None`, but it's certainly more explicit and is fine to use if your judgment has found it to make sense.

Re: Python Best Practice Patterns

#95
post #61
post #36

Earlier quoted context omitted.

The builtins are broken, that is why there are new builtins liked `sorted()`, list.sort() returning None is not an improvement. The standard libraries are a _mess_, there is absolutely know cohesion in their api design, or even naming conventions (go peruse the standard lib). Much of what is Pythonic is someones opinion on how a nanny-language should behave. At this point I think calling something idiomatic or Python…

sorted returns a new object, not mutates the original object, so it follows the convention GP is talking about. sort() also follows that rule, since it mutates, it returns None. In terms of refutation, some things are just conventions, and breaking them has to be done with the understanding that the benefits outweigh the costs. If python were a clean slate, totally new language, you might have a discussion about the…

Counterpoint, object.next() was removed from python3 and replaced with next(object). It both modifies state and returns data. I really prefered next() as a method since it does change the state of a generator.

Re: Python Best Practice Patterns

#96

Earlier quoted context omitted.

As another change, it is recommended to avoid explicit line continuations by using parentheses instead. def is_file_for(is_nagyker, type): return ((type == KIS_ES_NAGYKER) or (type == KISKER and not is_nagyker) or (type == NAGYKER and is_nagyker)) This way, it doesn't break if there is extra whitespace at the end of the line.

As yet another change, PEP8 recommends placing comparison operators (and dots, when method chaining) at the beginning of each line to make things a little clearer. def is_file_for(is_nagyker, type): return ((type == KIS_ES_NAGYKER) or (type == KISKER and not is_nagyker) or (type == NAGYKER and is_nagyker))

This is incorrect. “The preferred place to break around a binary operator is after the operator, not before it.”

Re: Python Best Practice Patterns

#97
post #96

Earlier quoted context omitted.

As yet another change, PEP8 recommends placing comparison operators (and dots, when method chaining) at the beginning of each line to make things a little clearer. def is_file_for(is_nagyker, type): return ((type == KIS_ES_NAGYKER) or (type == KISKER and not is_nagyker) or (type == NAGYKER and is_nagyker))

This is incorrect. “The preferred place to break around a binary operator is after the operator, not before it.”

You're right. It must've been another Python style guide I somehow remembered that from.

From what I can tell this is kind of a point of contention among many developers; there are lots of debates when Googling that particular line.

Post reply on HN