142

I'm learning python, and I have a novice question about initializing sets. Through testing, I've discovered that a set can be initialized like so:

my_set = {'foo', 'bar', 'baz'}

Are there any disadvantages of doing it this way, as opposed to the standard way of:

my_set = set(['foo', 'bar', 'baz'])

or is it just a question of style?

nabster
  • 1,561
  • 2
  • 20
  • 32
fvrghl
  • 3,642
  • 5
  • 28
  • 36
  • 2
    The documentation does mention it, just not there. Note that that's the documentation for an deprecated module, the *real* sets are now builtin. It's in the "What’s New in Python 2.7" document, and the language reference briefly describes it: http://docs.python.org/2/reference/expressions.html#set-displays –  Jun 28 '13 at 20:38
  • @delnan I use python 2.7, so I didn't think to look in the python 3 docs. The link I posted is for 2.7, but it strangely doesn't mention this. – fvrghl Jun 28 '13 at 20:44
  • 1
    I since edited my comment, the 2.7 docs also mention this. The link you posted is outdated, a relic of the past, wrong, deprecated. Forget that it exists and use what it itself tells you to use instead: http://docs.python.org/2/library/stdtypes.html#set and http://docs.python.org/2/library/stdtypes.html#frozenset –  Jun 28 '13 at 20:46
  • @delnan Thanks for helping me out. I edited the question so that I no longer say there is no documentation for it (although there are few examples mentioning this online). – fvrghl Jun 28 '13 at 20:52
  • For passer by: Pycharm warns against using a function call when one can use a literal - there may be performance reasons - so do prefer the set literal way in new code – Mr_and_Mrs_D Nov 11 '14 at 12:57

5 Answers5

139

There are two obvious issues with the set literal syntax:

my_set = {'foo', 'bar', 'baz'}
  1. It's not available before Python 2.7

  2. There's no way to express an empty set using that syntax (using {} creates an empty dict)

Those may or may not be important to you.

The section of the docs outlining this syntax is here.

bgporter
  • 35,114
  • 8
  • 59
  • 65
64

Compare also the difference between {} and set() with a single word argument.

>>> a = set('aardvark')
>>> a
{'d', 'v', 'a', 'r', 'k'} 
>>> b = {'aardvark'}
>>> b
{'aardvark'}

but both a and b are sets of course.

Thruston
  • 1,467
  • 17
  • 23
35

From Python 3 documentation (the same holds for python 2.7):

Curly braces or the set() function can be used to create sets. Note: to create an empty set you have to use set(), not {}; the latter creates an empty dictionary, a data structure that we discuss in the next section.

in python 2.7:

>>> my_set = {'foo', 'bar', 'baz', 'baz', 'foo'}
>>> my_set
set(['bar', 'foo', 'baz'])

Be aware that {} is also used for map/dict:

>>> m = {'a':2,3:'d'}
>>> m[3]
'd'
>>> m={}
>>> type(m)
<type 'dict'> 

One can also use comprehensive syntax to initialize sets:

>>> a = {x for x in """didn't know about {} and sets """ if x not in 'set' }
>>> a
set(['a', ' ', 'b', 'd', "'", 'i', 'k', 'o', 'n', 'u', 'w', '{', '}'])
0x90
  • 39,472
  • 36
  • 165
  • 245
11

You need to do empty_set = set() to initialize an empty set. {} is an empty dict.

S3DEV
  • 8,768
  • 3
  • 31
  • 42
Arjjun
  • 1,203
  • 16
  • 15
5

I'm surprised nobody has mentioned this, but it appears there is actually a difference between those two syntaxes from what I can tell—and that is performance/optimization.

For most situations the difference should be negligible, but in your example the following is creating a set from items directly:

my_set = {'foo', 'bar', 'baz'}

While the following creates a list and then passes it to the set constructor:

my_set = set(['foo', 'bar', 'baz'])

The end results are equivalent, but we're getting them two slightly different ways. As you'd expect, the second one is a bit slower:

❯ python -m timeit 'my_set = {"foo", "bar", "baz"}'
10000000 loops, best of 5: 37.3 nsec per loop

❯ python -m timeit 'my_set = set(["foo", "bar", "baz"])'
5000000 loops, best of 5: 92.3 nsec per loop

As far as I'm aware, the {} literal syntax is the only way to skip creating an intermediate iterable when constructing a set. It's a little odd to me personally that the set constructor wasn't instead designed to take a variable number of positional arguments like so:

# This usage is invalid in real Python. If it existed,
# I would expect the call to be exactly equivalent
# to the performance of the literal syntax.
>>> set("foo", "bar", "baz")

# You would then construct a `set` from an existing
# `list` by simply unpacking the sequence.
>>> set(*["foo", "bar", "baz"])

Unfortunately, that signature doesn't exist.

Aaron Beaudoin
  • 461
  • 1
  • 5
  • 14