Live data from Hacker News

Anti-Patterns in Python Programming

lignos.org

151–160 of 242 posts

Re: Anti-Patterns in Python Programming

#151
post #69

Earlier quoted context omitted.

Can you clarify? def foo(default_arg = []): Why can't that just be shorthand for: def foo(default_arg = ParamNone): if default_arg == ParamNone: default_arg = [] How would that break first class functions?

As a minor point, use "default_arg is ParamNone", since "==" probably won't do the right thing. What breaks is something like: def foo(default_arg = slow_f()): pass Under the shorthand gets turned into: ParamNone = object() def foo(default_arg = ParamNone): if default_arg is ParamNone: default_arg = slow_f() pass This is fine, since everyone would know that the shorthand means to not put slow code there. Instead, peo…

In Python 3 there's the nonlocal keyword to deal with the scoping thing.

The default arguments thing is worse than a lot of the stuff Python 3 corrected.

Re: Anti-Patterns in Python Programming

#152
This is a nice little article, but I wonder about some of the design decisions. In particular:

> The simplifications employed (for example, ignoring generators and the power of itertools when talking about iteration) reflect its intended audience.

Are generators really that hard? (Not a rhetorical question!)

The article mentions problems resulting from the creation of a temporary list based on a large initial list. So, why not just replace a list comprehension "[ ... ]" with a generator expression "( ... )"? Result: minimal storage requirements, and no computation of values later than those that are actually used.

And then there is itertools. This package might seem a bit unintuitive to those who have only programmed in "C". But I think the solution to that is to give examples of how itertools can be used to create simple, readable, efficient code.

Re: Anti-Patterns in Python Programming

#153
post #100
post #34

Earlier quoted context omitted.

Couldn't agree more! One of my all time new python interview questions gets a surprisingly large number of developers. Given a function like: def append_one(l=[]): l.append(1) return l What does this return each time? >>> append_one() >>> append_one() >>> append_one()

Wow, that is really ugly semantics. Here are some notes of mine on how hard R works to avoid exposing this sort of aliasing/mutability issue to the user: http://www.win-vector.com/blog/2014/04/you-dont-need-to-unde...

Yeah i really don't understand why this is just assumed to be a common 'gotcha' to be recognized and avoided by every competent python programmer. What exactly does the python spec specify as the desired behavior here? If you have this 'broken stair' that everyone should just know to step over, shouldn't somebody actually fix the stair!?

I know python is not unique in having warts like this, but it's pretty b.s. in general that unexpected behavior is just thought to be okay, especially in a language meant to be very accessible, and most especially since it's being used as a perfectly valid metric for disqualifying new python programmers from employment.

Re: Anti-Patterns in Python Programming

#154
post #34
post #3

The more frequent and dangerous pitfalls are, in my humble opinion: - Bare except: statements (that catches everything , even Ctrl-C) - Mutables as default function/method arguments - Wildcard imports!

Couldn't agree more! One of my all time new python interview questions gets a surprisingly large number of developers. Given a function like: def append_one(l=[]): l.append(1) return l What does this return each time? >>> append_one() >>> append_one() >>> append_one()

I would caution you not to interview on things you would not be happy to see in your code base.

In my experence your much better off with people that look at odd syntax and say, "I don't know what that does" vs those who do.

Re: Anti-Patterns in Python Programming

#155
post #92
post #66

Earlier quoted context omitted.

Tuples by pythonists are used as they were mere lists, just immutable. This is clearly displayed by Python's own interface. For the rest of the world, tuples are not immutable lists. They are tuples, i.e. collections of "objects" that could share nothing about their type. Tuples often are not even iterable! (Erlang, Haskell) The fact that tuples in Python can have as much structure as one wants is derived from dynami…

I'm sorry, I don't see clearly what a tuple should be. What would be different about Python tuples if they were true tuples?

In most languages you can't usually:

1. Iterate over a tuple

2. Convert a list to a tuple

3. Construct a tuple of a length not known at compile-time

Python allows these because "why not?" but it does break their "one and only one way to do it" rule and confuses beginners a hell of a lot.

There are definitely borderline cases. For instance, should a Vector be a list or a tuple? A Vec3 type is obviously a tuple, but a large Vector destined for BLAS is obviously a list.

Re: Anti-Patterns in Python Programming

#156
post #34

Earlier quoted context omitted.

Couldn't agree more! One of my all time new python interview questions gets a surprisingly large number of developers. Given a function like: def append_one(l=[]): l.append(1) return l What does this return each time? >>> append_one() >>> append_one() >>> append_one()

At what level would you test an interviewee with this kind of question: Python guru, Python expert, Python ninja, Python rockstar, or merely "is familiar with Python"? Your example is a very common gotcha that has been covered ad nauseam, but IMO it's still the kind of bug that would be caught immediately in code review and is very easily fixed.

I thought we were past using trick questions like this anyways! Since, you know, it would be easy for an experienced yet anxious programmer to get tripped up on this, but someone who just browsed "python interview questions 101" to breeze on through. Also it selects against experienced multi-language developers, since language-specific quirks like this are not generally useful information to keep front-loaded, but are trivial to become re-familiar with in a work environment, or even gasp learn for the first time from a co-worker or helpful article.

If the industry as a whole cared about evidence-based, non-superstitious, non-monoculture-reinforcing hiring practices, we'd realize that tripping people up and judging programming capability based on minutia is as unfair as it is self-defeating.

Re: Anti-Patterns in Python Programming

#157

Earlier quoted context omitted.

alist = [foo(word) for word in words if word.startswith('a')] alist = map(foo, filter(lambda word: word.startswith('a'), words)) Which reads better?

I don't use FP practices in Python much, but if I did I'd define the filter outside the map, like so: begins_with_a = lambda x: x.startswith('a') alist = map(foo, filter(begins_with_a, words))

Even with named functions, Python's use of global functions instead of methods for iterators force you to read the expression from the inside out. I think Lisp languages nailed this with their threading macros, which allow natural left-to-right reading, but Ruby's strategy is better than Python's, too, while maintaining very similar syntax.

    ;; clojure
    (let [begins-with-a #(.startsWith % "a")
          foo #(do-some-stuff-with %)]
      (-> words (filter begins-with-a) (map foo))))

    # ruby
    words.filter { |e| e.start_with?(?a) }.map { |e| foo(e) }
It doesn't really make sense for things like `len` and `map` to be global functions in object-oriented languages.

Re: Anti-Patterns in Python Programming

#158
post #66

Earlier quoted context omitted.

Tuples by pythonists are used as they were mere lists, just immutable. This is clearly displayed by Python's own interface. For the rest of the world, tuples are not immutable lists. They are tuples, i.e. collections of "objects" that could share nothing about their type. Tuples often are not even iterable! (Erlang, Haskell) The fact that tuples in Python can have as much structure as one wants is derived from dynami…

If it's so subtle, does it matter? This sounds like you just have a problem with the word "tuple" applied to an object that behaves differently from tuples in a statically-typed language. Would you feel better if they named it "ImmutableList" instead?

Can't speak for GP, but I would [feel better with that name].

(Although I agree with you that statically-typed-language-tuples don't seem to make sense in Python.)

But hey... Python's weird choice of how to name the ImmutableList could be worse, right?

For example, someone could be malicious enough to call their general-purpose associative array a "hash", just because a hashmap (note: not a hash) is a good implementation for large associative arrays. Wow, that'd be hilariously misleading, wouldn't it? Good times!

Or imagine someone was silly enough to name their auto-resizing arrays "vectors", even though in all previously existing contexts a "vector" is a sort of thing which absolutely cannot be meaningfully resized/extended. Ha. Think of the tiny cognitive burden placed on generations of future programmers-who-study-math, trying to juggle these two very-similar-but-distinct concepts, multiplied by the number of such future programmers. Amazing practical joke, right?

/rant

Re: Anti-Patterns in Python Programming

#159
post #82

Earlier quoted context omitted.

Map is not allegedly slower, it is demonstrably slower. $ python -mtimeit -s'nums=range(10)' 'map(lambda i: i + 3, nums)' 1000000 loops, best of 3: 1.61 usec per loop $ python -mtimeit -s'nums=range(10)' '[i + 3 for i in nums]' 1000000 loops, best of 3: 0.722 usec per loop Function calls have overhead in python, list comprehensions are implemented knowing this fact and avoiding it so the heavy lifting ultimately happ…

Fair enough. I said "allegedly" because I had never personally measured the performance difference. Even though you could construe map as "half as fast" (or twice as slow) as the equivalent comprehension, I don't see a difference of ~1 usec making any difference in my code thus far. Good to know, though.

Yup, for very large calculations, or certain use cases, it can make much larger differences. It all depends on your use case.

Re: Anti-Patterns in Python Programming

#160
post #94

Earlier quoted context omitted.

It has something to do with mutability, because if an object is immutable, the behavior of Python matches what the naive developer expects. It's only mutable objects that break those expectations. Don't even get into unexpected behavior in classes: In [1]: class A(object): ...: l = [] ...: In [2]: a, b = A(), A() In [3]: a.l.append("Something") In [4]: a.l Out[4]: ['Something'] In [5]: b.l Out[5]: ['Something'] In [6…

> if an object is immutable, the behavior of Python matches what the naive developer expects If the object was immutable then append wouldn't work. That's hardly matching expectations.

Read my post that has the "correct answers" which show you how to do it. The key is setting the default to None and then doing something like:

if val is None: val = []

or the more idiomatic python way:

    val = val or []
Post reply on HN