【问题标题】:Initialize a list of objects in Python在 Python 中初始化对象列表
【发布时间】:2010-12-20 21:24:00
【问题描述】:

我希望初始化一个非空对象的数组/列表——类构造函数生成数据。在 C++ 和 Java 中,我会这样做:

Object lst = new Object[100];

我已经研究过了,但是有没有 Pythonic 的方法来完成这项工作?

这不像我想象的那样工作(我得到 100 次对同一个对象的引用):

lst = [Object()]*100

但这似乎以我想要的方式工作:

lst = [Object() for i in range(100)]

对于 Java 中如此简单的事情,列表理解似乎(在智力上)需要“大量”工作。

【问题讨论】:

    标签: python arrays list initialization


    【解决方案1】:

    没有办法像 C++ 中那样为数组的每个元素隐式调用 Object() 构造函数(回想一下,在 Java 中,新数组的每个元素都初始化为 null 用于引用类型) .

    我会说你的列表理解方法是最 Pythonic 的:

    lst = [Object() for i in range(100)]
    

    如果您不想踩到词法变量i,那么Python 中的约定是使用_ 来表示值无关紧要的虚拟变量:

    lst = [Object() for _ in range(100)]
    

    对于 Java 中类似的构造,您当然可以使用 *

    lst = [None] * 100
    

    【讨论】:

    • @orip 在 Python 3 中,range() 执行 xrange() 过去所做的事情,而 xrange() 不存在。如果您想编写可在 Python 2 和 Python 3 上运行的代码,则不能使用 xrange()
    • @SergeStroobandt 很公平,尽管 2 和 3 之间存在更显着的差异,我建议采用不同的兼容性方法,例如明确目标 3 或保持与 2to3 的兼容性,而不是让 Python2 用户惊讶潜在的巨大内存分配
    • 有趣的是,在我的 Eclipse 环境中,最重要的列表理解方式是给我关于未使用变量 i 的警告,当我使用下划线时,它不再警告我了。我想知道,它真的改变了发生的事情吗? Python 是否知道下划线是一个未使用的虚拟变量,因此执行速度更快?
    • @PeteP:不,使用下划线不会改变 Python 的功能。 (您可以通过使用和不使用下划线对代码进行计时来自行检查。)您只是看到使用下划线会改变 Eclipse 的行为。
    【解决方案2】:

    您应该注意 Python 对 Java 代码的等效项 (创建 100 个对 Object 的 null 引用的数组):

    Object arr = new Object[100];
    

    或 C++ 代码:

    Object **arr = new Object*[100];
    

    是:

    arr = [None]*100
    

    不是:

    arr = [Object() for _ in range(100)]
    

    第二个和 Java 的一样:

    Object arr = new Object[100];
    for (int i = 0; i < arr.lenght; i++) {
        arr[i] = new Object();
    }
    

    事实上,Python 初始化复杂数据结构的能力远胜于 Java。


    注意: C++代码:

    Object *arr = new Object[100];
    

    必须做与 Python 的列表理解一样多的工作:

    • 为 100 个对象分配连续内存

    • 为每个对象调用 Object::Object()

    结果将是完全不同的数据结构。

    【讨论】:

      【解决方案3】:

      我认为列表推导是最简单的方法,但是,如果你不喜欢它,它显然不是获得你想要的东西的唯一方法——在没有参数的情况下调用给定的可调用对象 100 次以形成 100 个项目的一个新列表。比如itertools显然可以做到:

      >>> import itertools as it
      >>> lst = list(it.starmap(Object, it.repeat((), 100)))
      

      或者,如果你真的是一个传统主义者,mapapply

      >>> lst = map(apply, 100*[Object], 100*[()])
      

      请注意,如果不需要在没有参数的情况下调用 Object 需要使用一个参数来调用,那么这基本上是相同的(在概念上和实际上都是很小的;-)所需的工作量 -- 或,比如说,如果Object 实际上是一个函数而不是一个类型。

      令您惊讶的是,执行此任务可能需要“与列表理解一样多”,您似乎认为每种语言都应该特殊情况下需要执行“对类型的调用,不带参数”而不是其他类型调用 over callables,但我看不出这个非常具体的案例有什么如此重要和特别之处,以保证与其他所有案例不同的处理方式;因此,我个人很高兴 Python 并没有将这一个案例单独列出来进行特殊和怪异的处理,而是像任何其他类似的用例一样定期和轻松地处理!-)

      【讨论】:

      • 我觉得你把事情复杂化了。像这样简单的东西不需要导入其他模块
      • 关于特殊情况的好点——我想我没有从那个角度考虑过。那条地图线真的很整洁——我还没有玩过地图,所以我得玩一下。
      • 啊,但是@Inspector,你看,map/apply 解决方案不需要任何导入,但这并不比 itertools 简单:它只是碰巧使用旧的东西它碰巧在很多很多年前被放置在内置函数中,而 itertools 是一个较新的想法,并且被正确放置在标准库的自己的模块中。 apply 在 Python 3 中消失了,map 发生了变化。所以,你看:你对复杂事物的看法(基于这样一个完全不恰当的标准,比如是否使用 import!)实际上是完全、根本上错误和错误的。
      【解决方案4】:
      lst = [Object() for i in range(100)]
      

      由于数组是它自己在 python 中的第一类对象,我认为这是获得所需内容的唯一方法。 * 做了一些疯狂的事。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-02-10
        • 2020-01-08
        相关资源
        最近更新 更多