【问题标题】:How to get dictionary of sub-object using __dict__ on main object?如何在主对象上使用 __dict__ 获取子对象的字典?
【发布时间】:2021-06-17 20:35:00
【问题描述】:

我有一个类Car,它有一个名为parts 的属性。这个属性是一个列表,会在我的程序的过程中填写。 parts 将包含一个列表其他类型的对象,如EngineBatteryWheels 等,它们有自己的属性但不继承自Car。 在我将构建我的Car 对象实例并用所有必要的对象填充它的parts 之后,我想将其转换为字典(易于搜索和比较)并进一步转换为 JSON。我发现__dict__() 是如何用于自定义对象的,这使得它非常快速和有弹性,而无需在Car 类中定义它。但__dict__ 不会递归地为属性部分内的对象创建字典。

我应该如何解决这个问题?我应该在 Car 类中定义我自己的 __dict__() 方法还是有其他方法可以让我的类保持弹性?

解决方案:

感谢@enzo,我向前迈进了一步。他没有给出正确的答案,因为他没有假设Car 类的parts 属性是一个零件列表。有时,Car 可以具有其他属性,即列表帽子没有__dict__ 属性。所以需要更多的检查。

在我的代码下方。 cars 是所有 Car 对象的列表,cars_to_dict 将保留我当前的 cars 列表的“快照”:

cars = list()
cars_to_dict = dict()
for car in cars:
  for k, v in car.__dict__.items():
    if type(v) == type([list()]): 
      cars_to_dict = cars_to_dict | { k : list() }
      for a in v:
        if type(a) == type(Whell()):
          cars_to_dict[k].append(a.__dict__)
        else:
          cars_to_dict[k].append(a)
    else:
      cars_to_dict = cars_to_dict | { k : list() }

【问题讨论】:

  • 您不需要__dict__ 来比较对象。请考虑使用数据类。
  • __dict__ 不将对象转换为字典
  • “我想把它转换成字典(便于搜索和比较)”老实说,这听起来是个坏主意,这完全不利于首先创建类
  • @juanpa.arrivillaga:我知道我可以在两个对象上使用== 运算符,但我想比较一些确保两者相同的属性。相反,我应该覆盖== 运算符吗?

标签: python


【解决方案1】:

你可以这样做:

# Equivalent to your Engine class
class Foo:
    def __init__(self, value):
        self.v1 = value
        
# Equivalent to your Battery class
class Bar:
    def __init__(self, value):
        self.v2 = value
        
# Equivalent to your Wheels class
class Baz:
    def __init__(self, value):
        self.v3 = value
    
# Equivalent to your Car class
class FBB:
    def __init__(self):
        self.v = 0
        self.foo = Foo(1)
        self.bar = Bar(2)
        self.baz = Baz(3)
        
fbb = FBB()
print({k: vars(v) if hasattr(v, '__dict__') else v for k, v in vars(fbb).items()})
# {'v': 0, 'foo': {'v1': 1}, 'bar': {'v2': 2}, 'baz': {'v3': 3}}

请注意,例如,如果 Bar 包含对 Baz 的引用,这将不起作用。为此,您可以考虑创建一个递归函数:

class Foo:
    def __init__(self, value):
        self.v1 = value
        
class Bar:
    def __init__(self, value):
        self.v2 = value
        # Contains a reference to Baz!
        self.baz = Baz(3)
        
class Baz:
    def __init__(self, value):
        self.v3 = value
    
class FBB:
    def __init__(self):
        self.v = 0
        self.foo = Foo(1)
        self.bar = Bar(2)
        
def full_vars(obj):
    return {k: full_vars(v) if hasattr(v, '__dict__') else v for k, v in vars(obj).items()}
        
fbb = FBB()
print(full_vars(fbb))
# {'v': 0, 'foo': {'v1': 1}, 'bar': {'v2': 2, 'baz': {'v3': 3}}}

【讨论】:

    【解决方案2】:

    下面怎么样。我假设单个零件类型只能在汽车中出现一次(例如,您可以将其概括为多个轮子)。

    class Engine:
        def __init__(self, vol:int):
            self.vol = vol
            
    class Wheel:
        def __init__(self, radius:int):
            self.radius = radius
        def __repr__(self):
            # consider maybe using json.dump instead of str (__repr__ has to return str)
            return str(self.__dict__)
    
    class Car:
        def __init__(self, name:str, **kwargs):
            self.name = name
            self.parts = kwargs or dict()
            
        def add_part(self, part):
            self.parts[type(part).__name__] = part
        
        def remove_part(self, part):
            self.parts.pop(part.__name__, None)
            
    
    x = Car("BMW")
    x.add_part(Engine(50))
    print(x.parts)
    x.add_part(Wheel(35))
    print(x.parts)
    x.remove_part(Engine)
    print(x.parts)
    

    输出:

    {'Engine': <__main__.Engine object at 0x7436868c70>}
    {'Engine': <__main__.Engine object at 0x7436868c70>, 'Wheel': {'radius': 35}}
    {'Wheel': {'radius': 35}}
    

    然后

    >>> print(x.__dict__)
    
    {'name': 'BMW', 'parts': {'Wheel': {'radius': 35}}}
    

    有关__repr__的更多信息:https://stackoverflow.com/a/1984177/11610186

    有关__dict__的更多信息:https://stackoverflow.com/a/19907498/11610186

    【讨论】:

    • 谢谢,这就是我现在正在做的。问题是:如何从另一个对象 (Car) 中调用主对象 (x.__dict__) 中的方法的对象 (Whell) 创建字典。您的最后一个代码清单显示了字典中的 Wheel 对象,描述了 x 对象的当前状态,但我想使用 x.__dict__ 方法来剥离所有属性中的所有对象(Whells 等等......) x.
    • type(part).__name__ 的意义何在?为什么不只是type(part)
    • @juanpa.arrivillaga - 试试看,主要是关于格式化(输入名称而不是&lt;class ...
    • @plepleple - 现在试试 __repr__ 是缺失的谜题。
    • @GrzegorzSkibinski 谁在乎它的打印方式? type(part) 不会那么脆弱
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-04
    • 2023-02-05
    • 1970-01-01
    • 2022-12-15
    • 1970-01-01
    相关资源
    最近更新 更多