Skip to content

Commit 4b81afe

Browse files
committed
perf: replace KeyError exception with dict.get() in BoundStatement.bind()
Replace try/except KeyError with dict.get() + sentinel pattern in the per-column binding loop of BoundStatement.bind(). This loop runs once per column per execute() call for dict-style bindings, making it a hot path. Using dict.get() avoids the overhead of raising and catching KeyError for every missing/optional column. The sentinel object (_BIND_SENTINEL) is necessary to distinguish a missing key from an explicit None value in the bound dict.
1 parent 9c53d78 commit 4b81afe

1 file changed

Lines changed: 12 additions & 9 deletions

File tree

cassandra/query.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@
4949
Only valid when using native protocol v4+
5050
"""
5151

52+
_BIND_SENTINEL = object()
53+
"""Sentinel for dict.get() in BoundStatement.bind() to distinguish missing keys from None values."""
54+
5255
NON_ALPHA_REGEX = re.compile('[^a-zA-Z0-9]')
5356
START_BADCHAR_REGEX = re.compile('^[^a-zA-Z0-9]*')
5457
END_BADCHAR_REGEX = re.compile('[^a-zA-Z0-9_]*$')
@@ -608,15 +611,15 @@ def bind(self, values):
608611

609612
# sort values accordingly
610613
for col in col_meta:
611-
try:
612-
values.append(values_dict[col.name])
613-
except KeyError:
614-
if proto_version >= 4:
615-
values.append(UNSET_VALUE)
616-
else:
617-
raise KeyError(
618-
'Column name `%s` not found in bound dict.' %
619-
(col.name))
614+
val = values_dict.get(col.name, _BIND_SENTINEL)
615+
if val is not _BIND_SENTINEL:
616+
values.append(val)
617+
elif proto_version >= 4:
618+
values.append(UNSET_VALUE)
619+
else:
620+
raise KeyError(
621+
'Column name `%s` not found in bound dict.' %
622+
(col.name))
620623

621624
value_len = len(values)
622625
col_meta_len = len(col_meta)

0 commit comments

Comments
 (0)