PyYAML выполняет синтаксический анализ в произвольный объект

StackOverflow https://stackoverflow.com/questions/2442933

  •  19-09-2019
  •  | 
  •  

Вопрос

У меня есть следующая программа на Python 2.6 и определение YAML (с использованием Пиямл):

import yaml

x = yaml.load(
    """
        product:
           name     : 'Product X'
           sku      : 123
           features :
             - size    :  '10x30cm'
               weight  :  '10kg'

         """
    )

print type(x)
print x


Что приводит к следующему результату:
<type 'dict'>
{'product': {'sku': 123, 'name': 'Product X', 'features': [{'weight': '10kg', 'size': '10x30cm'}]}}

Можно создать объект с полями из x?

Я хотел бы сделать следующее:

print x.features[0].size

Я знаю, что можно создать экземпляр из существующего класса, но это не то, что я хочу для данного конкретного сценария.

Редактировать:

  • Обновлена запутанная часть о "строго типизированном объекте".
  • Изменен доступ к features индексатору , как предложил Алекс Мартелли
Это было полезно?

Решение

Итак, у вас есть словарь со строковыми ключами и значениями, которые могут быть числами, вложенными словарями, списками, и вы хотели бы обернуть это в экземпляр, который позволяет вам использовать доступ к атрибутам вместо индексации dict и "вызывать с индексом" вместо индексации списка - не уверен, какое отношение к этому имеет "строго типизированный", или почему вы думаете .features(0) это лучше, чем .features[0] (такой более естественный способ индексирования списка!), но, конечно, это выполнимо.Например, простым подходом может быть:

def wrap(datum):
  # don't wrap strings
  if isinstance(datum, basestring):
    return datum
  # don't wrap numbers, either
  try: return datum + 0
  except TypeError: pass
  return Fourie(datum)

class Fourie(object):
  def __init__(self, data):
    self._data = data
  def __getattr__(self, n):
    return wrap(self._data[n])
  def __call__(self, n):
    return wrap(self._data[n])

Итак x = wrap(x['product']) должен дать вам ваше пожелание (почему вы хотите пропустить этот уровень, когда ваша общая логика, очевидно, требует x.product.features(0).size, я понятия не имею, но очевидно, что пропуск лучше применять в точке вызова, а не жестко кодировать в классе-оболочке или функции фабрики-оболочки, которую я только что показал).

Редактировать:как говорит оперативник, он действительно хочет features[0] вместо того , чтобы features(0), просто измените последние две строки на

  def __getitem__(self, n):
    return wrap(self._data[n])

т.е. определить __getitem__ (магический метод, лежащий в основе индексации) вместо __call__ (магический метод, лежащий в основе вызова экземпляра).

Альтернатива "существующему классу" (здесь, Fourie) было бы создать новый класс "на лету" на основе самоанализа обернутого dict - тоже возможно, но серьезно темно-серого, если не на самом деле Черный, магия, и без какого-либо реального оперативного преимущества, о котором я могу думать.

Если ОП сможет точно объяснить, почему он может стремиться к вершинам метапрограммирования в создании классов "на лету", какое преимущество, по его мнению, он мог бы получить таким образом и т.д., я покажу, как это сделать (и, вероятно, я также покажу, почему желанное преимущество будет нет на самом деле будь там;-).Но простота - важное качество в любом начинании программиста, и использовать "глубокую темную магию", когда простой код, подобный приведенному выше, работает просто отлично, как правило, не самая лучшая идея!-)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top