我正在做一些性能关键的Python工作,希望创建一个函数,如果满足某些条件,则从列表中删除一些元素。我不想创建列表的任何副本,因为它包含了很多非常大的对象。
我要实现的功能:
def listCleanup(listOfElements):
i = 0
for element in listOfElements:
if(element.meetsCriteria()):
del(listOfElements[i])
i += 1
return listOfElements
myList = range(10000)
myList = listCleanup(listOfElements)
我不熟悉Python的底层工作。myList是按值传递还是按引用传递?
我怎样才能让这个更快?
是否可以以某种方式扩展list类并在其中实现listCleanup()?
myList = range(10000)
myList.listCleanup()
谢谢-
乔纳森
看起来是过早的优化。在尝试优化之前,您应该尝试更好地了解python的工作原理。
在这种情况下,您不需要担心对象的大小。复制列表是使用列表理解,或者slice只执行表面复制(复制对对象的引用,即使该术语并不真正适用于python)。但列表中的项目数可能很重要,因为del是O(n)。可能还有其他的解决方案,比如用None或传统的空对象替换一个项,或者使用另一个数据结构(如set或dictionary),这样删除项的成本要低得多。
Python以相同的方式传递所有内容,但称之为“按值”或“按引用”并不能清除所有内容,因为Python的语义与这些术语通常适用的语言不同。如果我要描述它,我会说所有传递都是按值传递的,并且该值是一个对象引用。(这就是我不想说的原因!)
如果你想从列表中筛选出一些内容,你需要建立一个新的列表
或者,使用列表理解语法
Python不会复制列表中的对象,而是
foo
和new_foo
都将引用相同的对象。(Python从不隐式复制任何对象。)你建议你对这个操作有性能问题。从旧列表中使用重复的
del
语句将不会导致代码不那么惯用,处理起来更加混乱,但它将引入二次型性能,因为每次都必须重新整理整个列表。要解决性能问题:
启动并运行它。除非代码正常工作,否则您无法了解自己的性能。这也将告诉您必须优化的是速度还是空间;您在代码中提到了对这两者的关注,但通常优化需要以牺牲另一个为代价。
配置文件。您可以使用the stdlib tools来及时提高性能。有各种第三方内存分析器,它们可能有些有用,但不是很好用。
测量。Time或在您进行更改时重新设置内存,以查看更改是否有改进,如果有,则说明改进是什么。
为了提高代码的内存敏感性,通常需要改变存储数据的方式,而不是像不构建第二个列表来进行筛选这样的微观优化。(时间也是如此,真的:改变到一个更好的算法几乎总是给最好的加速。但是,要概括速度优化是很困难的)。
在Python中优化内存消耗的一些常见范式转换包括
使用发电机。生成器是懒惰的iterables:它们不会一次将整个列表加载到内存中,而是计算出下一个项目是什么。要使用生成器,上面的代码片段看起来像
或者,使用生成器表达式语法
对同源序列使用
numpy
,特别是对数值计算的序列。这也可以加速执行大量矢量运算的代码。将数据存储到磁盘上,如在数据库中。
在Python中,列表总是通过引用传递的。
列表中对象的大小不会影响列表的性能,因为列表只存储对对象的引用。但是,列表中的项目数确实会影响某些操作的性能,例如删除一个O(n)的元素。
如前所述,listCleanup是最坏情况的O(n**2),因为O(n)del操作在一个可能是O(n)本身的循环中。
如果元素的顺序无关紧要,则可以使用内置的
set
类型而不是列表。set
有O(1)个删除和插入。但是,您必须确保您的对象是不可变的和散列的。否则,你最好重新创建列表。这是O(n),你的算法至少需要O(n),因为你需要检查每个元素。您可以按如下方式将列表筛选为一行:
相关问题 更多 >
编程相关推荐