当前位置:  开发笔记 > 编程语言 > 正文

在Python中创建类的开销:使用类的完全相同的代码是本机DS的两倍慢?

如何解决《在Python中创建类的开销:使用类的完全相同的代码是本机DS的两倍慢?》经验,为你挑选了1个好方法。

我使用所有列表函数在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

Dakkaron.. 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': , '__module__': '__main__', '__doc__': None}

如果你动态地定义一个函数(所以不是在类声明中但是在创建对象之后)函数不会转到x.__class__.__dict__但是转而去x.__dict__.

还有两个dicts可以保存当前函数可以访问的所有变量.有globals()locals()包括所有全局和局部变量.

所以,现在让我们说,你有一个对象x类的X具有功能yz这是在类的声明和第二函数声明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

如您所见,类空间方法需要花费更多时间进行查找,对象空间方法也很慢.最快的选择是本地功能.

但是你可以在不牺牲课程的情况下解决这个问题.可以说,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

对象的成员变量也会发生类似的事情.它们也比局部变量慢.如果调用函数或使用作为另一个对象的成员变量的对象中的成员变量,则效果也会增加.所以举个例子

a.b.c.d.e.f()

因为每个点需要另一个字典查找,所以会慢一点.

官方Python性能指南建议在代码的性能关键部分避免使用点:https: //wiki.python.org/moin/PythonSpeed/PerformanceTips



1> Dakkaron..:

首先,警告:函数调用很少会限制你的速度.这通常是不必要的微优化.只有这样,如果它实际上限制了你的表现.之前做一些好的分析,看看是否有更好的优化方法.

确保您不会因为这种微小的性能调整而牺牲易读性!

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': , '__module__': '__main__', '__doc__': None}

如果你动态地定义一个函数(所以不是在类声明中但是在创建对象之后)函数不会转到x.__class__.__dict__但是转而去x.__dict__.

还有两个dicts可以保存当前函数可以访问的所有变量.有globals()locals()包括所有全局和局部变量.

所以,现在让我们说,你有一个对象x类的X具有功能yz这是在类的声明和第二函数声明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

如您所见,类空间方法需要花费更多时间进行查找,对象空间方法也很慢.最快的选择是本地功能.

但是你可以在不牺牲课程的情况下解决这个问题.可以说,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

对象的成员变量也会发生类似的事情.它们也比局部变量慢.如果调用函数或使用作为另一个对象的成员变量的对象中的成员变量,则效果也会增加.所以举个例子

a.b.c.d.e.f()

因为每个点需要另一个字典查找,所以会慢一点.

官方Python性能指南建议在代码的性能关键部分避免使用点:https: //wiki.python.org/moin/PythonSpeed/PerformanceTips

推荐阅读
mobiledu2402851373
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有