Python列表与STL类似的接口

时间:2010-01-01 12:39:47

标签: c++ python stl

我必须将C ++ STL应用程序移植到Python。我是一个Python新手,但已编程超过十年。我对STL有很多经验,发现它让我迷上了使用C ++。过去几天我一直在Google上搜索以下内容:

  1. Python STL(希望利用我多年的STL经验)
  2. Python链接列表
  3. Python高级列表用法
  4. Python列表优化
  5. Python有序集
  6. 并且已经找到了关于上述主题的帖子,关于Python列表的教程明显没有进展,或者死路一条。我对自己缺乏成功感到非常惊讶,我认为我只是因为过度劳累和输入错误的搜索条件而感到筋疲力尽!

    (我的问题)我可以获得Python STL包装器,或者像STL一样工作的Python列表的接口吗?如果没有,有人能指出我真正的高级教程或论文来管理非常大的非平凡对象的集合吗?

    P.S。我可以轻松地为一两个用途实现变通方法,但如果管理层想要移植更多代码,我想准备好立即用等效的Python代码替换我找到的任何STL代码。是的,我已经测量过并且需要完全具有最佳代码!我只能做冗余的搜索和搜索!

    (ADDENDUM)感谢您的回复,我已经查看了一些参考资料,我很高兴。回应一些评论:

    1 - 它正被移植到python,因为管理层这么说,我会尽快不管它 - 如果它不能解决,为什么要解决它?

    2 - 使用非平凡对象的高级列表使用,我的意思是:许多不同的方式来排序和比较对象,而不是通过一个 cmp 方法。我想广泛地拼接,排序,合并,搜索,插入,擦除和组合列表。我想要列表迭代器列表,我想避免复制。

    3 - 我现在知道内置列表实际上是数组,我应该寻找一个不同的python类。我认为这是我困惑的根源。

    4 - 当然我正在学习以Python的方式做事,但我也有截止日期。我正在移植的STL代码工作正常,我想尽可能少地改变它,因为这会引入错误。

    感谢大家的投入,我真的很感激。

6 个答案:

答案 0 :(得分:13)

如果我是你,我会花时间学习如何正确使用Python中可用的各种数据结构,而不是寻找类似于你从C ++中知道的东西。

这不像你正在寻找一些花哨的东西,只是在处理一些数据结构。在那种情况下,我会推荐你​​Python's documentation on the subject

这样做'Python'的方式可以帮助你,更重要的是未来的维护者,他们会想知道你为什么要尝试用Python编写C ++。

为了满足您的胃口,也没有理由偏好 STL的样式到Python(并且为了记录,我也是一个彻底了解STL的C ++程序员),考虑最简单的例子构建列表并遍历它:

Pythonic方式:

mylist = [1, 2, 3, 4]

for value in mylist:
    # playaround with value

在Python中使用STL方式(我把它做成了,类似于STL):

mylist = [1, 2, 3, 4]
mylistiter = mylist.begin()

while mylistiter != mylist.end():
    value = mylistiter.item()
    mylistiter.next()

答案 1 :(得分:13)

Python的“列表”不是链接的列表 - 它们就像Java ArrayList或C ++的std::vector,即在较低级别的术语中,可调整大小紧凑的指针数组。

关于此类主题的一个很好的“高级教程”是Hettinger的Core Python containers: under the hood演示文稿(URL上的视频是在意大利会议上的演示文稿,但是它是用英语写的;另一个,基本相同的演讲的简短演示是here)。

因此,Python列表的性能特征基本上是C ++的std::vector:Python的.append,如C ++的push_back,是O(1),但插入或删除“在中间“是O(N)。因此,保持列表排序(可以通过Python标准库模块bisect中的函数轻松完成)是昂贵的(如果项目随机到达和/或随机离开,每次插入和删除都是O(N),就像类似地维护std::vector中的顺序一样。出于某些目的,例如优先级队列,您可以使用“堆队列”,也可以通过Python标准库模块中的函数轻松维护{ {3}} - 当然,它不能提供与完全排序的列表(或矢量)相同的用途范围。

因此,对于在C ++中使用std::set的目的(并且依赖于它的排序,即,hashset不会这样做 - Python的set是基于哈希的,你可能最好避免使用Python内置容器,而不是heapq(如果你需要保持纯粹的Python),或this module(它提供AVL树,而不是RB,但是如果C编码的扩展是可以的话,它被编码为C实现的Python扩展,因此可以提供更好的性能。

如果您最终使用自己的模块(无论是纯Python还是C编码),您可以根据需要为其提供类似STL的胶合代码/界面(.begin,{{ 1}},迭代器通过递增而不是按照正常的Python行为,通过调用它们的.end方法来推进...,尽管它永远不会像“与谷物一样”运行语言会(next语句被优化为使用普通的Python迭代器,即使用for方法的迭代器,并且它比围绕非Python的包装有点笨拙next更快 - 标准的,类似STL的迭代器。)

要为任何Python内置容器提供类似STL的胶合代码,您将产生大量的包装开销,因此性能损失可能相当大。如果您,正如您所说,“需要完全具有最佳代码”,那么仅仅出于“语法方便”的目的使用这样的胶合板似乎是一个非常糟糕的选择。

this one,包含功能强大的C ++ Boost库的Python扩展包,可能最适合您的目的。

答案 2 :(得分:2)

对于类似链接列表的操作,人们通常使用collections.deque

您需要快速执行哪些操作?平分?插入

答案 3 :(得分:2)

我会说你的问题不仅仅是STL移植。由于list,dict和set数据结构(通过STL固定在​​C ++上)是核心Python的原生,因此它们的用法被合并到常见的Python代码习语中。如果你想给谷歌另一个镜头,试着寻找“Python for C ++ Programmers”的参考。你的一个点击将是this presentation by Alex Martelli。它有点过时了,从第三版开始,但是对于通过文本文件读取的一些基本Python代码以及使用STL的外观有一个并排的比较。

从那里,我建议您阅读这些Python功能:

  • 迭代
  • 发电机
  • 列表和生成器理解

这些内置函数:

  • 拉链
  • 地图

熟悉这些内容之后,您就可以在STL用法和Python内置数据结构之间构建自己的转换/映射。

正如其他人所说的那样,如果你正在寻找一个“插件式”公式来将STL C ++代码转换为Python,你最终会得到糟糕的Python。这种蛮力方法永远不会导致单行列表理解的力量,优雅和简洁。 (当我向熟悉Java和C ++迭代器的经理们介绍Python时,我有这方面的经验。当我向他展示这段代码时:

numParams = 1000
paramRequests = [ ("EqptEmulator/ProcChamberI/Sensors", 
                   "ChamberIData%d"%(i%250)) for i in range(numParams) ]
record.internalArray = [ParameterRequest(*pr) for pr in paramRequests]

我解释说这些代替了这个代码(或类似代码,这可能是C ++和Java API的混乱,对不起):

std::vector<ParameterRequest> prs = new std::vector<ParameterRequest>();
for (int i = 0; i<1000; ++i) {
    string idstr;
    strstream sstr(idstr);
    sstr << "ChamberIData" << (i%250);
    prs.add(new ParameterRequest("EqptEmulator/ProcChamberI/Sensors", idstr));
}
record.internalArray = new ParameterRequest[prs.size];
prs.toArray(record.internalArray);

使用C ++的一种直觉是不愿意从旧的列表创建新列表,而是更新或过滤列表。我们甚至在Python开发人员的许多论坛上看到这一点,询问如何在迭代时修改列表。在Python中,最好使用列表解析从旧构建新列表。

allItems = [... some list of items, perhaps from a database query ...]
validItems = [it for it in allItems if it.isValid()]

相反:

validItems = []
for it in allItems:
    if it.isValid():
        validItems.add(it)

或更糟:

# get list of indexes of items to be removed
removeIndexes = []
for i in range(len(allItems)):
    if not allItems[i].isValid():
        removeIndexes.add(i)

# don't forget to remove items in descending order, or later indexes
# will be invalidated by earlier removals
sort(removeIndexes,reverse=True)

# copy list
validItems = allItems[:]

# now remove the items from allItems
for idx in removeIndexes:
    del validItems[i]

答案 4 :(得分:1)

Python STL(希望利用我多年的STL经验) - 从ABC的集合开始,了解Python的含义。 http://docs.python.org/library/collections.html

Python链接列表。 Python列表具有您希望从链接列表中获得的所有功能。

Python高级列表用法。这是什么意思?

Python列表优化。这是什么意思?

Python有序集。你有几个选择;你可以发明自己的“有序集”作为丢弃重复的列表。您可以继承heapq并添加丢弃重复项的方法:http://docs.python.org/library/heapq.html

然而,在许多情况下,维护有序集的成本实际上是过高的,因为它必须在算法结束时只排序一次。在其他情况下,“有序集”实际上是一个heapq - 您从不需要类似集合的功能,只需要订购。

<强>非普通即可。 (我猜你的意思是“非平凡的”)。所有Python对象都是等价的。没有“琐碎”与“非平凡”的对象。它们都是一流的物体,并且在没有任何实际工作的情况下都可以具有“非平凡”的复杂性。这不是C ++,其中有原始(非对象)值浮动。一切都是Python中的一个对象。

管理期望。 在大多数情况下,Python中不存在C ++脑痉挛。以明显的方式使用明显的Python类,你将获得更少的代码。代码量的减少是的最大胜利。通常,将C ++转换为Python的管理原因是为了摆脱C ++的复杂性。

Python代码将更加简单,使其更可靠,更易于维护。

虽然Python通常比C ++慢,但选择正确的算法和数据结构也可以对性能进行戏剧性的改进。在一个基准测试中,有人发现Python实际上更快,因为C程序具有如此糟糕的数据结构。

你的C ++可能有一个非常糟糕的算法,你会发现Python的性能相当。

您的C ++程序也可能受I / O限制,或者还有其他限制因素会使Python以相同的速度运行。

答案 5 :(得分:1)

Python的设计是非常有意的“你可以只使用一些数据结构(数组和哈希表)来做任何你想做的事情,如果这不够快就会有C”。

Python的标准库没有像std::set那样的排序列表数据结构。你可以download a red/black tree implementation或自己动手。 (对于小型数据集,只需使用列表并定期对其进行排序,这在Python中是完全正常的。)

滚动您自己的链接列表非常容易。