Python 如何编写有效的uuu dict_uuuuu重载函数?

Python 如何编写有效的uuu dict_uuuuu重载函数?,python,pandas,performance,class,Python,Pandas,Performance,Class,我想实现一个to_dict函数,该函数的行为类似于内置的to_dict属性,但允许我使用自定义逻辑。(用于构造数据帧。请参见下面的示例。) 但是,我发现我的to_dict函数比to_dict慢约25% 即使他们做了完全相同的事情。如何改进代码 class Foo: def __init__(self, a,b,c,d): self.a = a self.b = b self.c = c self.d = d def

我想实现一个
to_dict
函数,该函数的行为类似于内置的
to_dict
属性,但允许我使用自定义逻辑。(用于构造数据帧。请参见下面的示例。)

但是,我发现我的
to_dict
函数比
to_dict
慢约25% 即使他们做了完全相同的事情。如何改进代码

class Foo:
    def __init__(self, a,b,c,d):
        self.a = a
        self.b = b
        self.c = c
        self.d = d

    def to_dict(self):
        return {
            'a':self.a,
            'b':self.b,
            'c':self.c,
            'd':self.d,
        }

list_test = [Foo(i,i,i,i)for i in range(100000)]

%%timeit
pd.DataFrame(t.to_dict() for t in list_test)
# Output: 199 ms ± 4.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%%timeit
pd.DataFrame(t.__dict__ for t in list_test)
# Output: 156 ms ± 948 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

这是一个离题的问题,但与我的最终目标有关:从自定义对象列表构造pandas数据帧的最有效方法是什么?我目前的方法是从
不将对象“转换”为
dict
(与
\u int\u
\u str\u
等不同),它是存储对象(可写)属性的地方

我认为你的实施相当有效。考虑这个简化的例子:

import dis

class Foo:
    def __init__(self, a):
        self.a = a
    def to_dict(self):
        return {'a': self.a}

foo = Foo(1)

dis.dis(foo.to_dict)
dis.dis('foo.__dict__')
我们可以看到Python每次都会查找属性并创建一个新的
dict
(另外您需要调用
。to_dict
,此处未显示):

虽然访问现有属性要简单得多:

  1           0 LOAD_NAME                0 (foo)
              2 LOAD_ATTR                1 (__dict__)
              4 RETURN_VALUE
但是,您可以将自定义表示存储在实例上,实现与
\uuu dict\uuuu
相同的字节码,但是您需要在对
Foo
的所有更改中正确更新它(这将消耗一些速度和内存)。如果更新在您的用例中不常见,那么这可能是一个可接受的权衡

在您的示例中,一个简单的选项是覆盖
\uuu getattribute\uuuu
,但我猜
Foo
还有其他属性,因此使用setter可能会更方便:

class Foo:
    def __init__(self, a):
        self.dict = {}
        self.a = a

    @property
    def a(self):
        return self._a

    @a.setter
    def a(self, value):
        self._a = value
        self.dict['a'] = value

foo = Foo(1)
print(foo.dict)  # {'a': 1}
foo.a = 10
print(foo.dict)  # {'a': 10}

他们做的事情并不完全相同
to_dict
每次都会创建一个新对象,而
t.\uuu dict\uuu_
已经存在。在创建
Foo
的实例时生成一个
dict
对象,并在更新值时对其进行更新。然后在
上执行dict
,返回对象,而不是在每次调用时生成它。应该更快。注意,
\uuu dict\uu
不是一个函数,它只是一个包含该对象名称空间的属性。
class Foo:
    def __init__(self, a):
        self.dict = {}
        self.a = a

    @property
    def a(self):
        return self._a

    @a.setter
    def a(self, value):
        self._a = value
        self.dict['a'] = value

foo = Foo(1)
print(foo.dict)  # {'a': 1}
foo.a = 10
print(foo.dict)  # {'a': 10}