jer*_*iff 7 python performance class function
我使用所有列表函数在Python中创建了一个Stack类作为练习.例如,Stack.push()只是list.append(),Stack.pop()是list.pop(),Stack.isEmpty()只是list == [].
我正在使用我的Stack类来实现十进制到二进制转换器,我注意到的是,即使这两个函数完全等同于我的Stack类的包装,用于push(),pop()和isEmpty(),实现使用Stack类的速度是使用Python列表的两倍.
那是因为在Python中使用类总是存在固有的开销吗?如果是这样,技术上的开销来自哪里("引擎盖下")?最后,如果开销是如此重要,除非你绝对必须使用类不是更好吗?
def dectobin1(num):
s = Stack()
while num > 0:
s.push(num % 2)
num = num // 2
binnum = ''
while not s.isEmpty():
binnum = binnum + str(s.pop())
return binnum
def dectobin2(num):
l = []
while num > 0:
l.append(num % 2)
num = num // 2
binnum = ''
while not l == []:
binnum = binnum + str(l.pop())
return binnum
t1 = Timer('dectobin1(255)', 'from __main__ import dectobin1')
print(t1.timeit(number = 1000))
0.0211110115051
t2 = Timer('dectobin2(255)', 'from __main__ import dectobin2')
print(t2.timeit(number = 1000))
0.0094211101532
Run Code Online (Sandbox Code Playgroud)
Dak*_*ron 18
首先,警告:函数调用很少会限制你的速度.这通常是不必要的微优化.只有这样,如果它实际上限制了你的表现.之前做一些好的分析,看看是否有更好的优化方法.
确保您不会因为这种微小的性能调整而牺牲易读性!
Python中的类有点像黑客.
它的工作方式是每个对象都有一个__dict__字段(一个字典),它包含对象包含的所有属性.此外,每个对象都有一个__class__对象,该对象再次包含一个__dict__包含所有类属性的字段(同样是一个字典).
例如,看看这个:
>>> class X(): # I know this is an old-style class declaration, but this causes far less clutter for this demonstration
... def y(self):
... pass
...
>>> x = X()
>>> x.__class__.__dict__
{'y': <function y at 0x6ffffe29938>, '__module__': '__main__', '__doc__': None}
Run Code Online (Sandbox Code Playgroud)
如果你动态地定义一个函数(所以不是在类声明中但是在创建对象之后)函数不会转到x.__class__.__dict__但是转而去x.__dict__.
还有两个dicts可以保存当前函数可以访问的所有变量.有globals()与locals()包括所有全局和局部变量.
所以,现在让我们说,你有一个对象x类的X具有功能y和z这是在类的声明和第二函数声明z,这是动态定义.假设对象x是在全局空间中定义的.此外,为了进行比较,有两个函数flocal(),它们在局部空间中定义,并fglobal()在全局空间中定义.
现在我将展示如果您调用这些函数中会发生什么:
flocal():
locals()["flocal"]()
fglobal():
locals()["fglobal"] -> not found
globals()["fglobal"]()
x.y():
locals()["x"] -> not found
globals()["x"].__dict__["y"] -> not found, because y is in class space
.__class__.__dict__["y"]()
x.z():
locals()["x"] -> not found
globals()["x"].__dict__["z"]() -> found in object dict, ignoring z() in class space
Run Code Online (Sandbox Code Playgroud)
如您所见,类空间方法需要花费更多时间进行查找,对象空间方法也很慢.最快的选择是本地功能.
但是你可以在不牺牲课程的情况下解决这个问题.可以说,xy()被调用了很多,需要进行优化.
class X():
def y(self):
pass
x = X()
for i in range(100000):
x.y() # slow
y = x.y # move the function lookup outside of loop
for i in range(100000):
y() # faster
Run Code Online (Sandbox Code Playgroud)
对象的成员变量也会发生类似的事情.它们也比局部变量慢.如果调用函数或使用作为另一个对象的成员变量的对象中的成员变量,则效果也会增加.所以举个例子
a.b.c.d.e.f()
Run Code Online (Sandbox Code Playgroud)
因为每个点需要另一个字典查找,所以会慢一点.
官方Python性能指南建议在代码的性能关键部分避免使用点:https: //wiki.python.org/moin/PythonSpeed/PerformanceTips
使用函数会产生固有的开销(实例上的方法只是要传入的函数的包装器self)。
函数调用需要将当前函数信息(帧)存储在堆栈(Python 调用堆栈)中,并为正在调用的函数创建一个新帧。这一切都需要时间和记忆:
>>> from timeit import timeit
>>> def f(): pass
...
>>> timeit(f, number=10**7)
0.8021022859902587
Run Code Online (Sandbox Code Playgroud)
查找属性(方法也是属性)和创建方法对象(方法名称的每个属性查找都会导致创建一个新的方法对象)也有(较小的)成本:
>>> class Foo:
... bar = None
... def baz(self): pass
...
>>> timeit('instance.bar', 'from __main__ import Foo; instance = Foo()', number=10**7)
0.238075322995428
>>> timeit('instance.baz', 'from __main__ import Foo; instance = Foo()', number=10**7)
0.3402297169959638
Run Code Online (Sandbox Code Playgroud)
因此,属性查找、方法对象创建和调用堆栈操作的总成本加起来就是您观察到的额外时间要求。
| 归档时间: |
|
| 查看次数: |
5702 次 |
| 最近记录: |