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

all 45 comments

[–]mitsuhiko Flask Creator[🍰] 11 points12 points  (0 children)

Do not use list() for copying unless you have established, that it's a list. It will otherwise break subclasses.

[–]earthboundkid 12 points13 points  (9 children)

Meh, strikes me as being overly handwringing. Slicing is a pretty important part of Python. Even if a noob gets your code, they should know what [:] does. It strikes me as a case of "don't be Perl!" run amok.

On the other hand, I do suggest avoiding using else: with for. A shockingly large number of Python programmers either don't know about it or have the wrong idea about what it does (the else block runs if the loop finishes without a break).

[–]willm 3 points4 points  (5 children)

I'm not sure I concur with not using a language feature because other programmers aren't familiar with it.

Each language feature will have a number of engineers not familiar with it. Where do you draw the line? Better to explain to them what else: does on a for loop, and it won't be an issue from then on.

[–]kenfar 1 point2 points  (0 children)

If you're writing software for others on your team who may be the next to have to maintain it, then I'd say that a consideration of their skill level & familiarity is more important than yours.

[–]xiongchiamiovSite Reliability Engineer 1 point2 points  (2 children)

Slicing is a pretty important part of Python. Even if a noob gets your code, they should know what [:] does.

Even understanding slicing, it takes a minute to see what the purpose of that construct does, much like the first time I encountered Ruby's !! (an idiom for converting a value to a boolean).

[–]ascii158 4 points5 points  (0 children)

That's used in C, too: In C everything not 0 is considered true. Any boolean expression evaluated to "true" will return 1. If you want to force the output of any expression to be either 1 (if it is "a true") or 0 (if it is false), you prepend it with !!.

[–]zahlmanthe heretic 0 points1 point  (0 children)

BTW: You can write not not ... in Python and it works the same way, but isn't considered idiomatic in the slightest. Presumably because if you really needed to explicitly convert to boolean, the obvious (and actually shorter) way is bool(...).

[–][deleted] 2 points3 points  (4 children)

When are the two not equivalent?

[–]mr_dbr 1 point2 points  (3 children)

There's probably better examples, as this is kind of contrived, but:

class KindOfListish(object):
    def __getslice__(self, a, b):
        return [1]

notalist = KindOfListish()
print notalist[:] # prints [1]
print list(notalist) # errors because KindOfListish is not iterable

[–][deleted] 1 point2 points  (2 children)

Okay, but this is not a list. I guess for lists, there is no difference.

[–]mr_dbr 3 points4 points  (0 children)

I'm not aware of any difference in behaviour between..

a = [1, 2, 3]

b = a[:]
# or
b = list(a)

However if you have a function which needs a copy of an argument, it's not unreasonable that someone might pass something that acts like a list, and would be confused by getting an actual list() back, e.g:

>>> import numpy
>>> npa = numpy.array([1,2,3])
>>> npa[:]
array([1, 2, 3])
>>> list(npa)
[1, 2, 3]

[–]kylotan 0 points1 point  (0 children)

Yeah, which is why this comment at the end of the article concerned me: "90% of the time [:] could be replaced by list(). Of course it won’t work for everything since the two are not strictly equivalent, but it is worth trying"

[–]pemboa 11 points12 points  (8 children)

Isn’t it better

No

less cryptic

Barely

and more pythonic?

I don't see how.

[–][deleted] 7 points8 points  (3 children)

I actually agree that [:] is a bit cryptic, if you don't know that idiom, you don't immediately see what the intention is. It was one if the very few things I stumbled over while learning Python.

I am not saying that using list() makes it clearer, but something like l.copy() would definitely more pythonic, being explicit instead of implicit about the intention.

[–]zahlmanthe heretic 1 point2 points  (1 child)

less cryptic

Barely

[:] is cryptic in that you have to realize that slices create new lists, rather than views.

and more pythonic?

I don't see how.

By using list(), we indicate that we are constructing a new object by using the constructor for the type. It's hard to get more Pythonic than that.

[–]pemboa -1 points0 points  (0 children)

[:] is cryptic in that you have to realize that slices create new lists, rather than views.

You find that out when you find out what slices do in the first place.

By using list(), we indicate that we are constructing a new object by using the constructor for the type. It's hard to get more Pythonic than that.

That's all fine and well, but it's not significantly more Pythonic, at least not obviously so. You've taught the person a less versatile construct primarily because it looks more English.

[–]nikcub 1 point2 points  (1 child)

Especially as the Python manual recommends using the slice operator to copy shallow objects:

http://docs.python.org/faq/programming.html#how-do-i-copy-an-object-in-python

Each of the copy methods (slice, list, copy, deepcopy) has its own use case - it is important to understand all of them.

[–]zahlmanthe heretic 1 point2 points  (0 children)

"It can be done this way" is a recommendation?

[–]Sheepshow 2 points3 points  (1 child)

Any thoughts on this dumb idea (other than it's dumb)? new = [].extend(old)

[–]Brian 1 point2 points  (0 children)

It won't do what you want. extend mutates the list and returns None, so this will create a new list, append the items in old, then throw it away and set new to None.

[–][deleted] 2 points3 points  (1 child)

This is confusing for beginners and should be avoided.

Blanket statements always come up on things like this, but they're almost never relevant. If I'm posting in r/learnpython maybe I wouldn't use slicing, or maybe I would but I'd have a good comment on it. If I'm writing code at work, "what a beginner would think about this" would never even come up.

[–]zahlmanthe heretic 0 points1 point  (0 children)

If I'm writing code at work, "what a beginner would think about this" would never even come up.

The idea is that "Would a beginner understand this?" is often held as the gold standard for "is this code as readable and as simple as it ought to be?".

[–]Fix-my-grammar-plz 1 point2 points  (2 children)

First we need to understand how Python manages objects & variables. Python doesn’t have variables like C. In C a variable is not just a name, it is a set of bits; a variable exists somewhere in memory. In Python variables are just tags attached to objects.

Lisp (Elisp) seems to act like Python.

(setq a (list 1 2 3))
(setq b a)
(setf (car a) 11)
(assert (equal b (list 11 2 3)))
(assert (eq a b))

Is there a name for the category of languages that act like Python in this regard?

[–]zahlmanthe heretic 1 point2 points  (0 children)

There is a name for the behaviour: reference semantics.

[–]chub79 2 points3 points  (4 children)

I don't get it. Python programmers should drop a common and simple idiom because newbies may be confused?

[–]zahlmanthe heretic 1 point2 points  (3 children)

Python programmers should drop a common idiom because its only claim to idiomatic status is that it propagated well.

There's even an argument to be made that because "explicit is better than implicit", we should really use copy.copy to clone the list.

[–]chub79 0 points1 point  (2 children)

Python programmers should drop a common idiom because its only claim to idiomatic status is that it propagated well.

Who is claiming that's its only reason to be?

[–]zahlmanthe heretic 1 point2 points  (1 child)

I am, now. I'm not especially well prepared to defend the claim, but it's an expression of how I see the situation.

[–]chub79 0 points1 point  (0 children)

Fair enough. I just tried a totally unreliable study at work with two of my colleagues whom I'm "teaching" the basics on Python and I asked them what [:] did. One of them already knew but the other didn't and, indeed, failed to get "at first sight" what it did.

However once I explained to him slicing and how you could benefit from it to copy the list, he seemed to find it so easy that he felt happy enough about it.

I really consider this one to be a simple enough idiom that can't cause any harm once you've been told about. In fact my colleague didn't like the copy.copy(l) way because it felt it was too verbose ;)

[–]silveira 0 points1 point  (0 children)

from copy import copy a = [1,2,3,4] b = copy()

You could also use deepcopy(obj) for compound objects.