LINUX.ORG.RU

TypeError: object of type 'filter' has no len()

 ,


0

1

Всем привет!

Есть такой код из туториала про веб-сервис:

#!flask/bin/python
from flask import Flask, jsonify
from flask import abort

app = Flask(__name__)

tasks = [
    {
        'id': 1,
        'title': u'Buy groceries',
        'description': u'Milk, Cheese, Pizza, Fruit, Tylenol',
        'done': False
    },
    {
        'id': 2,
        'title': u'Learn Python',
        'description': u'Need to find a good Python tutorial on the web',
        'done': False
    }
]

@app.route('/')
def index():
   return "200 OK"

@app.route('/todo/api/v1.0/tasks', methods=['GET'])
def get_tasks():
    return jsonify({'tasks': tasks})

@app.route('/todo/api/v1.0/tasks/<int:task_id>', methods=['GET'])
def get_task(task_id):
    task = filter(lambda t: t['id'] == task_id, tasks)
    if len(task) == 0:
        abort(404)
    return jsonify({'task': task[0]})

if __name__ == '__main__':
    app.run(debug=True)

Проблема в том, что когда вызываешь /todo/api/v1.0/tasks/2 все валится с ошибкой: TypeError: object of type 'filter' has no len() В чем тут проблема никак не могу понять.


В том, что у объекта типа filter нет метода len().
Почитай, чем filter в тройке отличается от filter во втором python.

beresk_let ★★★★★
()

Оберни вызов filter в list()

В python2 filter сам по себе возвращал список, но в python3 он возвращает итератор. Если нужен список, то теперь надо делать list(filter(..)), аналогично с map

Crocodoom ★★★★★
()
Ответ на: комментарий от Virtuos86

Туториал по python почитать не мешало бы автору этого туториала по Flask

Потому что «немножко код по-дэбильному написан» (с)

Crocodoom ★★★★★
()
Ответ на: комментарий от gadzira

Туториал же про веб-сервис)

Я понял. А надо бы хотя бы древнючую книгу ГВР про Python 2.2 в переводе Откидача проштудировать. Что-то там устарело, а многого и в принципе нет, но фундаментальное понимание даёт.

Когда питонокодер не в состоянии извлечь причину возникновения исключительной ситуации из стэктрейса (для чего достаточно знать базовый английский и базовый Python), то, увы, это безошибочно выдаёт в нём нуба.

Virtuos86 ★★★★★
()
Ответ на: комментарий от Virtuos86

Да там всю функцию get_task(task_id) надо переписывать. Начнём с того, что её код пытается опираться на то, что все id в списке tasks уникальны. Но делает это криво.

Как ты видишь, ищется список tasks совпадающих id.

  • Если нужных айдишников действительно может найтись несколько, тогда надо это ситуацию как-то обрабатывать на месте, а не тупо брать task[0] и забивать на остальные найденные значения.
  • Если нужных айдишников не более одного (это гарантируется каким-то другим кодом в другом месте), то не нужно гнать фильтром по всему списку tasks, это оверхед на пустом месте, да и просто некрасиво. Достаточно найти первое совпадение. В python3 это будет что-то вроде next(filter(..)).

Теперь да, насчёт len(task) == 0. Я не знаю, как именно отрабатывает вызов abort(404), но идиоматично здесь должна быть обработка исключения, которое будет бросать поиск по айдишнику. Если мы оставляем корявый вариант с task[0], то это будет обработка исключения IndexError, если переделываем, то какое-то другое исключение.

Третье замечание в том, что для хранения задач используется список вида [{'id': 1, ...}, {'id': 2, ...}, ...]. Тут нужно заводить словарь с ключом в виде id, тогда и никакой фильтр не нужен будет. Просто делаем tasks[id], а вместо len(task) == 0 тогда обрабатываем исключение KeyError.

Crocodoom ★★★★★
()
Ответ на: комментарий от Crocodoom

Что поделать, туториалы пишут те, кто их пишет. Возможно, тут идея просто написать что-то работающее в целом, пускай и несовершенное в деталях.

Virtuos86 ★★★★★
()
Ответ на: комментарий от gadzira

Скажем так, ты пытаешься участвовать в ралли, не умея чинить автомобиль. Проблема в том, что он обязательно сломается, и чинить придется. Так что если хочешь далеко уехать, чинить придется научиться, и желательно учиться не на ходу.

Virtuos86 ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.