Преобразовать вложенный Python dict в объект?

Являются ли композиция и наследование одинаковыми?

Они не совпадают.

Композиция : позволяет группе объектов обрабатываться так же, как один экземпляр объекта. Цель композита состоит в том, чтобы «компоновать» объекты в древовидных структурах представлять целые иерархии

Inheritance : класс наследует поля и методы из все его суперклассы, прямые или косвенные. Подкласс может переопределять методы, которые он наследует, или он может скрыть поля или методы, которые он наследует.

Если я хочу реализовать шаблон композиции, как я могу это сделать на Java?

Статья в Википедии достаточно хороша для реализации составного шаблона в java.

Ключевые участники:

Компонент:

  1. Является абстракцией для всех компонентов, включая составные
  2. Объявляет интерфейс для объектов в композиция

Лист:

  1. Представляет листовые объекты в композиции
  2. Реализует все методы Component

Композит:

  1. Представляет составной компонент (компонент с дочерними элементами)
  2. Реализует методы манипулирования детьми
  3. Реализует все методы Component, обычно делегируя их своим детям

Пример кода для понимания Composite patter n:

import java.util.List;
import java.util.ArrayList;

interface Part{
    public double getPrice();
    public String getName();
}
class Engine implements Part{
    String name;
    double price;
    public Engine(String name,double price){
        this.name = name;
        this.price = price;
    }
    public double getPrice(){
        return price;
    }
    public String getName(){
        return name;
    }
}
class Trunk implements Part{
    String name;
    double price;
    public Trunk(String name,double price){
        this.name = name;
        this.price = price;
    }
    public double getPrice(){
        return price;
    }
    public String getName(){
        return name;
    }
}
class Body implements Part{
    String name;
    double price;
    public Body(String name,double price){
        this.name = name;
        this.price = price;
    }
    public double getPrice(){
        return price;
    }
    public String getName(){
        return name;
    }
}
class Car implements Part{
    List parts;
    String name;

    public Car(String name){
        this.name = name;
        parts = new ArrayList();
    }
    public void addPart(Part part){
        parts.add(part);
    }
    public String getName(){
        return name;
    }
    public String getPartNames(){
        StringBuilder sb = new StringBuilder();
        for ( Part part: parts){
            sb.append(part.getName()).append(" ");
        }
        return sb.toString();
    }
    public double getPrice(){
        double price = 0;
        for ( Part part: parts){
            price += part.getPrice();
        }
        return price;
    }   
}

public class CompositeDemo{
    public static void main(String args[]){
        Part engine = new Engine("DiselEngine",15000);
        Part trunk = new Trunk("Trunk",10000);
        Part body = new Body("Body",12000);

        Car car = new Car("Innova");
        car.addPart(engine);
        car.addPart(trunk);
        car.addPart(body);

        double price = car.getPrice();

        System.out.println("Car name:"+car.getName());
        System.out.println("Car parts:"+car.getPartNames());
        System.out.println("Car price:"+car.getPrice());
    }

}

выход:

Car name:Innova
Car parts:DiselEngine Trunk Body
Car price:37000.0

Объяснение:

  1. Часть - это лист
  2. Автомобиль содержит много частей
  3. В автомобиль добавлены запчасти автомобиля
  4. Цена Автомобиль = сумма (Цена каждой партии)

См. ниже вопрос о преимуществах и недостатках композиции и наследования.

Предпочитают композицию по наследованию?

494
задан wim 15 May 2018 в 14:58
поделиться

11 ответов

Обновление: В Python 2.6 и новее подумайте, соответствует ли структура данных namedtuple вашим потребностям:

>>> from collections import namedtuple
>>> MyStruct = namedtuple('MyStruct', 'a b d')
>>> s = MyStruct(a=1, b={'c': 2}, d=['hi'])
>>> s
MyStruct(a=1, b={'c': 2}, d=['hi'])
>>> s.a
1
>>> s.b
{'c': 2}
>>> s.c
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'MyStruct' object has no attribute 'c'
>>> s.d
['hi']

Альтернатива (исходное содержание ответа):

class Struct:
    def __init__(self, **entries):
        self.__dict__.update(entries)

Затем вы можете использовать:

>>> args = {'a': 1, 'b': 2}
>>> s = Struct(**args)
>>> s
<__main__.Struct instance at 0x01D6A738>
>>> s.a
1
>>> s.b
2
636
ответ дан 22 November 2019 в 22:35
поделиться

Вот еще одна реализация:

class DictObj(object):
    def __init__(self, d):
        self.__dict__ = d

def dict_to_obj(d):
    if isinstance(d, (list, tuple)): return map(dict_to_obj, d)
    elif not isinstance(d, dict): return d
    return DictObj(dict((k, dict_to_obj(v)) for (k,v) in d.iteritems()))

[Edit] Пропущен бит, касающийся также обработки словарей внутри списков, а не только других словарных статей. Добавлено исправление.

2
ответ дан 22 November 2019 в 22:35
поделиться

Вот еще один способ реализовать исходное предложение SilentGhost:

def dict2obj(d):
  if isinstance(d, dict):
    n = {}
    for item in d:
      if isinstance(d[item], dict):
        n[item] = dict2obj(d[item])
      elif isinstance(d[item], (list, tuple)):
        n[item] = [dict2obj(elem) for elem in d[item]]
      else:
        n[item] = d[item]
    return type('obj_from_dict', (object,), n)
  else:
    return d
2
ответ дан 22 November 2019 в 22:35
поделиться
>>> def dict2obj(d):
        if isinstance(d, list):
            d = [dict2obj(x) for x in d]
        if not isinstance(d, dict):
            return d
        class C(object):
            pass
        o = C()
        for k in d:
            o.__dict__[k] = dict2obj(d[k])
        return o


>>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
>>> x = dict2obj(d)
>>> x.a
1
>>> x.b.c
2
>>> x.d[1].foo
'bar'
13
ответ дан 22 November 2019 в 22:35
поделиться

x .__ dict __. update (d) должно работать нормально.

8
ответ дан 22 November 2019 в 22:35
поделиться

Это должно помочь вам начать:

class dict2obj(object):
    def __init__(self, d):
        self.__dict__['d'] = d

    def __getattr__(self, key):
        value = self.__dict__['d'][key]
        if type(value) == type({}):
            return dict2obj(value)

        return value

d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}

x = dict2obj(d)
print x.a
print x.b.c
print x.d[1].foo

Это пока не работает для списков. Вам нужно будет обернуть списки в UserList и перегрузить __ getitem __ , чтобы обернуть dicts.

6
ответ дан 22 November 2019 в 22:35
поделиться

Позвольте мне объяснить решение, которое я почти использовал некоторое время назад. Но сначала причина, по которой я этого не сделал, проиллюстрирована тем фактом, что следующий код:

d = {'from': 1}
x = dict2obj(d)

print x.from

дает эту ошибку:

  File "test.py", line 20
    print x.from == 1
                ^
SyntaxError: invalid syntax

Поскольку "from" является ключевым словом Python, существуют определенные ключи словаря, которые вы не можете разрешить.


Теперь мой Решение позволяет получить доступ к элементам словаря, используя их имена напрямую. Но он также позволяет использовать «семантику словаря». Вот код с примером использования:

class dict2obj(dict):
    def __init__(self, dict_):
        super(dict2obj, self).__init__(dict_)
        for key in self:
            item = self[key]
            if isinstance(item, list):
                for idx, it in enumerate(item):
                    if isinstance(it, dict):
                        item[idx] = dict2obj(it)
            elif isinstance(item, dict):
                self[key] = dict2obj(item)

    def __getattr__(self, key):
        return self[key]

d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}

x = dict2obj(d)

assert x.a == x['a'] == 1
assert x.b.c == x['b']['c'] == 2
assert x.d[1].foo == x['d'][1]['foo'] == "bar"
4
ответ дан 22 November 2019 в 22:35
поделиться
x = type('new_dict', (object,), d)

затем добавьте к этому рекурсию, и все готово.

редактировать вот как я бы это реализовал:

>>> d
{'a': 1, 'b': {'c': 2}, 'd': ['hi', {'foo': 'bar'}]}
>>> def obj_dic(d):
    top = type('new', (object,), d)
    seqs = tuple, list, set, frozenset
    for i, j in d.items():
        if isinstance(j, dict):
            setattr(top, i, obj_dic(j))
        elif isinstance(j, seqs):
            setattr(top, i, 
                type(j)(obj_dic(sj) if isinstance(sj, dict) else sj for sj in j))
        else:
            setattr(top, i, j)
    return top

>>> x = obj_dic(d)
>>> x.a
1
>>> x.b.c
2
>>> x.d[1].foo
'bar'
60
ответ дан 22 November 2019 в 22:35
поделиться
class obj(object):
    def __init__(self, d):
        for a, b in d.items():
            if isinstance(b, (list, tuple)):
               setattr(self, a, [obj(x) if isinstance(x, dict) else x for x in b])
            else:
               setattr(self, a, obj(b) if isinstance(b, dict) else b)

>>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
>>> x = obj(d)
>>> x.b.c
2
>>> x.d[1].foo
'bar'
103
ответ дан 22 November 2019 в 22:35
поделиться

Основываясь на моем ответе на " python: Как динамически добавить свойство в класс? ":

class data(object):
    def __init__(self,*args,**argd):
        self.__dict__.update(dict(*args,**argd))

def makedata(d):
    d2 = {}
    for n in d:
        d2[n] = trydata(d[n])
    return data(d2)

def trydata(o):
    if isinstance(o,dict):
        return makedata(o)
    elif isinstance(o,list):
        return [trydata(i) for i in o]
    else:
        return o

Вы вызываете makedata в словаре, который хотите преобразовать, или, возможно, trydata в зависимости от то, что вы ожидаете в качестве ввода, и он выдает объект данных.

Примечания:

  • Вы можете добавить elifs в trydata , если вам нужна дополнительная функциональность.
  • Очевидно, что это не сработает, если вы хотите xa = {} или аналогичный.
  • Если вам нужна версия только для чтения, используйте данные класса из исходного ответа .
1
ответ дан 22 November 2019 в 22:35
поделиться

Обычно Вы хотите зеркально отразить dict иерархию в свой объект, но не список или кортежи, которые обычно являются на самом низком уровне. Таким образом, это - то, как я сделал это:

class defDictToObject(object):

    def __init__(self, myDict):
        for key, value in myDict.items():
            if type(value) == dict:
                setattr(self, key, defDictToObject(value))
            else:
                setattr(self, key, value)

, Таким образом, мы делаем:

myDict = { 'a': 1,
           'b': { 
              'b1': {'x': 1,
                    'y': 2} },
           'c': ['hi', 'bar'] 
         }

и доберитесь:

x.b.b1.x 1

x.c ['привет', 'панель']

0
ответ дан 22 November 2019 в 22:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: