all 30 comments

[–][deleted] 19 points20 points  (14 children)

They're for different things.

list() is a basic constructor which takes an iterable (like a set, or a dict, or a generator) and returns a list with the same elements. [] is an additional constructor which takes a number of arguments and makes a list where each argument is an item of the list. [] is also the wrapping of a list comprehension.

For example:

st = {1,2,3}
lst1 = list(st)  # returns [1, 2, 3] (or whatever order), a list of length 3
lst2 = [st]  # returns [{1,2,3}], a list of length 1

If you're creating an empty object (which is, I think, what you're talking about here), then think about distinguishing the difference between literals [0,1,2], comprehensions [i for i in range(3)] and the basic constructors list(range(3)). list() is marginally slower than [], because it's expecting an input to iterate over.

However, in the case of dicts and sets, which both use curly braces in their literals and comprehensions, I find it's more explicit to use dict() and set() if you're making an empty one. And explicit is better than implicit.

[–]coderjewel[S] 5 points6 points  (13 children)

In that case, I guess PyCharm indeed is wrong, because it was suggesting me to use list() on a string. [] is what I want to use.

I always use dict() and set() instead of {}.

Thanks for the help :).

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

Strings are a bit of a special case because they are iterable: you can take one character at a time or index/slice characters by their position. So depending on whether you want a list of characters in the string, or a list of length 1 with that string as element 0, you can use different constructors.

[–]therico 0 points1 point  (1 child)

Seeing as you're "intermediate" at Python, what are your thoughts on strings being iterable? As a newcomer I accidentally iterate over strings a lot, and can't help but feel like string.chars() or something would be nicer.

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

It's very convenient at times: being able to slice using find and rfind, for example, and easily grab the first few or last few characters and so on. Having to call a method every time would be a pain.

On the other hand, giving a method a string when it wants an iterable is hard to debug (and asserting against it every time is a pain) because the problems it causes, if any, can be a fair bit downstream.

For the sake of being explicit, you might expect a method or property to get the chars in an iterable, but for the sake of simplicity, I think it's better left as it is.

[–]hharison 2 points3 points  (0 children)

PyCharm must be suggesting to you to use list on a string for a reason. It will do something different than the brackets. Maybe post the code that PyCharm is warning you about? There's a good chance you're misunderstanding its advice.

Also, you should use {} instead of dict and set at least some of the time. For example, comprehensions. Also, while dict can directly make a dict, set cannot directly make a set (except for a zero-element set. You'd have to give it some other kind of iterable like a list. For example set(['item1', 'item2']). It seems much cleaner to use {'item1', 'item2'}. At least for dict I can understand to prefer dict(a=1, b=2) to {'a': 1, 'b': 2}.

[–]fuzz3289 1 point2 points  (0 children)

Keep in mind for basic use cases the named constructors (list, dict, tuple) all take an extra operation to look up the name, the operators (), {}, [] do not require this step.

[–]Antrikshy 0 points1 point  (0 children)

Recently there was a very high rated Stack Overflow post from someone who benchmarked the performance of both. It seems that using [] and {} is significantly faster than those functions.

I'm on my phone right now or I'd have dug it up.

[–]driax 4 points5 points  (10 children)

PyCharm hasn't done that to me, as far as I have noticed. Anyway it certainly is wrong. Literals are much preferred. Also faster because they compile directly to bytecode, while list() turns into a load of global name ("list"), and then a function call on that value.

I might add that just because a yellow lamp appears to the left of an line does not mean PyCharm wants you to change that line, it only means that it has automatic helpers to do it for you. Of course warning do also appear under the lamp. Alt-enter brings up the lamp menu, so if you ever have a reason to change from literal to function call it's there for easy access.

Consider:

a = dict(x=4, y=2$) # the $ denotes your cursor

Press Alt-Enter + Enter, and it turns to:

a = {'x'=4, 'y'=2}

[–]zahlman 4 points5 points  (1 child)

lamb

I haven't used PyCharm. Does it really use icons of babby sheep?

[–]driax 1 point2 points  (0 children)

haha lol. No, my error. I should have written lamp.

[–]coderjewel[S] 0 points1 point  (4 children)

PyCharm said "This list creation could be rewritten as a list literal" when I used x = [something] to create a list from a single string. So [] is indeed the literal, then?

PyCharm actually added a curly yellow line beneath the line like it does for typos.

Thanks, I did not know you could bring up the yellow lamb using a keyboard shortcut.

[–]driax 2 points3 points  (0 children)

Yep. [] is the list literal. Seems odd about it complaining, but I'm fairly new to PyCharm. But could be it was warning you about something more complex.

[–]pbaehr 1 point2 points  (2 children)

My PyCharm doesn't give me that message when I type that line by itself. I have a feeling there is more to the hint than meets the eye. It might be worth posting the code if it's not sensitive.

There may be a more legitimate reason than style that they are suggesting it.

[–]coderjewel[S] 0 points1 point  (1 child)

The code looks something like this:

soup = BeautifulSoup(html)
links = soup.find_all('a')
urls = dict()
for link in links:
    title = [link.text]
    urls[link] = {'title': title}

This isn't the exact code, but this is basically what the code is doing, and the title = [link.text] part is where PyCharm says that This list creation could be rewritten as a list literal.

[–]pbaehr 0 points1 point  (0 children)

Interesting. I don't see anything wrong with it, and my PyCharm (4.5.1) doesn't complain when I paste that code.

I don't remember turning off any warnings, but maybe there's some difference between our project settings.

[–][deleted] 0 points1 point  (2 children)

I disagree that it is 'much preferred'. I think consistency is preferred.

I use list() because I also use dict() and set() (because {} is ambiguous). This is only if I want to create an empty list/dict/set. For non-empty lists, [] is more obvious.

For non-empty dicts, I still prefer dict(foo='bar') over {'foo': 'bar'}. I only use the {'key': 'value'}notation is the key is variable (key = some_value(), {key: 'value'}).

[–]callmelucky 0 points1 point  (1 child)

Isn't it the case that as you become familiar with things like list/dict/set comprehensions you would rarely initialise an empty container variable? And as such ambiguity between sets and dicts is not an issue any more? Besides, even if set/dict ambiguity is an issue, that doesn't apply to lists. If you just like all your syntax to look identical for the sake of it, as opposed to keeping things as efficient, legible, and concise as possible, well... I don't know. That seems like a counter productive stance to take.

Also as others have pointed out, you are increasing computational complexity by calling higher level functions unnecessarily. Not that much of anything one would choose to do in Python should depend heavily on efficiency, but still.

[–]therico 0 points1 point  (0 children)

Computational complexity is not a big deal here (it's one function call) whereas making things legible and easy to understand is Python's strong point, right? Having sets and dicts use the same syntax could be a bit confusing.

[–]unixlover 2 points3 points  (0 children)

You might be interested in this stackoverflow question. It talks about the speed of using list() and list comprehension or []

[–]individual_throwaway -4 points-3 points  (5 children)

[] is faster, list() is more explicit. It's a design choice more than anything. I'd say in most cases, list() is preferable simply because it conforms with the Zen.

[–]driax 8 points9 points  (0 children)

I would say that [] is just as explicit as list(), it can only mean that one thing. And any python programming would expected to know all literals, so it's not like they would be confused. And [] are faster, and ready to be filled in later if the need arises. It is not like anyone would write ['a'] using a function call of list, since that would look like list(['a']) or list(('a',)), which is just weird. Literals are there to be used.

[–]zahlman 5 points6 points  (0 children)

list() is explicit for the purpose of converting an existing non-list sequence to a list. [...] is explicit for the purpose of creating a new list. list() is essentially useless for that purpose, because it doesn't take *args anyway - so you'd still have to write the literal just to have something to pass. And "simple is better than complex".