Skip to content

Commit 582b4a4

Browse files
committed
Rarely hash
- We use id(code) to key into _moduleless - this is cheap to resolve, and there is minimal chance of collision. - We store hash(code) into a list as value. In the rare event we store the same id for different code objects over time, this hash should distinguish. Note: 'is' comparison to a weakref would be always correct and cleaner. However, tests show such implementations have worse performance, O(N) where N = len(sys.modules). The implementation here is O(1).
1 parent 73f440d commit 582b4a4

1 file changed

Lines changed: 15 additions & 11 deletions

File tree

Lib/inspect.py

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@
151151
import builtins
152152
from keyword import iskeyword
153153
from operator import attrgetter
154-
from collections import namedtuple, OrderedDict
154+
from collections import defaultdict, namedtuple, OrderedDict
155155

156156
# Create constants for the compiler flags in Include/code.h
157157
# We try to get them from dis to avoid duplication
@@ -974,7 +974,7 @@ def getabsfile(object, _filename=None):
974974

975975
modulesbyfile = {}
976976
_filesbymodname = {}
977-
_moduleless = set()
977+
_moduleless = defaultdict(set)
978978

979979
def getmodule(object, _filename=None):
980980
"""Return the module an object was defined in, or None if not found."""
@@ -985,19 +985,21 @@ def getmodule(object, _filename=None):
985985
# Try the filename to modulename cache
986986
if _filename is not None and _filename in modulesbyfile:
987987
return sys.modules.get(modulesbyfile[_filename])
988-
# Compute hash to track moduleless objects
988+
# Check for moduleless objects
989989
code = _getcode(object)
990-
hashcode = id(code) ^ hash(code) if code else None
991-
if hashcode and hashcode in _moduleless:
992-
return None
990+
if hashes := _moduleless.get(id(code)):
991+
if hash(code) in hashes:
992+
return None
993993
# Try the cache again with the absolute file name
994994
try:
995995
file = getabsfile(object, _filename)
996996
except (TypeError, FileNotFoundError):
997-
_moduleless.add(hashcode)
998-
return None
999-
if hashcode and hashcode in _moduleless:
997+
if code:
998+
_moduleless[id(code)].add(hash(code))
1000999
return None
1000+
if hashes := _moduleless.get(id(code)):
1001+
if hash(code) in hashes:
1002+
return None
10011003
if file in modulesbyfile:
10021004
return sys.modules.get(modulesbyfile[file])
10031005
_update_module_file_name_cache()
@@ -1006,7 +1008,8 @@ def getmodule(object, _filename=None):
10061008
# Check the main module
10071009
main = sys.modules['__main__']
10081010
if not hasattr(object, '__name__'):
1009-
_moduleless.add(hashcode)
1011+
if code:
1012+
_moduleless[id(code)].add(hash(code))
10101013
return None
10111014
if hasattr(main, object.__name__):
10121015
mainobject = getattr(main, object.__name__)
@@ -1018,7 +1021,8 @@ def getmodule(object, _filename=None):
10181021
builtinobject = getattr(builtin, object.__name__)
10191022
if builtinobject is object:
10201023
return builtin
1021-
_moduleless.add(hashcode)
1024+
if code:
1025+
_moduleless[id(code)].add(hash(code))
10221026
return None
10231027

10241028
def _update_module_file_name_cache():

0 commit comments

Comments
 (0)