Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork2.2k
Improve__setattr__
performance of Pydantic models by caching setter functions#10868
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
codspeed-hqbot commentedNov 18, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
CodSpeed Performance ReportMerging#10868 willnot alter performanceComparing Summary
Benchmarks breakdown
|
github-actionsbot commentedNov 18, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Coverage reportClick to see where and how coverage changed
This report was generated bypython-coverage-comment-action |
please review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Cool idea, thanks! I think memoization could be helpful here. Let me circle back with some colleagues to verify.
Specifically,@dmontagu, wdyt about this? I recall you've done a lot of work on these setattr branches.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
This is great!
Smart idea to memoize most of the checks that are really only dependent on the class and attribute name. I made a couple notes and generally defer to Sydney on specific style nits, but the overall approach seems sensible to me and a good improvement.
Consider the PR approved by me, at least conceptually; I'm just not explicitly approving due to the nit comments maybe meriting some minor changes before merging.
sydney-runkle commentedNov 18, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Fantastic, thanks for the prompt review. I've give this a nit-picky review this evening, then we can move forward! This makes me think more about what else we could potentially memoize in the schema gen department... One other thing I want to make sure of - this doesn't leave us with any pickling issues? I don't think so, given passing tests, but we should check. |
d9d4272
to6f0ab2d
CompareThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Thanks, I think this is a smart idea. We might have to worry about the size of the cache for large models (with a lot of fields). If we encounter such issues, we could use proper functions defined once instead of creating lambdas everytime
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
I wouldnt worry about size of it as anyways all the fields are listed in various ClassVars. However if we want to remove the tiny overhead of field name strs we could push the handler fn into eg FieldInfo/ModelPrivateAttr.
I purposely didnt want to touch the model generation side to not make it anymore heavier than it already is. Because of the mentioned large models it could just do work for no good reason in case fields are not even used like this. |
Viicos commentedNov 19, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Not sure exactly what you mean byfield name strs /didnt want to touch the model generation side, but what I wanted to say is we could do something like this: HANDLERS= {'descriptor':lambdam,val:attribute.__set__(m,val),'cached_property':lambdam,val:m.__dict__.__setitem__(name,val), ...}def_setattr_handler(name:str,value:Any): ...ifhasattr(attribute,'__set__'):returnHANDLERS['descriptor'] ...elifisinstance(attr,cached_property):returnHANDLERS['cached_property'] So that we don't create a new function every time. |
BaseModel.__setattr__
__setattr__
performance of Pydantic models by caching setter functions
Ah yes I see! That would make sense yes |
e8afcf3
to7dfbe50
CompareThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Thanks for adding the simple dict. This looks good to me.
Overall this approach can look a bit weird as calling__setattr__
(i.e. at theinstance level) mutates a class variable that will be valid for every instance. But functionally it makes sense.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Looking good! A few more questions / comments.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Great work, thank you!
addf1f9
intopydantic:mainUh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Change Summary
Attribute setting has been pretty slow for
BaseModel
due to the extensive checks it has been doing for every__setattr__
call. PR improves performance of__setattr__
by memoizing the attribute specific handlers to the model class. This makes the attribute assigning some 7x faster. Also add missing benchmarks for attribute usage.Related issue number
fix#10853
Checklist
Selected Reviewer:@sydney-runkle