Live data from Hacker News

Anti-Patterns in Python Programming

lignos.org

181–190 of 242 posts

Re: Anti-Patterns in Python Programming

#181

Speaking of find\_item, is the `for..else` loop (which can be used to write find\_item in another way) considered Pythonic? I personally like `for..else` loops but I don't know where the consensus is at.

http://en.wikipedia.org/wiki/No_true_Scotsman Don't ask what's "more Pythonic" or "less Pythonic", Python is not a cult, it's a very practical scripting language. Ask for benefits and weaknesses of a given approach in given circumstances.

Speaking a language in the same way as other speakers of that language makes you easier to understand.

Re: Anti-Patterns in Python Programming

#182
post #150

Earlier quoted context omitted.

Everybody, listen to this person!

Then it turns into this: x = [] for word in words: for letter in word: x.append(letter) Which in addition to being far more verbose and less readable, is also less efficient.

For loops can often be avoided. I would write this particular example in one of these ways, that I think are readable:

    x = []
    for word in words:
        x.extend(word)

    from itertools import chain
    x = [letter for letter in chain(*words)]

    x = list(chain(*words))

Re: Anti-Patterns in Python Programming

#183
post #69

Earlier quoted context omitted.

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.

I don't see how nonlocal could fix this. Could you explain?

More specifically, given a better 'default arguments thing', how would you interpret:

    x = [2]
    def f(x=x*5):
        x.append(4)
With the earlier conversion it's:

    x = [2]
    def f(x=DefaultArg):
        if x is DefaultArg:
            x = x*5
        x.append(4)
This isn't going to work because the x inside of f() is different than the outside x, and you'll get the error message I mentioned.

If you add a nonlocal, as in:

    x = [2]
    def f(x=DefaultArg):
        nonlocal x
        if x is DefaultArg:
            x = x*5
        x.append(4)
then you'll get "SyntaxError: name 'x' is parameter and nonlocal".

What other solution are you thinking of?

Re: Anti-Patterns in Python Programming

#184
post #24

Earlier quoted context omitted.

Why even use a list here? Tuples are for immutable/constant data. a_tuple_of_words = ("my", "tuple", "of", "words") or a_tuple_of_words = "my", "tuple", "of", "words"

...because it's a list? Tuples were supposed to have a structure (at least that's what all the rest of the world thinks of them), so iterating through combination of apples, cars and languages makes no sense whatsoever. But yes, Python misses entirely the point of tuples, treating them as read-only lists. http://dozzie.jogger.pl/2014/04/11/python-tuples-the-useless...

> Tuples were supposed to have a structure (at least that's what all the rest of the world thinks of them)

No, a structure is, you know, a structure -- what C calls a struct. Python calls it a namedtuple. If some people call it just a tuple, well, that's a difference in terminology, but it doesn't mean Python is confused about the concepts, it's just using terminology you're not used to.

Also, if we're going to be pedantic about the meaning of data types, your blog post is wrong about lists. You say "position in the list doesn't matter", but that means ordering doesn't matter, and an unordered collection of similar objects is a set, not a list. Python makes this distinction clear: a list is ordered, a set is not.

Re: Anti-Patterns in Python Programming

#185
post #172

Earlier quoted context omitted.

> The default value gets created when the function is interpreted ("compiled"). No. The default value gets "created" (the expression is evaluated and stored) when the def statement is executed. Take the following example: In [1]: def foo(): ...: def append_five(l=[]): ...: l.append(5) ...: return l ...: return append_five ...: In [2]: a = foo() In [3]: b = foo() In [4]: a() Out[4]: [5] In [5]: b() Out[5]: [5] In [6]:…

I thought that was what he meant. Is there any sharp distinction between "interpreting" and "evaluating" in python that I am unaware of? I've always used the words more or less interchangeably. But now that I think about it that might be a little naive since I have no idea how it works under the hood

The parent wrote "compiled", which is certainly more incorrect than either "interpreted" or "evaluated."

Re: Anti-Patterns in Python Programming

#186
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 think the idea is to see whether the interviewee is a kind of person who always googles and reads on "gotchas of language X" whenever he/she learns X.

Re: Anti-Patterns in Python Programming

#187
post #150

Earlier quoted context omitted.

Then it turns into this: x = [] for word in words: for letter in word: x.append(letter) Which in addition to being far more verbose and less readable, is also less efficient.

For loops can often be avoided. I would write this particular example in one of these ways, that I think are readable: x = [] for word in words: x.extend(word) from itertools import chain x = [letter for letter in chain(*words)] x = list(chain(*words))

Wouldn't chain(*words) require unpacking all of words before feeding it into the chain function, storing a second copy of the word list in memory?

Re: Anti-Patterns in Python Programming

#188
> Things like parsing arguments are best delegated to a function named main, so that any internal variables in that function do not live in the outer scope.

Why a function named `main`? We're not writing C here, there's no need for a function named `main`. Let's call it something that's actually useful, like `parse_cmd_arguments`

Re: Anti-Patterns in Python Programming

#190

Failing to use join is a big one. I have seen countless instances of people writing the logic to output commas in between items (like for CSV export) that they want to concatenate into a string. header_line = ','.join( header for header in headers ) csv_line = ','.join( str(dataset[key]) for key in dataset.keys() ) Example for a case of a dictionary mapping a string to a bunch of numbers.

Any reason not to do the first one more compactly? ','.join(headers)

Oops. Good catch!
Post reply on HN