Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Improve the Efficiency of Python3.11.1 __getattr__ #102213

Closed
Labels
performancePerformance or resource usagetype-featureA feature request or enhancement
@wangxiang-hz

Description

@wangxiang-hz

Feature or enhancement

__getattr__ in Python3.11.1 is much slower than@Property and visiting an object's attribute. It's even slower than Python3.10.4.
_PyObject_GenericGetAttrWithDict is the key reason. If Python3 fails finding an attribute in normal ways, it will return NULL and raise an exception. But raising an exception has performance cost. Python3.11.1 add set_attribute_error_context to supportFine Grained Error Locations in Tracebacks. It makes things worser.

Pitch

We can use this test code:

importtimeimportsysclassA:deffoo(self):print("Call A.foo!")def__getattr__(self,name):return2@propertydefppp(self):return3classB(A):deffoo(self):print("Call B.foo!")classC(B):def__init__(self)->None:self.pps=1deffoo(self):print("Call C.foo!")defmain():start=time.time()foriinrange(1,1000000):passend=time.time()peer=end-startc=C()print(f"Python version of{sys.version}")start=time.time()foriinrange(1,1000000):s=c.ppsend=time.time()print(f"Normal getattr spend time:{end-start-peer}")start=time.time()foriinrange(1,1000000):s=c.ppaend=time.time()print(f"Call __getattr__ spend time:{end-start-peer}")start=time.time()foriinrange(1,1000000):s=c.pppend=time.time()print(f"Call property spend time:{end-start-peer}")if__name__=="__main__":main()

The result shows how slow__getattr__ is:

Python version of 3.11.1 (main, Dec 26 2022, 16:32:50) [GCC 8.3.0]Normal getattr spend time: 0.03204226493835449Call __getattr__ spend time: 0.4767305850982666Call property spend time: 0.06345891952514648

When we define__getattr__, failed to find an attribute is what we expected. If we can get this result and then call__getattr__ without exception handling, it will be faster.
I tried to modify Python3.11.1 like this:

  1. add a new function inobject.c:
PyObject*PyObject_GenericTryGetAttr(PyObject*obj,PyObject*name){return_PyObject_GenericGetAttrWithDict(obj,name,NULL,1);}
  1. changetypeobject.c :
if (getattribute==NULL||        (Py_IS_TYPE(getattribute,&PyWrapperDescr_Type)&&         ((PyWrapperDescrObject*)getattribute)->d_wrapped==         (void*)PyObject_GenericGetAttr))// res = PyObject_GenericGetAttr(self, name);res=PyObject_GenericTryGetAttr(self,name);else {Py_INCREF(getattribute);res=call_attribute(self,getattribute,name);Py_DECREF(getattribute);    }if (res==NULL) {if (PyErr_ExceptionMatches(PyExc_AttributeError))PyErr_Clear();res=call_attribute(self,getattr,name);    }Py_DECREF(getattr);returnres;

Rebuild python, it really become faster:spend time: 0.13772845268249512.

Previous discussion


getattr is much slower in Python3.11

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    performancePerformance or resource usagetype-featureA feature request or enhancement

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions


      [8]ページ先頭

      ©2009-2025 Movatter.jp