Python:创建一个函数来通过引用而不是值来修改列表

Jon*_*han 14 python list

我正在做一些性能关键的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)
Run Code Online (Sandbox Code Playgroud)

我不熟悉Python的低级工作方式.myList是通过值还是通过引用传递的?

我怎样才能让它更快?

有可能以某种方式扩展列表类并在其中实现listCleanup()吗?

myList = range(10000)
myList.listCleanup()
Run Code Online (Sandbox Code Playgroud)

谢谢-

乔纳森

Mik*_*ham 29

Python以相同的方式传递所有内容,但是"按值"或"按引用"调用它不会清除所有内容,因为Python的语义与这些术语通常适用的语言不同.如果我要描述它,我会说所有传递都是按值,并且该值是对象引用.(这就是我不想说的原因!)

如果要从列表中过滤掉一些内容,可以构建一个新列表

foo = range(100000)
new_foo = []
for item in foo:
    if item % 3 != 0: # Things divisble by 3 don't get through
        new_foo.append(item)
Run Code Online (Sandbox Code Playgroud)

或者,使用列表推导语法

 new_foo = [item for item in foo if item % 3 != 0]
Run Code Online (Sandbox Code Playgroud)

Python将不会复制的对象列表,而是两者foonew_foo会引用同一个对象.(Python从不隐式复制任何对象.)


您已建议您对此操作有性能问题.使用del旧列表中的重复 语句将导致代码不再具有惯用性并且更难以处理,但它将引入二次性能,因为每次必须重新整理整个列表.

解决性能问题:

  • 启动并运行.除非你有代码工作,否则你无法弄清楚你的表现是什么样的.这也将告诉您是否必须优化速度或空间; 你在代码中提到了对这两者的关注,但通常优化涉及以另一个为代价获得一个.

  • 轮廓.您可以使用stdlib工具及时获得性能.有各种第三方内存分析器可能有点用,但不太适合使用.

  • 测量. 当您进行更改以查看更改是否有所改进时,时间或重新编码内存,如果是,那么改进是什么.

  • 为了使您的代码对内存更敏感,您通常需要在存储数据的方式上进行范式转换,而不是像不构建第二个列表来进行过滤的微观优化.(对于时间也是如此,真的:改为更好的算法几乎总能提供最佳的加速.然而,更难以概括速度优化).

    在Python中优化内存消耗的一些常见范例转换包括

    1. 使用生成器.生成器是懒惰的迭代:它们不会立即将整个列表加载到内存中,它们会在运行中找出它们的下一个项目.要使用生成器,上面的代码段看起来像

      foo = xrange(100000) # Like generators, xrange is lazy
      def filter_divisible_by_three(iterable):
          for item in foo:
              if item % 3 != 0:
                  yield item
      
      new_foo = filter_divisible_by_three(foo)
      
      Run Code Online (Sandbox Code Playgroud)

      或者,使用生成器表达式语法,

      new_foo = (item for item in foo if item % 3 != 0)
      
      Run Code Online (Sandbox Code Playgroud)
    2. 使用numpy为均质的序列,特别是那些是数值-mathy.这也可以加速执行大量矢量操作的代码.

    3. 将数据存储到磁盘,例如数据库中.


Dan*_*ach 6

在Python中,列表总是通过引用传递.

列表中对象的大小不会影响列表性能,因为列表仅存储对对象的引用.但是,列表中的项目数确实会影响某些操作的性能 - 例如删除元素,即O(n).

正如所写的那样,listCleanup是最坏情况的O(n**2),因为你在一个可能是O(n)本身的循环中有O(n)del操作.

如果元素的顺序无关紧要,您可以使用内置set类型而不是列表.所述set具有O(1)缺失和插入.但是,您必须确保对象是不可变和可清除的.

否则,你最好重新创建列表.那是O(n),你的算法需要至少为O(n),因为你需要检查每个元素.您可以在一行中过滤列表,如下所示:

listOfElements[:] = [el for el in listOfElements if el.MeetsCriteria()]
Run Code Online (Sandbox Code Playgroud)