Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/291.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 类名为tuple的类_Python - Fatal编程技术网

Python 类名为tuple的类

Python 类名为tuple的类,python,Python,当我需要一个快速的单用途类时,我发现自己经常在python代码中编写这个类 class Struct(object): def __init__( self, **kwargs ): for k in kwargs: setattr(self,k,kwargs[k]) 基本思路是,我可以快速完成以下任务: foo = Struct( bar='one', baz=1 ) print foo.bar foo.baz += 1 foo.novo = 42 # I

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

class Struct(object):
   def __init__( self, **kwargs ):
      for k in kwargs:
         setattr(self,k,kwargs[k])
基本思路是,我可以快速完成以下任务:

foo = Struct( bar='one', baz=1 )
print foo.bar
foo.baz += 1
foo.novo = 42 # I don't do this as often.
当然,这不能很好地扩展,添加方法简直是疯了,但即使如此,我有足够的数据,也只能扔掉我一直在使用的类

这就是我所想的。但是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
  

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


你所拥有的是一个完全合理的原型,但你是对的,它不能扩展

如果您喜欢使用它们,但想在以后获得更好的代码,我建议如下:

  • 每次这样做时,子类结构:

    类控制(结构):通过

  • 稍后,当您想要一个“真实”类时,用类似()的东西替换超类,它提供相同的构造函数和属性接口,但约束您可以填充的插槽

像这样的规程只需要在前面多花费一行代码,如果您以后想要更多的功能,它不会破坏您的代码

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}
这是我解决这个问题的办法。漂亮的语法,不可变(至少不用求助于一些讨厌的对象。setattr()),轻量级,可打印。虽然没有什么是你用口述不能做到的

point = t(x=10, y=20, z=30)
d = point.x ** 2 + point.y ** 2 + point.z ** 2
有一个非常好的对称性

point = (10, 20, 30)
d = point[0] ** 2 + point[1] ** 2 + point[2] ** 2
总的来说,比以前干净多了

point = {'x': 10, 'y': 20, 'z': 30}
d = point['x'] ** 2 + point['y'] ** 2 + point['z'] ** 2

你可能想看看旁边。作为一个“可变命名元组”,它对我来说非常有效。

来自Python 3.3,之后,您可以使用:

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

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__
更新

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

您可以按如下方式使用它:

foo = Struct( bar='one', baz=1 )
print(foo.bar)
foo.baz += 1
foo.novo = 42
默认情况下,它包含相等性测试和一个漂亮的repr:

>>> foo == Struct(bar='one', baz=2)
True
>>> foo
Struct(bar='one', baz=2)

用口述有什么不对?x={'baz':1}x['baz']+=1
namedtuple
是一个
元组
,因此您不能更改其内容。@JochenRitzel,您可以调用
\u replace
。例如:
p=点(x=11,y=22)
<代码>p._更换(x=33)
<代码>点(x=33,y=22)检查这一点到一个类似的问题。值得检查:哇!与简单的束配方相比,使用
exec
似乎有点极端。这种方法的一个限制是,当使用
\uuuuuuu插槽时,它不起作用。
from dataclasses import dataclass, field

@dataclass
class Struct:
    bar: str = field(default='one')
    baz: int = field(default=1)
foo = Struct( bar='one', baz=1 )
print(foo.bar)
foo.baz += 1
foo.novo = 42
>>> foo == Struct(bar='one', baz=2)
True
>>> foo
Struct(bar='one', baz=2)