代码之家  ›  专栏  ›  技术社区  ›  ostrokach

为什么是`数据类.asdict(obj)`>比'obj.\uu dict\慢10倍()`

  •  2
  • ostrokach  · 技术社区  · 6 年前

    dataclasses 来自的后端口包 ericvsmith .

    看来打电话 dataclasses.asdict(my_dataclass) 比打电话慢10倍 my_dataclass.__dict__

    In [172]: @dataclass
         ...: class MyDataClass:
         ...:     a: int
         ...:     b: int
         ...:     c: str
         ...: 
    
    In [173]: %%time
         ...: _ = [MyDataClass(1, 2, "A" * 1000).__dict__ for _ in range(1_000_000)]
         ...: 
    CPU times: user 631 ms, sys: 249 ms, total: 880 ms
    Wall time: 880 ms
    
    In [175]: %%time
         ...: _ = [dataclasses.asdict(MyDataClass(1, 2, "A" * 1000)) for _ in range(1_000_000)]
         ...: 
    CPU times: user 11.3 s, sys: 328 ms, total: 11.6 s
    Wall time: 11.7 s
    

    这是预期的行为吗?在什么情况下我应该使用 dataclasses.asdict(obj) 而不是 obj.__dict__


    编辑 :使用 __dict__.copy() 没有太大区别:

    In [176]: %%time
         ...: _ = [MyDataClass(1, 2, "A" * 1000).__dict__.copy() for _ in range(1_000_000)]
         ...: 
    CPU times: user 922 ms, sys: 48 ms, total: 970 ms
    Wall time: 970 ms
    
    1 回复  |  直到 6 年前
        1
  •  26
  •   user2357112    6 年前

    在大多数情况下 __dict__ dataclasses ,你应该继续使用 ,也许有一个 copy 打电话。 asdict 你可能并不真正想要的额外工作。这就是它的作用。


    首先,从 docs

    每个数据类都转换为其字段的dict,即name:value对。 数据类、dict、列表和元组被递归到。 例如:

    @dataclass
    class Point:
         x: int
         y: int
    
    @dataclass
    class C:
         mylist: List[Point]
    
    p = Point(10, 20)
    assert asdict(p) == {'x': 10, 'y': 20}
    
    c = C([Point(0, 0), Point(10, 4)])
    assert asdict(c) == {'mylist': [{'x': 0, 'y': 0}, {'x': 10, 'y': 4}]}
    

    因此,如果您想要递归的数据类措辞,请使用 阿斯迪克特 ,然后将包含的对象的实现更改为 dataclass 将改变 阿斯迪克特 在外部物体上。


    除此之外, 阿斯迪克特 __口述__ 直接访问对象的属性dict。的返回值 阿斯迪克特 不会受到重新分配原始对象字段的影响。也, 阿斯迪克特 使用 fields 阿斯迪克特 不包括他们。

    最后,医生一点也没提,但是 阿斯迪克特 call deepcopy

    else:
        return copy.deepcopy(obj)
    

    (数据类对象、dict、列表和元组通过递归逻辑,它也构建了一个副本,只是应用了递归措辞。)

    深度复制 memo 处理意味着 阿斯迪克特 可能会在非平凡对象图中创建共享对象的多个副本。请注意:

    >>> from dataclasses import dataclass, asdict
    >>> @dataclass
    ... class Foo:
    ...     x: object
    ...     y: object
    ... 
    >>> a = object()
    >>> b = Foo(a, a)
    >>> c = asdict(b)
    >>> b.x is b.y
    True
    >>> c['x'] is c['y']
    False
    >>> c['x'] is b.x
    False