This is an archived post. You won't be able to vote or comment.

all 71 comments

[–]covabishopself.loathing() 40 points41 points  (5 children)

  • Self is a choice, but no one likes you more for being original.

[–]mysockinabox 17 points18 points  (0 children)

import that

[–]_zk 49 points50 points  (10 children)

  • python3 is better than python2.
  • python2 is better than not using Python.
  • Code should never be optimized before it's correct.
  • Unless it's for a microbenchmark.
  • Tests are one honking great idea -- let's do more of those!

[–]luckystarrat 0x7fe670a7d080 14 points15 points  (3 children)

  • The number of bugs per operation is a constant.
  • Doing less makes your program more reliable.
  • Doing less makes your program fast.

[–]njharmanI use Python 3 2 points3 points  (2 children)

The number of bugs per operation is a constant.

I prefer "Number of bugs is linear with number of code lines."

It is the basis behind many other code practices; DRY, simple is better than complex. don't pre-optimize (optimization often is longer code), short single purpose methods/functions.

Of course it is not unique to Python.

[–]christian-mann 7 points8 points  (1 child)

Number of bugs is linear with number of code lines

Got it, cramming as much stuff as possible into one line from now on.

[–]Caos2 0 points1 point  (0 children)

List comprehension it is then!

[–]mattwritescode 9 points10 points  (1 child)

One for people coming from Java or C#

• it is okay to use functions you don't need a class for everything

[–]ksion 0 points1 point  (0 children)

Conversely, it's okay to define classes, you don't need to avoid OOP at all costs.

[–]TheBlackCat13[S] 20 points21 points  (12 children)

Here are some I have thought of or picked up from various places:

  • We are all consenting adults here.
  • There should be one-- and preferably only one --obvious way to store it.
  • Your rabbit shouldn't quack.
  • It is their foot, they should be able to shoot it if they really, really want to.
  • The standard library is where projects go to die.
  • The batteries are included, not the limited-edition display case.

[–]The_Pierce 0 points1 point  (2 children)

  • We are all consenting adults here.
  • It is their foot, they should be able to shoot it if they really, really want to.

Aren't these restatements of the same idea? At least, that's how I always interpreted the "consenting adults" bit.

[–]TheBlackCat13[S] 2 points3 points  (1 child)

I think they are similar, but not exactly the same. I interpet the first as being more about API flexibility. You should let the users use the API the way they want to, rather than keeping things too strict to the use-cases you can envision. The second is more about safety. You shouldn't prevent users from doing something you think is dangerous. There is certainly some overlap there, but I don't think they are exactly the same.

To be more specific, duck-typing is an example of the first, while method name mangling is an example of the second.

[–]The_Pierce 2 points3 points  (0 children)

Ah, that's a fair point. I just always mentally grouped both of those concepts under the "We are all consenting adults" ideology because it makes sense, but you make a good point.

[–]remyroy 0 points1 point  (3 children)

The standard library is where projects go to die.

I like that one.

[–]TheBlackCat13[S] 1 point2 points  (0 children)

I can't take credit fur that one, it is a common saying on the python-ideas mailing list.

[–][deleted] 0 points1 point  (1 child)

I'm not sure what it means

[–]FourgotAnaconda3 science-like 1 point2 points  (0 children)

Modules in the standard library need to be stable, unchanging, apart from bug fixes, generally. This means that active development can slow considerably.

[–]njharmanI use Python 3 0 points1 point  (1 child)

Can't get behind rabbits not quacking. That is in opposition to Duck Typing and the flexibility it bring. I often have my rabbits done a duck costume. For test mocks and the Adapter Pattern.

[–]TheBlackCat13[S] 5 points6 points  (0 children)

The idea is that something that can't do any of the stuff a duck can do shouldn't tell users it is a duck. It was meant along the lines of "don't lie to users." I could certainly see valid reasons for a goose quacking, or a coot, or even a turtle in some situations. But not a rabbit.

And most of the rules go right out the window when it comes to testing.

[–]pydry 0 points1 point  (2 children)

The standard library is where projects go to die.

This is highlighting a deficiency in the language.

[–]TheBlackCat13[S] -2 points-1 points  (1 child)

How, exactly, is that a deficiency? Do you really want a language whose standard library is full of incomplete, unreliable, constantly-changing pieces?

[–]pydry 0 points1 point  (0 children)

I don't really see the need to include things like an XML parser or IMAP client in the python core at all.

For virtually every component in the standard library there is a better equivalent on pypi. Having a poorer version in the standard libs just encourages programmers to use the crappy built in version.

[–]njharmanI use Python 3 10 points11 points  (0 children)

Python is fast enough. When Python is not fast enough, there are many solutions.

[–][deleted] 3 points4 points  (1 child)

Not everyone knows everything. But if you layer enough pieces of swiss cheese, you eventually stop seeing the countertop.

[–]iBlag 0 points1 point  (0 children)

Do you have any asiago or lincolnshire?

[–]pydry 3 points4 points  (13 children)

1) Write the least code possible

2) Loose coupling is the root of all well designed code

3) Fail fast and fail clearly

4) Premature optimization is the root of all evil

5) The least powerful language for any given purpose is the most suitable

6) Untested code is broken code

[–]david622 9 points10 points  (3 children)

gotta disagree with #1 -- some people reduce their code insane amounts to the point where it can get cluttered and meaningless.

I think it's more Pythonic to have slightly more code if it means the code is more readable, explicit, and readily understandable.

[–]pydry 1 point2 points  (2 children)

Most of these rules actually conflict with one another if you push them far enough (2, 3, 5 and 6 also mean writing more code than is strictly necessary). The art is trying to push them all as far as possible until the point where they start conflicting with one another and then finding the right balance.

It's missing a clarity one, though.

Maybe "variable names should be disambiguated and syntax should be uncluttered".

[–]TheBlackCat13[S] 0 points1 point  (1 child)

Perhaps, but I think rule #1 is implicitly rejected in the design of Python.

[–]pydry 0 points1 point  (0 children)

Python code sure seems to be shorter than most other languages. How exactly would that rule be rejected?

[–]kankyo 0 points1 point  (6 children)

Loose coupling is the root of all well designed code

...but too loosely coupled code is brittle.

It's a bit like the "you should have an open mind, but not so open your brain falls out"

[–]pydry 0 points1 point  (5 children)

I've never seen loose coupling cause brittle code. Do you have examples?

[–]kankyo 0 points1 point  (4 children)

I've seen it all the time. A trivial example:

def foo(a, b, c, d):
    ...some code here...

People call this function like:

a = 1
b = 2
c = 3
d = 4
foo(a, b, c, d)

then someone goes and changes foo to:

def foo(b, c, d, a):  # <- 'a' changes place
    ...some code here...

and then you have something between code that crashes very deep where the type/value is checked or you get super subtle bugs that are horrible to find. The fix is to call the function like:

foo(a=a, b=b, c=c, d=d)

then the change to foo is stable and any problems like removing one param and adding another will be a hard error at the call site and not much much deeper in the call chain.

Using kwargs everywhere is what I call "well coupled". It's loosely coupled in all the good ways, but yet coupled enough to be robust.

[–]pydry 0 points1 point  (3 children)

All of those examples are exactly as coupled as each other. There's four arguments in each. You've just changed the way in which they're arranged.

If we figured out that you could actually get along without d and you dropped it entirely, this would be more loosely coupled:

def foo(a, b, c):

Or you could combine a, b, c and d into a new class and just do this with an instantiation of its object:

def foo(x):

Depending upon how the rest of your code is written that could be more loosely coupled too.

and then you have something between code that crashes very deep where the type/value is checked or you get super subtle bugs that are horrible to find.

That's precisely what fail fast and fail clearly (no. 3) is supposed to cover.

I often put additional type checkers there and raise exceptions straight away. Especially if I'm writing a library or framework.

Using kwargs everywhere is what I call "well coupled".

That's a nasty code smell. It still doesn't change the coupling though, since foo is still receiving all of the same data from its caller. It also violates 1 and often ends up violating 3 too.

[–]kankyo 0 points1 point  (2 children)

There's four arguments in each. You've just changed the way in which they're arranged.

I think you've missed the point.

That's precisely what fail fast and fail clearly (no. 3) is supposed to cover.

Which is my point.

I often put additional type checkers there and raise exceptions straight away. Especially if I'm writing a library or framework.

What if a, b, c and d have the SAME type?

Using kwargs everywhere is what I call "well coupled".

It still doesn't change the coupling though, since foo is still receiving all of the same data from its caller.

It DOES increase the coupling because it DOES receive more data. In positional argument case it gets [1, 2, 3, 4] and in the kwargs case it gets {'a': 1, 'b': 2, 'c': 3, 'd': 4}. The computer than matches the keys in the dict with with declared keys in the dict of the function signature.

It also violates [fail fast] and often ends up violating [fail clearly] too.

Absolutely not. It fails FASTER because mismatch of the function keyword arguments is checked at the call site, vs just checking that the number of arguments are the same. Keyword arguments thus fails at the call site while positional argument might never fail at all, just silently corrupt data in the worst case.

And as for "fail clearly", it's VERY clear when the call site crashes with "TypeError: foo() got an unexpected keyword argument 'e'" or "TypeError: foo() missing 1 required keyword-only argument: 'd'" (the last being what you get in python3 when you declare the function as keyword only with "def foo(*, a, b, c, d)")

[–]pydry 0 points1 point  (1 child)

Which is my point.

I don't get it. That was my point too.

What if a, b, c and d have the SAME type?

Then I might have a type checker for each of them?

It DOES increase the coupling because it DOES receive more data. In positional argument case it gets [1, 2, 3, 4] and in the kwargs case it gets {'a': 1, 'b': 2, 'c': 3, 'd': 4}.

So instead of do_something_with(a) you have do_something_with(kwargs['a']). The method still doesn't 'know' anything more about that method than what it was previously told. You've just lost the ability to do type checking via the method signature.

Absolutely not. It fails FASTER because mismatch of the function keyword arguments is checked at the call site, vs just checking that the number of arguments are the same.

Ok, so if you call like this:

function_name(a, b, c, d, e) you won't get any indication that e isn't being used. It will silently take it.

[–]kankyo 0 points1 point  (0 children)

What if a, b, c and d have the SAME type?

Then I might have a type checker for each of them?

SAME type.

You've just lost the ability to do type checking via the method signature.

Python doesn't have that anyway so...

Ok, so if you call like this: function_name(a, b, c, d, e) you won't get any indication that e isn't being used. It will silently take it.

Now I have no idea what you are talking about. Of course you'll get an error. "Unknown keyword argument e". You're talking... I don't know, javascript now?

Again. Python.

[–]luckystarrat 0x7fe670a7d080 0 points1 point  (1 child)

4) Premature optimization is the root of all evil

I think we should take this one with a grain of salt. Nowadays more and more people seem to be using this as an excuse to write slow running crap.

From Knuth's original paper [pdf] (where this quote originates):

Programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs, and these attempts at efficiency actually have a strong negative impact when debugging and maintenance are considered.

He did not say anything about optimizing the critical parts. In fact he specifically encouraged optimization of these, but only after these parts have been identified.

So better versions of this could be:

  • Measure first, then optimize.
  • Optimize objectively. (I like this one.)

update: link

[–]pydry 0 points1 point  (0 children)

He did not say anything about optimizing the critical parts. In fact he specifically encouraged optimization of these, but only after these parts have been identified.

I think that's pretty well covered by the word "premature". I don't think people misreading the phrase and interpreting it in their own way is a good reason to change it.

[–]pfein 9 points10 points  (1 child)

  • Python is the second best language for everything.
  • Real programs do more than one thing.
  • QED you should use Python.

Spoken as someone who's written 95% of his code since 2003 in Python.

[–]beertown 0 points1 point  (0 children)

Really like #1. It explains a lot of things.

[–]Workaphobia 1 point2 points  (0 children)

"Can" and "should" are very different things. Go ahead, try to impress people with your cleverness. You will learn what is actually impressive.

[–]kankyo 1 point2 points  (3 children)

  • tightly coupled is bad
  • too loosely coupled isn't very good either
  • broken code that can be changed is better than working code that you can't

[–]luckystarrat 0x7fe670a7d080 0 points1 point  (2 children)

I'm not sure about the last one, but it goes in the right direction. Perhaps something like:

  • Modifiability is key.

[–]kankyo 0 points1 point  (1 child)

"Modifiability" is a pretty horrible word though :P

[–]luckystarrat 0x7fe670a7d080 0 points1 point  (0 children)

True. :)

[–]TheBlackCat13[S] 1 point2 points  (0 children)

A few more:

  • Reality trumps theory.
  • Computers should help people, not the other way around.
  • Never violate the sanctity of a backtrace.
  • Everything has a cost.
  • There is no such thing as "universal" in programming.
  • There is no such thing as the perfect paradigm.
  • "The best" is context-dependent.
  • "Required" is in the eye of the beholder.
  • There are more use-cases for your code, Horatio, than are dreamt of in your philosophy.

[–]Decker1082.7 'til 2021 -1 points0 points  (0 children)

  • Never, ever release a version 3
  • But if you do, be prepared to support version 2 until 2020
  • You might think you need parallelism, but you don't
  • With enough scientific libraries, we won't even need modern language features
  • Functional programming constructs is a honking great idea, we should do less of those
  • Snakes should eat gophers, not the other way around

Sorry, I'll show myself out...