Using a class as a data container

前端 未结 12 1096
孤街浪徒
孤街浪徒 2020-12-02 10:01

Sometimes it makes sense to cluster related data together. I tend to do so with a dict, e.g.,

self.group = dict(a=1, b=2, c=3)
print self.group[\'a\']


        
相关标签:
12条回答
  • 2020-12-02 10:33

    In a language which supports it, I would use a struct. A dictionary would be closest to a structure in Python, at least as far as I see it.

    Not to mention, you could add a method to a dictionary anyway if you really wanted to ;)

    0 讨论(0)
  • 2020-12-02 10:34

    A dict is obviously appropriate for that situation. It was designed specifically for that use case. Unless you are actually going to use the class as a class, there's no use in reinventing the wheel and incurring the additional overhead / wasting the space of a class that acts as a bad dictionary (no dictionary features).

    0 讨论(0)
  • 2020-12-02 10:35

    By the way, I think Python 3.7 implemented @dataclass is the simplest and most efficient way to implement classes as data containers.

    @dataclass
    class Data:
        a: list
        b: str    #default variables go after non default variables
        c: bool = False
    
    def func():
        return A(a="hello")
    
    print(func())
    

    The output would be :hello

    It is too similar to Scala like case class and the easiest way to use a class as a container.

    0 讨论(0)
  • 2020-12-02 10:36

    Your way is better. Don't try to anticipate the future too much as you are not likely to succeed.

    However, it may make sense sometimes to use something like a C struct, for example if you want to identify different types rather than use dicts for everything.

    0 讨论(0)
  • 2020-12-02 10:37

    Background

    A summary of alternative attribute-based, data containers was presented by R. Hettinger at the SF Python's 2017 Holiday meetup. See his tweet and his slide deck. He also gave a talk at PyCon 2018 on dataclasses.

    Other data container types are mentioned in this article and predominantly in Python 3 documentation (see links below).

    Here is a discussion on the python-ideas mailing list on adding recordclass to the standard library.

    Options

    Alternatives in the Standard Library

    • collections.namedtuple: tuple with attributes (see seminal recipe)
    • typing.NamedTuple: sub-classable tuple (see this post comparing it with namedtuple)
    • types.SimpleNamespace: simple class w/optional class declaration
    • types.MappingProxy: read-only dict
    • enum.Enum: constrained collection of related constants (does behave like a class)
    • dataclasses.dataclass: mutable namedtuple with default/boilerplate-less classes

    External options

    • records: mutable namedtuple (see also recordclass)
    • bunch: add attribute access to dicts (inspiration for SimpleNamedspace; see also munch (py3))
    • box: wrap dicts with dot-style lookup functionality
    • attrdict: access elements from a mapping as keys or attributes
    • fields: remove boilerplate from container classes.
    • namedlist: mutable, tuple-like containers with defaults by E. Smith
    • misc.: posts on making your own custom struct, object, bunch, dict proxy, etc.

    Which one?

    Deciding which option to use depends on the situation (see Examples below). Usually an old fashioned mutable dictionary or immutable namedtuple is good enough. Data classes are the newest addition (Python 3.7a) offering both mutability and optional immutability, with promise of reduced boilerplate as inspired by the attrs project.


    Examples

    import typing as typ
    import collections as ct
    import dataclasses as dc
    
    
    # Problem: You want a simple container to hold personal data.
    # Solution: Try a NamedTuple.
    >>> class Person(typ.NamedTuple):
    ...     name: str
    ...     age: int
    >>> a = Person("bob", 30)
    >>> a
    Person(name='bob', age=30)
    

    # Problem: You need to change age each year, but namedtuples are immutable. 
    # Solution: Use assignable attributes of a traditional class.
    >>> class Person:
    ...     def __init__(self, name, age):
    ...         self.name = name
    ...         self.age = age
    >>> b = Person("bob", 30)
    >>> b.age = 31
    >>> b
    <__main__.Person at 0x4e27128>
    

    # Problem: You lost the pretty repr and want to add comparison features.
    # Solution: Use included repr and eq features from the new dataclasses.
    >>> @dc.dataclass(eq=True)
    ... class Person:
    ...     name: str
    ...     age: int
    >>> c = Person("bob", 30)
    >>> c.age = 31
    >>> c
    Person(name='bob', age=31)
    >>> d = Person("dan", 31)
    >>> c != d
    True
    
    0 讨论(0)
  • 2020-12-02 10:38

    I prefer to follow YAGNI and use a dict.

    0 讨论(0)
提交回复
热议问题