PyYAML анализируют в объект arbitary

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

import yaml

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

         """
    )

print type(x)
print x


Который приводит к следующему выводу:

{'product': {'sku': 123, 'name': 'Product X', 'features': [{'weight': '10kg', 'size': '10x30cm'}]}}

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

Я хотел бы к следующему:

print x.features[0].size

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

Править:

  • Обновленный запутывающая часть о 'объекте со строгим контролем типов'.
  • Измененный доступ к features к индексатору как предложенный Alex Martelli

5
задан Philip Fourie 4 March 2015 в 05:15
поделиться

1 ответ

Итак, у вас есть словарь со строковыми ключами и значениями, которые могут быть числами, вложенными словарями, списками, и вы хотите обернуть его в экземпляр, который позволяет использовать доступ к атрибутам вместо индексации 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 , я понятия не имею, но ясно, что пропуск лучше применять в точке вызова, а не жестко закодировать в классе оболочки или функции фабрики оболочки, которую я только что показал).

Правка : поскольку ОП говорит, что ему нужны функции [0] , а не функции (0) , просто измените последние две строки на

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

, т. Е. define __ getitem __ (магический метод, лежащий в основе индексации) вместо __ call __ (магический метод, лежащий в основе вызова экземпляра).

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

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

8
ответ дан 14 December 2019 в 04:35
поделиться
Другие вопросы по тегам:

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