Jinja: Невозможно перебрать объект с элементом "items"

Созданный на 9 янв. 2017  ·  10Комментарии  ·  Источник: pallets/jinja

Сервер возвращает этот JSON:
{
"предметы": [1,2,3]
...
}

Попытка перебрать «элементы» дает:
{% для el в data.items%}
....
TypeError: объект 'builtin_function_or_method' не повторяется

Это происходит потому, что Python dict имеет встроенную функцию «items ()».

Как темп. Чтобы обойти эту проблему, я установил перехватчик и переименовал ключи в ответе JSON с «items» на «__items», а затем передал это Jinja2. В этот момент я перебираю переименованный атрибут в порядке:
{% для el в data .__ items%}

В идеале Jinja2 должен игнорировать встроенные функции в цикле for или if, если они специально не вызываются с помощью нотации function ().

Самый полезный комментарий

Вы можете использовать {% for el in data['items'] %} для определения приоритета элемента. Это также описано в документации. http://jinja.pocoo.org/docs/2.9/templates/#variables

Все 10 Комментарий

Вы можете использовать {% for el in data['items'] %} для определения приоритета элемента. Это также описано в документации. http://jinja.pocoo.org/docs/2.9/templates/#variables

Он не будет работать, если ответ JSON иногда не включает «элементы» (скажем, это необязательный атрибут ответа). В этом случае {% for el in data ['items']%} также даст:
TypeError: объект 'builtin_function_or_method' не повторяется

... поскольку items всегда определяется (как встроенная функция).

И это ошибка, ИМО. Данные ['items'] никогда не должны конфликтовать со встроенными функциями. Другими словами, если вы хотите аккуратно перебрать необязательный атрибут «items», вы должны его переименовать. В идеале этого не должно быть.

Почему ответ JSON не включает элементы? Я не совсем уверен, что вижу здесь проблему. Конечно, вы заранее знаете, каковы ваши данные. Вы также можете в шаблонах проверять ключи с помощью оператора in уже в словарях.

Об изменении этого поведения совершенно не может быть и речи, потому что тысячи шаблонов сломаются, если мы удалим эту поддержку атрибута / элемента.

Я не предлагаю ничего отказываться, просто чтобы было строже.

Проблема сегодня в том, что когда вы используете явную нотацию поиска: data['items'] она находит встроенную функцию словаря, а не должна . Python этого не делает, и jinja не должен. Если нужно вызвать встроенную функцию (или любую другую функцию, если на то пошло), у вас есть для нее вызывающая нотация: data.items()

Не уверен, что это будет очень понятно для особого случая dict.items там. Тем более, что он по-прежнему терпит неудачу для пользовательских dict-подобных типов или, может быть, даже для OrderedDict . Думаю, в таких случаях лучше foo['items'] . Это не очень красивое, но последовательное поведение.

Единственное возможное «исправление / взлом», которое я мог бы представить, чтобы исправить это лучше, - это проверка того, используется ли простой атрибут (то есть не вызов функции) в итерации, и вы пытаетесь перебрать что-то, что не повторяется, но вызывается . В этом случае попытка элемента вряд ли приведет к поломке существующего кода. Однако реализация такого поведения в Jinja, вероятно, была бы крайне ужасной;)

Почему это особый случай? Я прошу Jinja вести себя точно так же, как Python. В частности, foo ['items'] должен возвращать значение None, если в нем нет вставленных пользователем ключевых «элементов». Сегодня Jinja возвращается к поиску одноименной встроенной функции. Так что просто делайте то, что делает Python:

>>> print {}.get('items')
None

Кстати, я также считаю, что с альтернативной нотацией «foo.items» тоже нужно работать, так как вам нужно использовать «()» для вызова вызываемого объекта, но если вам требуется некоторая обратная совместимость для foo.items, чтобы либо найти клавишу или вызвать функцию автоматически, тогда я думаю, что это очень плохо.

Логика Jinja для ['x'] и .x такова:

  • Проверьте, существует ли элемент / attr (независимо от вашего синтаксиса в Python), если да, используйте это
  • Проверьте, существует ли attr / item ("противоположность" тому, что ваш синтаксис делает в Python), если да, используйте это
  • Ошибка, если ни один из них не существует

Итак, x.items проверяет атрибут, и, поскольку он существует, он его использует. Эта логика работает независимо от конкурса. Для улучшения этого потребуется изменение логики поиска атрибутов в зависимости от контекста. И даже тогда это привело бы к неловким ситуациям, подобным этому коду, который будет работать:

{% for x in mydict.items %}

против этого кода, который не будет работать

{% set items = mydict.items %}
{% for x in items %}

И поддерживать особую обработку в этом случае было бы просто невозможно без отслеживания того, откуда взялась переменная.

@slisznia , по сути, вы просите Jinja2 полностью изменить систему поиска атрибутов, которая существует уже около 7 лет.

Ах, я даже не видел предложения foo['bar'] не выполнять поиск атрибутов. Это определенно плохая идея! Что плохого в том, что вы просто используете for item in data.get('items', []) ?

@ThiefMaster mydict.get('items', []) конечно, работает, и спасибо за указание на другой метод, кроме переименования ключей.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги