简体   繁体   中英

If python set does not allow the mutable object then why it allow to add a list with single element

I read one article :

"Sets are implemented in a way, which doesn't allow mutable objects"

When I execute :

 cities = set((["Python","Perl"], ["Paris", "Berlin", "London"]))

It throws error :

TypeError: list objects are unhashable

I searched for this error and understood that set does not allow the mutable objects hence it throws this error. But as you can see the element inside the set is a tuple which is immutable so set should allow it. checked with type() But when I tried :

cities = set((["Python","Perl"]))

It worked even if the element inside the set is mutable list. I am really confused here. I am confused now. :-(

it worked even if the element inside the set is mutable list

You are initializing the set with a single argument (["Python","Perl"]) , which is the same as ["Python","Perl"] , ie a list of strings.

The set unpacks this list, leaving it with two elements of type str :

>>> cities = set((["Python","Perl"]))
>>> for c in cities: print type(c), c
<type 'str'> Python
<type 'str'> Perl

First of all, hashable and immutable are not the same thing. The python glossary contains a definition of hashable:

An object is hashable if it has a hash value which never changes during its lifetime (it needs a hash () method), and can be compared to other objects (it needs an eq () or cmp () method). Hashable objects which compare equal must have the same hash value.

Hashability makes an object usable as a dictionary key and a set member, because these data structures use the hash value internally.

All of Python's immutable built-in objects are hashable, while no mutable containers (such as lists or dictionaries) are. Objects which are instances of user-defined classes are hashable by default; they all compare unequal (except with themselves), and their hash value is their id().

As you can see, any object that implements __hash__ , __eq__ and __cmp__ can be added to a set. The wisdom of implementing these methods for highly mutable objects such as lists is questionable, but it can be done. Immutability is by no means a requirement.

Secondly a set can be initialized from a list, as long as each of elements is hashable. The line cities = set((["Python","Perl"])) constructs a set with Python and Perl as the elements. Note that the extra parentheses do not create a tuple. Adding an extra comma, cities = set((["Python","Perl"],)) would give you the same error as before since now you will have a tuple. In this case, the tuple attempts to compute a hash, but its hash depends on the hashes of the lists, which do not exist.

If you want a tuple of tuples in your example you should try:

cities = set((("Python","Perl"), ("Paris", "Berlin", "London")))
print cities #Output set([('Paris', 'Berlin', 'London'), ('Python', 'Perl')])
type(cities) #Output <type 'set'>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM