2

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

给定一个简单的类实现__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)更快地做到这一点。

笔记:

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

2 回答 2

2

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

不利的一面是,除非您的类本身继承自 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”var 作为可调用来在 Python 中构建实例 - 与某些需要文字类名的语言不同。无需cls.__new__“手动”调用和填充属性。这将移动

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

于 2015-01-22T11:25:21.857 回答
1

另一种尝试是将值作为列表分配给对象,并在__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
于 2015-01-22T11:36:50.520 回答