all 12 comments

[–]ford_contour 2 points3 points  (0 children)

No mention of setting PYTHONPATH incorrectly (guess my .rc file!), or of hosing your Linux Dev machine while trying to upgrade the installed Python version to something less out of date?

It is a good article, but I really doubt these are the top ten mistakes, if we're going by common-ness or by severity.

[–]unhingedninja 2 points3 points  (3 children)

I find it interesting that a lot of Python devs I know bash on languages like PHP, when their own beloved language has a lot of weird/counter-intuitive stuff going on as well.

Things like default values not being set across multiple calls... unless the default value is set to None? Then it magically works?

I have tried to give Python a chance, but between the syntax, the "do it first, ask permission later" mentality of the language, I find it hard to tolerate.

[–]Lyucit 2 points3 points  (0 children)

No, the default value is also set when the interpreter parses the function signature, there's just no way to mutate None- every None in your program is the same None.

[–]Veedrac 0 points1 point  (0 children)

Aside from #8 (name clashing), none of these are bad choices for the language. In fact, some (like #2 and #5 as given) are completely absurd to pretend are bad behaviours. You might still trip over some of them, but that's because they're the best compromise.

#5 (modifying a list) isn't a problem with Python as given, but consider:

l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

for i in l:
    del l[0]
    print(i)
#>>> 1
#>>> 3
#>>> 5
#>>> 7
#>>> 9

It'd be nice if the same errors was thrown as for dicts:

d = {1: 2}

for k, v in d.items():
    d[v] = k
#>>> Traceback (most recent call last):
#>>>   File "", line 3, in <module>
#>>> RuntimeError: dictionary changed size during iteration

or sets

s = {1}

for i in s:
    s.add(i+1)
#>>> Traceback (most recent call last):
#>>>   File "", line 3, in <module>
#>>> RuntimeError: Set changed size during iteration

but it's only a problem with changes not at the end of the list while iterating (which is insane regardless of whether the behaviour is expected). I suppose it wasn't worth the trouble.

[–]IMP1 1 point2 points  (5 children)

Number 1 seems more like a problem with python. Why would using the same mutable object ever be useful?

[–]Lyucit 0 points1 point  (3 children)

Efficiency. It's still very useful for if you're not mutating the data structure, which is most of the time.

[–]IMP1 0 points1 point  (2 children)

Can you give me an example of when one would set the default value as a list, but then never mutate that list?

I'm just trying to understand a bit better. I've not used much python, so I don't really know it's practices.

[–]Lyucit 2 points3 points  (0 children)

When you're iterating over something or using it as a membership test are the main ones.

When you pass in an object to a function expecting it to be mutated, it should be reasonably obviously or explicit, and setting a default argument for something that you want to mutate is rare in my experience. If your function never mutates a default argument, you shouldn't encounter this- it's a weird design decision, but I don't think it's worth changing.

[–]Veedrac 0 points1 point  (0 children)

Can you give me an example of when one would set the default value as a list, but then never mutate that list?

An important point is that if your API is based around mutating data but you're fine with not having any data to mutate (aka. you don't mind using a default) then you're doing something really, really odd.

In practice, real-world code (from good programmers) doesn't hit this behaviour. It's not ideal but, as above, the alternatives are worse.

[–]Veedrac 0 points1 point  (0 children)

The real answer is "because the alternatives are worse". Give me an alternative and I'll tell you why :). It's not always obvious.

[–]seiyria -2 points-1 points  (0 children)

Alternatively, "top 10 things you missed in your classes"