Skip to content

Commit 5a4fcb7

Browse files
committed
Skip redundant re-validation of constructor kwargs
HasTraits.__init__ validated every trait kwarg twice: once via setattr in the fast loop, then again via _cross_validate + set_trait. The second pass is only needed for traits that actually have a cross-validator (@Validate handler or a deprecated _<name>_validate method); for the common case with none it re-ran validate() on an already-validated value. The second loop now guards on the same condition _cross_validate itself uses (key in self._trait_validators or a _<name>_validate attribute exists). For traits without a cross-validator it records the already-stored (possibly coerced) value for the notification instead of re-validating, so notification payloads are byte-for-byte identical. Measured (Python 3.11): instantiation with kwargs and no cross-validators ~1.2-1.4x faster. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VaKDJ3fpGf7anQeYeBsJbk
1 parent 6941a69 commit 5a4fcb7

1 file changed

Lines changed: 11 additions & 3 deletions

File tree

traitlets/traitlets.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1394,9 +1394,17 @@ def ignore(change: Bunch) -> None:
13941394
# notify and cross validate all trait changes that were set in kwargs
13951395
changed = set(kwargs) & set(self._traits)
13961396
for key in changed:
1397-
value = self._traits[key]._cross_validate(self, getattr(self, key))
1398-
self.set_trait(key, value)
1399-
changes[key]["new"] = value
1397+
# Only re-run the (relatively expensive) cross-validation +
1398+
# set_trait pass for traits that actually have a cross-validator.
1399+
# For the common case with none, the value stored by the fast
1400+
# loop above is already fully validated; we just need to record
1401+
# the (possibly coerced) stored value for the notification.
1402+
if key in self._trait_validators or hasattr(self, f"_{key}_validate"):
1403+
value = self._traits[key]._cross_validate(self, getattr(self, key))
1404+
self.set_trait(key, value)
1405+
changes[key]["new"] = value
1406+
else:
1407+
changes[key]["new"] = getattr(self, key)
14001408
self._cross_validation_lock = False
14011409
# Restore method retrieval from class
14021410
del self.notify_change

0 commit comments

Comments
 (0)