Live data from Hacker News

Anti-Patterns in Python Programming

lignos.org

161–170 of 242 posts

Re: Anti-Patterns in Python Programming

#161
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 don't use this as a trick question. I ask them to describe mutable vs immutable objects and gotchas. Then I write this function and ask them to describe in excruciating detail what it does, why, and how.

It is simply a easy way to gauge a candidate's proficiency with the language. It also helps if they know that this is a problem. You'd be shocked to know a lot of people on the market for jobs writing python don't get this question correct, but the smart ones often do when talking through it even if they didn't originally.

Re: Anti-Patterns in Python Programming

#162
post #54
post #35

I always struggle to understand why a list comprehension alist = [foo(word) for word in words] is considered more Pythonic than map alist = map(foo, words)

Don't know if this is why , but the list comprehension takes an expression at the "foo(word)" location, and is therefore more general than map, which requires a function. The comprehension in that case is simpler. words = ['w1', 'w2', 'w3'] [word[1] for word in words] ['1', '2', '3'] map(lambda x: x[1], words) ['1', '2', '3'] I like looking at the list comprehension better. The use of lambda looks forced in this case…

In that case I'd use

  map(itemgetter(1), words)

Re: Anti-Patterns in Python Programming

#163
post #103
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…

The other scoping issue in python that always struck me as strange is that loop variables aren't scoped to the loop, they continue to exist after the loop completes. I can see the logic for this feature even if I don't agree with it, but what I really don't get is that the loop variables are not defined if you iterate over something that is empty: >>> for item in [1]: ... print item 1 >>> item 1 >>> for i in []: ...…

> but what I really don't get is that the loop variables are not defined if you iterate over something that is empty

if you conceptualize how a for-loop has to work as a while-loop using Python's iterator protocol (which is the only way the iterator protocol itself makes sense), it seems pretty intuitive.

That is, this:

  for item in items:
      ...1
  else:
      ...2
becomes, approximately:

  try:
      while True:
          __hidden_iter = items.iter()
          try: 
              item = __hidden_iter.next()
          except StopIteration:
              raise __NormalLoopExit
          ...1
  except __NormalLoopExit:
      ...2
If you have an empty loop, the first assignment doesn't complete (instead raising StopIteration in evaluating the right side, which raises the notional exception __NormalLoopExit, which invokes the else: clause, if any) so the variable never gets around to being created.

Re: Anti-Patterns in Python Programming

#164
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.

I'll tell you what I tell my team: it's barely more verbose, and the readability is up for extremely serious debate (I mean, everyone understands nested for loops, but the nested list comprehension thing is wierd... why is something that appears way way before the innermost "for" the same as something in that for loop's declaration?)

It may also be less efficient. When I'm shown numbers that the difference between the comprehension and the for loops are (in each specfic instance, or in aggregate for the program in question) is above statistical noise AND it's a significant factor in overall runtime (I won't ever worry about a millisecond when the runtime is 1s), then I'll gladly say: put them in.

Until then, just use the loops. Use of really strange language features that are surprising, not exactly idiomatic (this argument is common for this case) and not shown to be of actual benefit, are detrimental in a polyglot environment.

Re: Anti-Patterns in Python Programming

#165
post #93

Earlier quoted context omitted.

Not the op, but I'd accept the confusion response of: [[]] [[],[]] [[],[],[]] because the behavior is the same, whether or not they misread an 'l' as a 1.

Python doesn't seem to agree with you :^) In [1]: a = [] In [2]: a.append(a) In [3]: a Out[3]: [[...]] In [4]: a[0] Out[4]: [[...]] In [5]: a[0][0] Out[5]: [[...]] In [6]: a[0][0][0] Out[6]: [[...]] In [7]: a[0][0][0][0] Out[7]: [[...]] In [8]: a.append(a) In [9]: a Out[9]: [[...], [...]] In [10]: a[0][1][0] is a Out[10]: True In [11]: id(a) Out[11]: 4547140064 In [12]: id(a[0][1][0]) Out[12]: 4547140064

Yeah, the whole infinite loop thing. Wasn't fully thinking when I wrote my reply. Good catch.

Re: Anti-Patterns in Python Programming

#166
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...

The distinction between "tuple" and "immutable list" doesn't make any sense outside of a staticly-typed language, since the only difference is what other values a particular value is type-compatible with.

Re: Anti-Patterns in Python Programming

#167
post #92

Earlier quoted context omitted.

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…

> Python allows these because "why not?"

No, it allows them because the distinction that those restrictions are founded on is only useful in a statically-typed languages, and Python isn't statically typed.

> For instance, should a Vector be a list or a tuple?

A real vector/array should be its own data type (probably implemented in a C, or similar low-level, extension) that happens to implement the interface expected of an indexable, iterable collection, neither a list nor a tuple.

Re: Anti-Patterns in Python Programming

#168
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.

I'll tell you what I tell my team: it's barely more verbose, and the readability is up for extremely serious debate (I mean, everyone understands nested for loops, but the nested list comprehension thing is wierd... why is something that appears way way before the innermost "for" the same as something in that for loop's declaration?) It may also be less efficient. When I'm shown numbers that the difference between th…

When I see a list comprehension I can see with a single glance what it's doing. Not so with the 4 line for loop. Comprehensions aren't a strange language feature in Python either...it's one of the central features of Python.

Don't use something until it's proven to yield a great benefit is a very conservative approach. That may be appropriate in some cases, but I'm very glad that I am not in such a team since that would be incredibly frustrating. I much prefer an approach where you go with the choice that's most likely the better one, even if it's not 100% proven better or not a big difference.

Re: Anti-Patterns in Python Programming

#169
post #154
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()

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.

Well, this is pulled from a list of common python errors.

Using the default value in some capacity isn't that uncommon... Though maybe you were speaking to a more general case? for example, decoding a an obfuscated C file.

Re: Anti-Patterns in Python Programming

#170
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.
Post reply on HN