What does Tuple[Hashable] mean in Python? - python

I came across the following piece of code:
def func(self, v: Tuple[Hashable]):
...
I know v: Tuple would mean variable v must be of type Tuple, but what does Tuple[Hashable] mean? Isn't a tuple in Python always hashable?

A tuple is only hashable if the values in the tuple are hashable themselves.
>>> hash((1,2))
-3550055125485641917
>>> hash(([1],2))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

Related

Why isinstance() not recognising list as a type?

Very basic but I can't think what I'm doing wrong so hoping maybe it's a syntax change I'm not yet aware of.
This line:
if isinstance(x, list):
Throws this error:
TypeError: isinstance() arg 2 must be a type or tuple of types
So why isinstance() not recognising list as a type?
You probably overwritten list somewhere in your program:
>>> isinstance("", list)
False
>>> list = 123
>>> isinstance("", list)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: isinstance() arg 2 must be a type or tuple of types
>>>

Update Python Dictionary with Tuple of Strings to set (key, value) fails

dict.update([other]) says
Update the dictionary with the key/value pairs from other, overwriting existing keys. Return None.
update() accepts either another dictionary object or an iterable of key/value pairs (as tuples or other iterables of length two). If keyword arguments are specified, the dictionary is then updated with those key/value pairs: d.update(red=1, blue=2).
But
>>> {}.update( ("key", "value") )
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: dictionary update sequence element #0 has length 3; 2 is required
So why does Python apparently try to use the first string of the tuple?
The argument needs to be an iterable of tuples (or other iterables of length two), e.g. a list
>>> d = {}
>>> d.update([("key", "value")])
>>> d
{'key': 'value'}
or a tuple, however this fails:
>>> d = {}
>>> d.update((("key", "value")))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: dictionary update sequence element #0 has length 3; 2 is required
The Python documentation on tuple again solves this mystery:
Note that it is actually the comma which makes a tuple, not the parentheses. The parentheses are optional, except in the empty tuple case, or when they are needed to avoid syntactic ambiguity.
I.e. (None) is not a tuple at all, but (None,) is:
>>> type( (None,) )
<class 'tuple'>
So this works:
>>> d = {}
>>> d.update((("key", "value"),))
>>> d
{'key': 'value'}
>>>
You can't omit the parentheses because
>>> d = {}
>>> d.update(("key", "value"),)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: dictionary update sequence element #0 has length 3; 2 is required
that would be said syntactic ambiguity (comma is function argument separator).

Python how to combine a string and list to a tuple

I have a string and a list
a=100
b=["abc","def"]
How do I combine these to a tuple, that looks like (abc, 100), (def, 100)? I tried
>>> for i in file:
... tuple(file, uid)
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
TypeError: tuple() takes at most 1 argument (2 given)
a=100
b=["abc","def"]
print [(i,a) for i in b]
You can do this through simple list comprehension
as the traceback said, tuple takes 1 argument, in your code, just change tuple(file, uid) to tuple([file, uid]). That is to say, tuple takes one argument which is iterable

Python3: TypeError: unhashable type: 'list' when using Counter

I am using Python 3 and I have this code:
from collections import Counter
c = Counter([r[1] for r in results.items()])
But when I run it I get this error:
Traceback (most recent call last):
File "<pyshell#100>", line 1, in <module>
c = Counter([r[1] for r in results.items()])
File "C:\Python33\lib\collections\__init__.py", line 467, in __init__
self.update(iterable, **kwds)
File "C:\Python33\lib\collections\__init__.py", line 547, in update
_count_elements(self, iterable)
TypeError: unhashable type: 'list'
Why am I getting this error? The code was originally written for Python 2, but I am using it in Python 3. Is there anything that changed between Python 2 and 3?
The docs say:
A Counter is a dict subclass for counting hashable objects.
In your case it looks like results is a dict containing list objects, which are not hashable.
If you are sure that this code worked in Python 2, print results to see its content.
Python 3.3.2+ (default, Oct 9 2013, 14:50:09)
>>> from collections import Counter
>>> results = {1: [1], 2: [1, 2]}
>>> Counter([r[1] for r in results.items()])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/vic/projects/venv/trains/lib/python3.3/collections/__init__.py", line 467, in __init__
self.update(iterable, **kwds)
File "/home/vic/projects/venv/trains/lib/python3.3/collections/__init__.py", line 547, in update
_count_elements(self, iterable)
TypeError: unhashable type: 'list'
By the way, you can simplify your construction:
Counter(results.values())

Python unhashable type: 'OrderedDict'

I am not at all unfamiliar with the concept of:
TypeError: unhashable type: 'OrderedDict'
But I can not understand how the following line of codes can produce such a stack-trace.
89: #staticmethod
90: def diff(var1, var2, path=[], level=0, curpath=[]):
...
101: elif isinstance(var1, list) and isinstance(var2, list):
102: l1s = set(var1)
103: l2s = set(var2)
104: retlist = []
File "myFile.py", line 102, in diff
l1s = set(var1)
TypeError: unhashable type: 'OrderedDict'
How can line 102, in the above code throw such an exception?
Some data structures (most notably dicts and sets) require objects they contain (keys in the case of dictionaries, items in the case of sets) to implement the __hash__() magic method, so that calling hash(obj) returns a value.
This is required to optimize the structure, and together with immutability to help guarantee uniqueness of contained objects.
In your case, var1 contains some object that is not hashable (it does not implement hash()). This object is an OrderedDict, which is a mutable object and is not hashable by design.
As an example of an other object type which is mutable and not hashable by design, consider list and this example:
>>> L = [1, 2, 3]
>>> set([L])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> hash(L)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
If you're using set() to ensure uniqueness then you must go some other way, though it's not clear from your question.
dict(including OrderedDict) in python are mutable containers.
If a dict was hashed, its hash value would be changed as long as you changed the dict's contents.
Sets in python are based on hashes. OrderedDicts are not hashable.

Categories

Resources