Namedtuple like class

后端 未结 5 1919
有刺的猬
有刺的猬 2021-02-06 01:27

I find myself writing this class often in my python code when I need a quick single use class.

class Struct(object):
   def __init__( self, **kwargs ):
      for          


        
相关标签:
5条回答
  • 2021-02-06 02:05

    From Python 3.3 and afterwards, you can use types.SimpleNamespace:

    >>> import types
    >>> foo = types.SimpleNamespace(bar='one', baz=1)
    >>> print(foo.bar)
    one
    >>> foo.baz += 1
    >>> foo.novo = 42
    

    The builtin type is roughly equivalent to the following code:

    class SimpleNamespace:
    
        def __init__(self, **kwargs):
            self.__dict__.update(kwargs)
    
        def __repr__(self):
            keys = sorted(self.__dict__)
            items = ("{}={!r}".format(k, self.__dict__[k]) for k in keys)
            return "{}({})".format(type(self).__name__, ", ".join(items))
    
        def __eq__(self, other):
            return self.__dict__ == other.__dict__
    

    update

    Starting with Python 3.7, you can use the dataclass module:

    from dataclasses import dataclass, field
    
    @dataclass
    class Struct:
        bar: str = field(default='one')
        baz: int = field(default=1)
    

    You can use this as follows:

    foo = Struct( bar='one', baz=1 )
    print(foo.bar)
    foo.baz += 1
    foo.novo = 42
    

    By default, it incorporates equality testing and a nice looking repr:

    >>> foo == Struct(bar='one', baz=2)
    True
    >>> foo
    Struct(bar='one', baz=2)
    
    0 讨论(0)
  • 2021-02-06 02:08

    There is a python recipe for this (It just updates the instance's dict instead of calling setattr) Recipe 52308

    class Bunch(object):
        def __init__(self, **kwds):
            self.__dict__.update(kwds)
    
    0 讨论(0)
  • 2021-02-06 02:08

    What you have is a perfectly reasonable prototype, but you're right that it doesn't scale.

    If you like using them, but want to have a path to better code later, here's what I'd suggest:

    • every time you do that, subclass Structure:

      class Control(Structure): pass

    • later, when you want a "real" class, replace the superclass with something like strongbox.Strongbox (example usage) that provides that same constructor and attribute interface, but constrains which slots you can fill in.

    A discipline like this only costs you one extra line up front, and won't break your code if you want more power later.

    0 讨论(0)
  • 2021-02-06 02:26
    class t(dict):
    
       def __init__(self, **kwargs):
          for key, value in kwargs.items():
             dict.__setitem__(self, key, value)
       def __getattr__(self, key):
          return dict.__getitem__(self, key)
       def __setattr__(self, key, value):
          raise StandardError("Cannot set attributes of tuple")      
       def __setitem__(self, key, value):
          raise StandardError("Cannot set attributes of tuple")      
       def __delitem__(self, key):
          raise StandardError("Cannot delete attributes of tuple")
    
    point = t(x=10, y=500, z=-50)
    print point.x        # 10
    print point.y        # 500
    print point['z']     # -50
    print point          # {'z': -50, 'y': 500, 'x': 10}
    point.x = 100        # StandardError: cannot set attributes of tuple
    point.y += 5         # StandardError: cannot set attributes of tuple
    point.z = -1         # StandardError: cannot set attributes of tuple
    
    def hypo(x, y, z):
       return (x**2 + y**2 + z**2)**0.5
    
    print hypo(point)    # TypeError: unsupported operand type(s)
    print hypo(**point)  # 502.593274925   
    
    for k in point.items():
       print k           # ('y', 500)
                         # ('x', 10)
                         # ('z', -50)
    
    for k in point.keys():
       print k           # x
                         # y
                         # z
    
    for k in point.values():
       print k           # 500
                         # 10
                         # -50
    
    print len(point)     # 3
    
    print dict(point)    # {'y': 500, 'x': 10, 'z': -50}
    

    This is my solution to this problem. Beautiful syntax, immutable (at least without resorting to some nasty object.setattr() gymnastics), lightweight and pretty-printable. Although there is nothing you can do with this that you cannot do with a dict,

    point = t(x=10, y=20, z=30)
    d = point.x ** 2 + point.y ** 2 + point.z ** 2
    

    has a really nice symmetry with

    point = (10, 20, 30)
    d = point[0] ** 2 + point[1] ** 2 + point[2] ** 2
    

    and overall is just so much cleaner than

    point = {'x': 10, 'y': 20, 'z': 30}
    d = point['x'] ** 2 + point['y'] ** 2 + point['z'] ** 2
    
    0 讨论(0)
  • 2021-02-06 02:27

    You may want to look at Records by George Sakkis. It has worked well for me as a "mutable named tuple."

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