Рубрики
Без рубрики

Расширение SimplenAmespace для вложенных словарей

Я огромный поклонник типов Python3. SimplenAmespace. По сути, это позволяет нам принять дикт, как так: … Теги с Python, учебник.

Я огромный поклонник Python3’s Типы. SimplenAmespace. . По сути, это позволяет нам принять дикт, как так:

my_dict = {
  "a": 1,
  "b": 2,
  "c": 3,
}

my_dict["a"] # 1
my_dict["b"] # 2, etc

И управлять этим так:

from types import SimpleNamespace
my_namespace = SimpleNamespace(a=1, b=2, c=3)

my_namespace.a # 1
my_namespace.b # 2
my_namespace.c # 3

В качестве альтернативы, мы также могли сделать что-то вроде:

from types import SimpleNamespace

my_dict = {
  "a": 1,
  "b": 2,
  "c": 3,
}

my_namespace = SimpleNamespace(**my_dict)
my_namespace.a # 1
my_namespace.b # 2
my_namespace.c # 3

Но – что происходит, если наше my_dict вложен? Вот так:

my_dict = {
  "a": {
    "d": 4,
  },
  "b": 2,
  "c": 3,
  "e": [5,6,7,{
    "f": 8,
  }]
}

my_namespace = SimpleNamespace(**my_dict)
my_namespace.a # {"d": 4} /womp womp 😭
my_namespace.a.d # raises Exception! 😭😭

Короче говоря, Simplenanamespace Просто не поддерживает этот корпус использования. Но это нормально! Мы можем продлить Simplenanamespace и построить эту функциональность для себя.

Определение рекурсивного пространства имен

from types import SimpleNamespace

# this is how SimpleNamespace looks when output
SimpleNamespace(**my_dict)
# namespace(a={'d': 4}, b=2, c=3, e=[5, 6, 7, {'f': 8}])

class RecursiveNamespace(SimpleNamespace):

  @staticmethod
  def map_entry(entry):
    if isinstance(entry, dict):
      return RecursiveNamespace(**entry)

    return entry

  def __init__(self, **kwargs):
    super().__init__(**kwargs)
    for key, val in kwargs.items():
      if type(val) == dict:
        setattr(self, key, RecursiveNamespace(**val))
      elif type(val) == list:
        setattr(self, key, list(map(self.map_entry, val)))

# this is how RecursiveNamespace looks when output
RecursiveNamespace(**my_dict)
# RecursiveNamespace(
#    a=RecursiveNamespace(d=4), 
#    b=2, 
#    c=3, 
#    e=[5, 6, 7, RecursiveNamespace(f=8)])

Итак, что здесь происходит? Мы устанавливаем новый класс, RecursivenAmespace это расширяется Simplenanamespace Отказ В __init__ Метод конструктора, мы называем Simplenanamespace Конструктор. Затем мы просто проходим через наш словарь и ценность, который является Также Словарь или список, мы создали то, что с RecursivenAmespace Отказ ТА ДА.

Слияние

Технически мы даже не нужны Типы. Simplenanamespace Здесь – мы можем реализовать этот класс без просто добавления двух строк кода:

class RecursiveNamespace2: # without extending SimpleNamespace!

  @staticmethod
  def map_entry(entry):
    if isinstance(entry, dict):
      return RecursiveNamespace(**entry)

    return entry

  def __init__(self, **kwargs):
    for key, val in kwargs.items():
      if type(val) == dict:
        setattr(self, key, RecursiveNamespace(**val))
      elif type(val) == list:
        setattr(self, key, list(map(self.map_entry, val)))
      else: # this is the only addition
        setattr(self, key, val)

Оригинал: “https://dev.to/taqkarim/extending-simplenamespace-for-nested-dictionaries-58e8”