Namedtuple喜欢上课

def*_*ode 9 python

当我需要一个快速的单用类时,我发现自己经常在我的python代码中编写这个类.

class Struct(object):
   def __init__( self, **kwargs ):
      for k in kwargs:
         setattr(self,k,kwargs[k])
Run Code Online (Sandbox Code Playgroud)

基本的想法是这样我可以做这样的快速事情:

foo = Struct( bar='one', baz=1 )
print foo.bar
foo.baz += 1
foo.novo = 42 # I don't do this as often.
Run Code Online (Sandbox Code Playgroud)

当然这不能很好地扩展,添加方法只是疯了,但即便如此,我仍然有足够的数据丢弃类,我一直在使用它.

这是我认为namedtuple将是.但是这个名字的语法很大而且很笨拙.

标准库中有什么东西我还没有发现它能做到这一点还是更好?

这是坏风格吗?还是有一些隐藏的缺陷?

更新

两个具体的例子来说明为什么我不只是使用dict.这两个例子都可以用dict完成,但显然不是惯用语.

#I know an order preserving dict would be better but they don't exist in 2.6.
closure = Struct(count=0)
def mk_Foo( name, path ):
   closure.count += 1
   return (name, Foo( name, path, closure.count ))

d = dict([
   mk_Foo( 'a', 'abc' ),
   mk_Foo( 'b', 'def' ),
   # 20 or so more
   ] )


@contextmanager
def deleter( path ):
   control = Struct(delete=True,path=path)
   try:      
      yield control
   finally:
      if control.delete:
         shutil.rmtree(path)

with deleter( tempfile.mkdtemp() ) as tmp:
   # do stuff with tmp.path

   # most contexts don't modify the delete member
   # but occasionally it's needed
   if keep_tmp_dir:
      tmp.delete = False
Run Code Online (Sandbox Code Playgroud)

Tig*_*isC 9

这有一个python配方(它只是更新实例的dict而不是调用setattr) Recipe 52308

class Bunch(object):
    def __init__(self, **kwds):
        self.__dict__.update(kwds)
Run Code Online (Sandbox Code Playgroud)


Ray*_*ger 7

从Python 3.3及之后,您可以使用types.SimpleNamespace:

>>> import types
>>> foo = types.SimpleNamespace(bar='one', baz=1)
>>> print(foo.bar)
one
>>> foo.baz += 1
>>> foo.novo = 42
Run Code Online (Sandbox Code Playgroud)

内置类型大致相当于以下代码:

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__
Run Code Online (Sandbox Code Playgroud)

更新

从Python 3.7开始,您可以使用dataclass模块:

from dataclasses import dataclass, field

@dataclass
class Struct:
    bar: str = field(default='one')
    baz: int = field(default=1)
Run Code Online (Sandbox Code Playgroud)

您可以按如下方式使用:

foo = Struct( bar='one', baz=1 )
print(foo.bar)
foo.baz += 1
foo.novo = 42
Run Code Online (Sandbox Code Playgroud)

默认情况下,它包含相等测试和漂亮的repr:

>>> foo == Struct(bar='one', baz=2)
True
>>> foo
Struct(bar='one', baz=2)
Run Code Online (Sandbox Code Playgroud)