【问题标题】:Is there a data type in Python similar to structs in C++?Python 中是否有类似于 C++ 中的结构的数据类型?
【发布时间】:2022-01-19 14:37:36
【问题描述】:

Python 中是否有类似于 C++ 中的结构的数据类型?我喜欢结构功能myStruct.someName。我知道类有这个,但我不想每次我需要一个“容器”来存储一些数据时都写一个类。

【问题讨论】:

  • 因为在 C++ 中 structs 和 classes 是同一个东西(它们只是在默认成员和继承访问说明符上有所不同)你可以写一个 class...跨度>
  • 一般我们使用dict,语法为mydict["someName"]。但是如果你定义了自己的类一次,你就可以添加任何你想要的属性到实例中。
  • @Thomas K:你的意思是我可以创建一个类foo 的实例bar 并动态添加属性?就像第一个 foo 它是空的,然后我添加一个属性,然后添加另一个属性等等?
  • 是的。 class Struct(object): passs = Struct()s.a = 5print(s.a) 打印 5。
  • @All:谢谢大家的建议!

标签: c++ python types struct


【解决方案1】:

为什么不呢?上课就可以了。

如果您想节省一些内存,您可能还想使用__slots__,这样对象就没有__dict__。有关详细信息,请参阅http://docs.python.org/reference/datamodel.html#slots,有关一些有用信息,请参阅Usage of __slots__?

例如,一个只包含两个值(ab)的类可能如下所示:

class AB(object):
    __slots__ = ('a', 'b')

如果您确实想要一个字典,但使用obj.item 访问而不是obj['item'],您可以将字典子类化并实现__getattr____setattr__,使其行为类似于__getitem____setitem__

【讨论】:

  • 谢谢。我会坚持上课! :) 你对“修改” dict 的建议真的很酷!
  • 在一个晦涩的话题中,这是一个被严重低估的答案。在我看来,带有 __getattr____setattr__ 函数的 dict 是在 python 中实现类似结构的行为的一种非常优雅的方式。
【解决方案2】:

除了 dict 类型之外,还有一个 namedtuple 类型,其行为有点像结构。

MyStruct = namedtuple('MyStruct', ['someName', 'anotherName'])
aStruct = MyStruct('aValue', 'anotherValue')

print aStruct.someName, aStruct.anotherName

【讨论】:

  • 这让我想起了 Visual Basic 6.0 中的“用户定义类型”。它们是 VB 对 C++ 结构的模拟。甚至它的声明方式也是相似的。 vb6.us/tutorials/user-defined-types-udt-vb
  • 注意namedtuple是只读的,也就是说你不能改变像aStruct.someName = "foo"这样的值(当然这和普通的元组是一致的)。
【解决方案3】:

dataclass 现在已内置于 Python 3.7 中!

from dataclasses import dataclass

@dataclass
class EZClass:
    name: str='default'
    qty: int

测试:

classy = EZClass('cars', 3)
print(classy)

输出:

EZClass(name='cars', qty=3)

除了自动初始化和它生成的__repr__ 方法外,它还自动创建一个__eq__ 方法,以使比较类的两个实例变得简单直观。

PEP 557

使用 dataclasses package 向后移植到 Python 3.6。

【讨论】:

    【解决方案4】:

    请注意,在 C++ 中,类和结构的唯一区别是类的元素默认是私有的,继承也是如此。以下是等价的:

    class D : public B {
        public:
        ...
    }; 
    
    struct D {
        ...
    };
    

    在 Python 中,如果您想使用点运算符来访问元素,那么使用类是最有意义的。事实上,它更容易,因为您只需初始化您当前想要的成员,并且可以在以后添加/删除成员。因此,以下将起作用:

    class D(object):
        pass
    

    然后,您可以添加任意数量的成员,只需分配给他们即可。

    【讨论】:

    • 感谢您的详细解释。我的问题背后的想法是我的代码的可读性。这会有很大帮助!
    • 应该是class D(object): pass
    • 据我所知,没有方法的类(转储类)被认为是一种反模式。
    【解决方案5】:

    您总是可以选择动态方法:

    class foo(object):
        def __init__(self,**kwargs):
            self.__dict__.update(kwargs)
    

    这将创建一个类,其方法与您作为 dict 传入的方法相同:

    bar = foo(bill="yo",heather="hi",sam="piss off")
    

    bar 上为您提供以下完全有效的调用:

    bar.bill
    >> "yo"
    bar.heater
    >> "hi"
    

    你懂的……

    【讨论】:

      【解决方案6】:

      我相信您正在寻找dict

      d = dict({
              'name': 'myname',
              'val': 'myval'
              })
      
      print d
      print d['name']
      

      【讨论】:

        【解决方案7】:

        尝试使用dict

        这是一个简单的演示。

        >>> something = {}
        >>> something['x'] = 42
        >>> something['y'] = 'cheese'
        >>> something
        {'y': 'cheese', 'x': 42}
        >>> something['x']
        42
        >>> something['y']
        'cheese'
        

        【讨论】:

          【解决方案8】:

          这可能有点过分了,但这里有一种创建“结构”的方法,它使用的语法有点类似于 C++ 结构,它也进行一些类型检查。首先,这是一个使用它的例子:

          >>> MyStruct = Struct({
          ...     'i': int,
          ...     's': str,
          ...     'x': float,
          ... }, 'MyStruct')
          >>> print(MyStruct)
          MyStruct {
              i: int,
              s: str,
              x: float,
          }
          
          >>> instance = MyStruct(i=1, s='s', x=1.0)
          >>> print(instance)
          MyStruct(i: 1, s: 's', x: 1.0)
          

          这是实现。这是__slots__ 想法的变体,其中带槽的类(即“struct”类型)是动态生成的。当然,这可以通过各种方式充实,但这只是一个概念证明。

          class Struct:
          
              class StructInstance:
          
                  __slots__ = ()
          
                  def __str__(self):
                      values = []
                      for name in self.__slots__:
                          value = getattr(self, name)
                          values.append('{name}: {value!r}'.format(name=name, value=value))
                      type_name = self.__class__.__name__
                      values = ', '.join(values)
                      return '{type_name}({values})'.format(type_name=type_name, values=values)
          
              def __init__(self, fields, name=None):
                  for field_name, field_type in fields.items():
                      assert isinstance(field_name, str), 'Expected str for field name'
                      assert isinstance(field_type, type), 'Expected type for field type'
                  self.fields = fields
                  self.name = name or 'Struct'
                  self.type = type(
                      self.name, (self.StructInstance,), {'__slots__': tuple(fields)})
          
              def __call__(self, **values):
                  instance = self.type()
                  for name in instance.__slots__:
                      value = values[name]
                      expected_type = self.fields[name]
                      assert isinstance(value, expected_type), 'Expected %s for %s' % (expected_type, name)
                      setattr(instance, name, value)
                  return instance
          
              def __str__(self):
                  fields = ['    {n}: {t.__name__},'.format(n=n, t=t) for n, t in self.fields.items()]
                  return '{name} {{\n{fields}\n}}'.format(name=self.name, fields='\n'.join(fields))
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2015-08-20
            • 1970-01-01
            • 2019-09-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多