Create a set from a list using {} - python

Sometimes I have a list and I want to do some set actions with it. What I do is to write things like:
>>> mylist = [1,2,3]
>>> myset = set(mylist)
{1, 2, 3}
Today I discovered that from Python 2.7 you can also define a set by directly saying {1,2,3}, and it appears to be an equivalent way to define it.
Then, I wondered if I can use this syntax to create a set from a given list.
{list} fails because it tries to create a set with just one element, the list. And lists are unhashable.
>>> mylist = [1,2,3]
>>> {mylist}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
So, I wonder: is there any way to create a set out of a list using the {} syntax instead of set()?

Basically they are not equivalent (expression vs function). The main purpose of adding {} to python was because of set comprehension (like list comprehension) which you can also create a set using it by passing some hashable objects.
So if you want to create a set using {} from an iterable you can use a set comprehension like following:
{item for item in iterable}
Also note that empty braces represent a dictionary in python not a set. So if you want to just create an empty set the proper way is using set() function.

I asked a related question recently: Python Set: why is my_set = {*my_list} invalid?. My question contains your answer if you are using Python 3.5
>>> my_list = [1,2,3,4,5]
>>> my_set = {*my_list}
>>> my_set
{1, 2, 3, 4, 5}
It won't work on Python 2 (that was my question)

You can use
>>> ls = [1,2,3]
>>> {i for i in ls}
{1,2,3}

Related

Python list not appending [duplicate]

This question already has answers here:
Quickly append value to a list [closed]
(4 answers)
Closed 4 years ago.
I've been following a tutorial exactly but my list isn't appending--I get the error, "AttributeError: 'list' object attribute 'append' is read-only."
My code is:
mylist = [1,2,3]
mylist.append = (4)
Thank you in advance.
mylist = [1,2,3]
mylist.append = (4) # Wrong!!
append is a method that is used to add an element to an existing list object. If the object contains 3 elements and you wish to append a new element to it, you can do it as follows:
mylist.append(4)
There is something very important to note here. Whenever you do something like this:
mylist = [] # or mylist = list()
You are creating an object of type list. Hence, if you are familiar with OOP concepts, append is a member function of the class. To further verify this, you can do something like this: (Using Python 3.7)
>>> a = []
>>> type(a)
<class 'list'>
Welcome to programming!
Append is a (read-only) function. You don't assign to it, you call it.
mylist.append(4)
is what you're looking for!
append is a function so use mylist.append(4) and it should work fine.
append is an attribute of List. If you want to append an item to your list use append as a function.
mylist = [1, 2, 3]
mylist.append(4)
print(mylist)
>> [1, 2, 3, 4]
what you are currently doing it you are trying to override the append function to be = 4
append is function it takes the argument which you want to append:
e.g.
.append()

python dictionary: how does appending of items work? [duplicate]

This question already has answers here:
How do I initialize a dictionary of empty lists in Python?
(7 answers)
Closed 2 years ago.
I came across this behavior that surprised me in Python 2.6 and 3.2:
>>> xs = dict.fromkeys(range(2), [])
>>> xs
{0: [], 1: []}
>>> xs[0].append(1)
>>> xs
{0: [1], 1: [1]}
However, dict comprehensions in 3.2 show a more polite demeanor:
>>> xs = {i:[] for i in range(2)}
>>> xs
{0: [], 1: []}
>>> xs[0].append(1)
>>> xs
{0: [1], 1: []}
>>>
Why does fromkeys behave like that?
Your Python 2.6 example is equivalent to the following, which may help to clarify:
>>> a = []
>>> xs = dict.fromkeys(range(2), a)
Each entry in the resulting dictionary will have a reference to the same object. The effects of mutating that object will be visible through every dict entry, as you've seen, because it's one object.
>>> xs[0] is a and xs[1] is a
True
Use a dict comprehension, or if you're stuck on Python 2.6 or older and you don't have dictionary comprehensions, you can get the dict comprehension behavior by using dict() with a generator expression:
xs = dict((i, []) for i in range(2))
In the first version, you use the same empty list object as the value for both keys, so if you change one, you change the other, too.
Look at this:
>>> empty = []
>>> d = dict.fromkeys(range(2), empty)
>>> d
{0: [], 1: []}
>>> empty.append(1) # same as d[0].append(1) because d[0] references empty!
>>> d
{0: [1], 1: [1]}
In the second version, a new empty list object is created in every iteration of the dict comprehension, so both are independent from each other.
As to "why" fromkeys() works like that - well, it would be surprising if it didn't work like that. fromkeys(iterable, value) constructs a new dict with keys from iterable that all have the value value. If that value is a mutable object, and you change that object, what else could you reasonably expect to happen?
To answer the actual question being asked: fromkeys behaves like that because there is no other reasonable choice. It is not reasonable (or even possible) to have fromkeys decide whether or not your argument is mutable and make new copies every time. In some cases it doesn't make sense, and in others it's just impossible.
The second argument you pass in is therefore just a reference, and is copied as such. An assignment of [] in Python means "a single reference to a new list", not "make a new list every time I access this variable". The alternative would be to pass in a function that generates new instances, which is the functionality that dict comprehensions supply for you.
Here are some options for creating multiple actual copies of a mutable container:
As you mention in the question, dict comprehensions allow you to execute an arbitrary statement for each element:
d = {k: [] for k in range(2)}
The important thing here is that this is equivalent to putting the assignment k = [] in a for loop. Each iteration creates a new list and assigns it to a value.
Use the form of the dict constructor suggested by #Andrew Clark:
d = dict((k, []) for k in range(2))
This creates a generator which again makes the assignment of a new list to each key-value pair when it is executed.
Use a collections.defaultdict instead of a regular dict:
d = collections.defaultdict(list)
This option is a little different from the others. Instead of creating the new list references up front, defaultdict will call list every time you access a key that's not already there. You can there fore add the keys as lazily as you want, which can be very convenient sometimes:
for k in range(2):
d[k].append(42)
Since you've set up the factory for new elements, this will actually behave exactly as you expected fromkeys to behave in the original question.
Use dict.setdefault when you access potentially new keys. This does something similar to what defaultdict does, but it has the advantage of being more controlled, in the sense that only the access you want to create new keys actually creates them:
d = {}
for k in range(2):
d.setdefault(k, []).append(42)
The disadvantage is that a new empty list object gets created every time you call the function, even if it never gets assigned to a value. This is not a huge problem, but it could add up if you call it frequently and/or your container is not as simple as list.

python initialize nested dictionary with keys and ambiguous behavior of dict.fromkeys class method [duplicate]

This question already has answers here:
How do I initialize a dictionary of empty lists in Python?
(7 answers)
Closed 2 years ago.
I came across this behavior that surprised me in Python 2.6 and 3.2:
>>> xs = dict.fromkeys(range(2), [])
>>> xs
{0: [], 1: []}
>>> xs[0].append(1)
>>> xs
{0: [1], 1: [1]}
However, dict comprehensions in 3.2 show a more polite demeanor:
>>> xs = {i:[] for i in range(2)}
>>> xs
{0: [], 1: []}
>>> xs[0].append(1)
>>> xs
{0: [1], 1: []}
>>>
Why does fromkeys behave like that?
Your Python 2.6 example is equivalent to the following, which may help to clarify:
>>> a = []
>>> xs = dict.fromkeys(range(2), a)
Each entry in the resulting dictionary will have a reference to the same object. The effects of mutating that object will be visible through every dict entry, as you've seen, because it's one object.
>>> xs[0] is a and xs[1] is a
True
Use a dict comprehension, or if you're stuck on Python 2.6 or older and you don't have dictionary comprehensions, you can get the dict comprehension behavior by using dict() with a generator expression:
xs = dict((i, []) for i in range(2))
In the first version, you use the same empty list object as the value for both keys, so if you change one, you change the other, too.
Look at this:
>>> empty = []
>>> d = dict.fromkeys(range(2), empty)
>>> d
{0: [], 1: []}
>>> empty.append(1) # same as d[0].append(1) because d[0] references empty!
>>> d
{0: [1], 1: [1]}
In the second version, a new empty list object is created in every iteration of the dict comprehension, so both are independent from each other.
As to "why" fromkeys() works like that - well, it would be surprising if it didn't work like that. fromkeys(iterable, value) constructs a new dict with keys from iterable that all have the value value. If that value is a mutable object, and you change that object, what else could you reasonably expect to happen?
To answer the actual question being asked: fromkeys behaves like that because there is no other reasonable choice. It is not reasonable (or even possible) to have fromkeys decide whether or not your argument is mutable and make new copies every time. In some cases it doesn't make sense, and in others it's just impossible.
The second argument you pass in is therefore just a reference, and is copied as such. An assignment of [] in Python means "a single reference to a new list", not "make a new list every time I access this variable". The alternative would be to pass in a function that generates new instances, which is the functionality that dict comprehensions supply for you.
Here are some options for creating multiple actual copies of a mutable container:
As you mention in the question, dict comprehensions allow you to execute an arbitrary statement for each element:
d = {k: [] for k in range(2)}
The important thing here is that this is equivalent to putting the assignment k = [] in a for loop. Each iteration creates a new list and assigns it to a value.
Use the form of the dict constructor suggested by #Andrew Clark:
d = dict((k, []) for k in range(2))
This creates a generator which again makes the assignment of a new list to each key-value pair when it is executed.
Use a collections.defaultdict instead of a regular dict:
d = collections.defaultdict(list)
This option is a little different from the others. Instead of creating the new list references up front, defaultdict will call list every time you access a key that's not already there. You can there fore add the keys as lazily as you want, which can be very convenient sometimes:
for k in range(2):
d[k].append(42)
Since you've set up the factory for new elements, this will actually behave exactly as you expected fromkeys to behave in the original question.
Use dict.setdefault when you access potentially new keys. This does something similar to what defaultdict does, but it has the advantage of being more controlled, in the sense that only the access you want to create new keys actually creates them:
d = {}
for k in range(2):
d.setdefault(k, []).append(42)
The disadvantage is that a new empty list object gets created every time you call the function, even if it never gets assigned to a value. This is not a huge problem, but it could add up if you call it frequently and/or your container is not as simple as list.

Should I use list() or wrap in brackets?

If I have a nested dictionary and I want to make a value into a list and add to it, should I do this
mydict[my_key][my_value] = [mydict[my_key][my_value]].append(new_value)
or this
mydict[my_key][my_value] = list(mydict[my_key][my_value]).append(new_value)
The structure looks like:
{'foo': {'bar': 'hi'}}
and I want:
{'foo': {'bar': ['hi', 'bye']}}
You should not do either one.
list.append works in-place and always returns None. So, mydict[my_key][my_value] will be assigned to None after Python executes either of those lines.
You need to call list.append on its own line:
mydict[my_key][my_value] = [mydict[my_key][my_value]]
mydict[my_key][my_value].append(new_value)
Also, list() and [] are two different things.
Putting mydict[my_key][my_value] in square brackets makes a one-item list where mydict[my_key][my_value] is the item.
Using list() however tells Python to iterate over mydict[my_key][my_value] and collect its items into a list. Moreover, a TypeError will be raised if mydict[my_key][my_value] is not iterable.
Below is a demonstration of what I said above:
>>> tup = (1, 2, 3)
>>> [tup] # Places tup in a list
[(1, 2, 3)]
>>> list(tup) # Makes tup into a list
[1, 2, 3]
>>>
>>> [1]
[1]
>>> list(1) # Integers are not iterable
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable
>>>
If you want a list for each dict element, use `defaultdict``
from collections import defaultdict
mydict = defaultdict(list)
mydict[some_key].append(new_value)

Python: How to compare two lists of dictionaries

Folks,
Relative n00b to python, trying to find out the diff of two lists of dictionaries.
If these were just regular lists, I could create sets and then do a '-'/intersect operation.
However, set operation does not work on lists of dictionaries:
>>> l = []
>>> pool1 = {}
>>> l.append(pool1)
>>> s = set(l)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'
You need a "hashable" dictionary.
The items() attribute is a list of tuples. Make this a tuple() and you have a hashable version of a dictionary.
tuple( sorted( some_dict.items() ) )
You can define your own dict wrapper that defines __hash__ method:
class HashableDict(dict):
def __hash__(self):
return hash(tuple(sorted(self.items())))
this wrapper is safe as long as you do not modify the dictionary while finding the intersection.
Python won't allow you to use a dictionary as a key in either a set or dictionary because it has no default __hash__ method defined. Unfortunately, collections.OrderedDict is also not hashable. There also isn't a built-in dictionary analogue to frozenset. You can either create a subclass of dict with your own hash method, or do something like this:
>>> def dict_item_set(dict_list):
... return set(tuple(*sorted(d.items())) for d in dict_list)
>>> a = [{1:2}, {3:4}]
>>> b = [{3:4}, {5:6}]
>>> dict(dict_item_set(a) - dict_item_set(b))
{1: 2}
>>> dict(dict_item_set(a) & dict_item_set(b))
{3: 4}
Of course, this is neither efficient nor pretty.

Categories

Resources