Skip to content

return Hashable from functools._make_key #5385

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 9, 2021
Merged

Conversation

Akuli
Copy link
Collaborator

@Akuli Akuli commented May 9, 2021

#5370 added functools._make_key. Its purpose is to return a hashable object to represent args and kwargs, so even though it returns two different things, returning Hashable works in both cases.

@Harmouch101 What do you think?

@github-actions
Copy link
Contributor

github-actions bot commented May 9, 2021

According to mypy_primer, this change has no effect on the checked open source code. 🤖🎉

@wiseaidev
Copy link
Contributor

Nope, it returns either Hashable or _HashedSeq inherited from list(not hashable!) because of:

>>> from functools import _make_key
>>> _make_key(('aa'),{},False)
['a', 'a']
>>> type(_make_key(('aa'),{},False))
<class 'functools._HashedSeq'>
>>> _make_key((1,),{'a':'b'},False )
[1, <object object at 0x7fbc462daeb0>, 'a', 'b']
>>> type(_make_key((1,),{'a':'b'},False ))
<class 'functools._HashedSeq'>

# if len(args) == 1 and type(key[0]) in fasttypes, it returns one of the fasttypes: {int,str} which is hashable

>>> _make_key(('a'),{},False)
'a'
>>> type(_make_key(('a'),{},False))
<class 'str'>
>>> _make_key(([1]),{},False)
1
>>> type(_make_key(([1]),{},False))
<class 'int'>

@Akuli
Copy link
Collaborator Author

Akuli commented May 9, 2021

_HashedSeq is hashable, because it defines __hash__. That's the whole purpose of having _HashedSeq instead of just using a list.

@wiseaidev
Copy link
Contributor

Well, it turns out to be hashable, but I thought maybe it inherits from list would make it not Hashable. Then, I decided to test it myself.

>>> from collections.abc import Hashable 
>>> isinstance(_make_key((1,),{'a':'b'},False ), Hashable)
True

Nice catch!

@wiseaidev
Copy link
Contributor

Maybe the __repr__ made me think it is a list object.

@wiseaidev
Copy link
Contributor

At the end of the day, I think no one would like to annotate a variable like:

key: _HashedSeq =  _make_key(args, kwargs, False ) 

But rather:

key: Hashable =  _make_key(args, kwargs, False ) 

However, giving the programmer more options would be kind.

@Akuli
Copy link
Collaborator Author

Akuli commented May 9, 2021

If you need the key to be a _HashedSeq specifically:

  • Before this PR, you need assert isinstance(key, _HashedSeq) to convince mypy that it is actually a _HashedSeq. Otherwise mypy thinks "it can be _HashedSeq or any other Hashable, so let's error if you assume it's _HashedSeq".
  • After this PR, the whole _HashedSeq is gone from the stubs and assert isinstace(key, _HashedSeq) will error. We can add it back later if someone actually wants to do this.

In general, we support undocumented non-public things (name starts with _, like _make_key and _HashedSeq) only if someone actually needs them, and if anyone needs this, we can add _HashedSeq back.

@Akuli Akuli merged commit 933787d into python:master May 9, 2021
@Akuli Akuli deleted the make_key branch May 9, 2021 17:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants