I run this code on Python3.11.1 and Python3.10.4:
import time
import sys
class A:
def foo(self):
print("Call A.foo!")
def __getattr__(self, name):
return 2
@property
def ppp(self):
return 3
class B(A):
def foo(self):
print("Call B.foo!")
class C(B):
def __init__(self) -> None:
self.pps = 1
def foo(self):
print("Call C.foo!")
def main():
start = time.time()
for i in range(1, 1000000):
pass
end = time.time()
peer = end - start
c = C()
print(f"Python version of {sys.version}")
start = time.time()
for i in range(1, 1000000):
s = c.pps
end = time.time()
print(f"Normal getattr spend time: {end - start - peer}")
start = time.time()
for i in range(1, 1000000):
s = c.ppa
end = time.time()
print(f"Call __getattr__ spend time: {end - start - peer}")
start = time.time()
for i in range(1, 1000000):
s = c.ppp
end = time.time()
print(f"Call property spend time: {end - start - peer}")
if __name__ == "__main__":
main()
My environment is debian 10.3 and I got this result:
Python version of 3.11.1 (main, Dec 26 2022, 16:32:50) [GCC 8.3.0]
Normal getattr spend time: 0.03204226493835449
Call __getattr__ spend time: 0.4767305850982666
Call property spend time: 0.06345891952514648
Python version of 3.10.4 (main, Dec 15 2022, 11:24:32) [GCC 8.3.0]
Normal getattr spend time: 0.044233083724975586
Call __getattr__ spend time: 0.3127727508544922
Call property spend time: 0.08991670608520508
As you can see, Python3.11.1 is faster than Python3.10.4, except for __getattr__
.
I compared slot_tp_getattr_hook
in typeobject.c in Python3.11.1 with Python3.10.4, and changed _PyType_Lookup
back to _PyType_LookupId
. But it doesn’t work and is still slower.
Can anyone know why? Thanks.