【问题标题】:Create slots object instance performance创建槽对象实例性能
【发布时间】:2015-03-20 12:32:27
【问题描述】:

我有一段代码使用值列表生成对象的实例。例如:

给定一个实现__slots__的简单类

class A(object):
  __slots__ = ('a', 'b')

和一个值列表

>>> l = [1, 2]

我们通过

创建对象的一个​​新实例
>>> o = A.__new__(A)
>>> o
<__main__.A object at 0x0617AE70>

然后我们使用列表中的元素填充对象的属性

>>> for idx, element in enumerate(l):
...   setattr(o, o.__slots__[idx], element)
>>> o.a
1
>>> o.b
2

我在许多值列表的循环中执行此操作,在分析我的程序后,这是它花费大量时间的地方。我想知道是否有更好的方法可以使用普通 python(没有 pypy 或 cython)更快地做到这一点。

注意事项:

  • 我的程序实际上从我的__slots__ 对象继承的方法调用cls.__new__(cls)。由于我不知道调用该方法的类,因此这是我发现创建该特定类类型的新实例的唯一方法。
  • 我正在从包含值的文件中创建这些对象,但这是程序的要求。

【问题讨论】:

  • 这个程序的目的是什么?很抱歉,但由于我不知道它的作用,所以代码相当......难以理解。谢谢!
  • 可能不会让您获得更多性能 - 但这样做会更漂亮(“Pythonic”):for attr, element in zip(o.__slots__, l): setattr(o, attr, l)
  • 我的猜测是你的问题太具体了。我认为它需要更多的上下文(对于 SO 来说可能太多了?)才能给你一个好的答案。
  • @jsbueno 我确实喜欢你的“Pythonic”方法,因为它更容易阅读,但性能有点差(从快速基准测试来看大约是 5%)。
  • 为什么首先需要一个对象(A 的实例)? Python 可以使用普通的数据结构进行繁重的处理。而“oop”方式往往是不必要的复杂性的来源。

标签: python performance python-internals slots


【解决方案1】:

所以,我可以在那里提出一些想法,但它们或多或少是投机性的。 一种想法是使用命名元组,而不是直接的对象属性。

不利的一面是,除非您的类本身继承自 namedtuples(并且需要进行一些黑客攻击),否则您将在属性路径中有一个额外的组件。

但是他们,还有一些东西:

from collections import namedtuple

class MyClass42(object):
    __slots__ = ["attrs"]
    scheme = namedtuple("attrs", "attr1 attr2 attr3 attr4")

    def __init__(self, attrs):
        self.attrs = self.scheme(*attrs)

# and to create the classes:
o = cls(attrs)

# the downsides are that you have to access attributes like

o.attrs.attr1
# and all such attributes are imutable :-/

请注意,您可以只使用“cls”变量作为可调用来构建 Python 中的一个实例 - 与某些语言不同 在其中您需要文字类名。 无需调用cls.__new__ 并填充属性 “手动”。这将移动

(附带说明,避免使用 1 个字母的变量名可以大大提高可读性, 但如果你愿意这样做,你真的应该避免使用'l' 这个名字,因为它看起来就像'1' - 我在上面使用过'attrs'

【讨论】:

  • 我今天会试一试,然后报告。对于l 名称问题,我实际上使用了更具描述性的名称,但是我在我的问题中为演示使用而对其进行了精简;无论哪种方式都很好。
【解决方案2】:

另一种尝试是将值作为列表分配给对象,并在 __getattribute__ 方法中懒惰地处理对它们的访问。虽然这几乎肯定会为您节省创建对象的时间,但它会将时间转移到第一次使用属性(但是,我不知道您是否真的必须访问所有对象的所有属性 - 您可以微调您的策略)-如果这是一个问题,您将对内存使用产生巨大影响。

class MyClass42(object):
    __slots__ = ["raw_attrs", "attr1", "attr2", ...]


    def __init__(self, attrs):
        self.raw_attrs = attrs

    def __getattr__(self, attr_name):
        attr = self.raw_attrs[self.__slots__.index(attr_name) - 1]
        setattr(self, attr_name, attr)
        return attr

【讨论】:

    猜你喜欢
    • 2013-10-15
    • 2019-04-07
    • 1970-01-01
    • 2021-07-22
    • 1970-01-01
    • 2016-01-31
    • 1970-01-01
    • 2012-11-08
    • 2013-10-20
    相关资源
    最近更新 更多