@oldziggy

Как сделать так, чтобы бот выполнял команду 1 раз?

Делаю телеграм-бота на пайтоне с помощью pyTelegramBotAPI.
Задача такая: бот, получая команду /weather, спрашивает у пользователя, погоду в каком городе ему нужно узнать.
Как сделать так, чтобы получить данные о погоде можно было только 1 раз после того, как бот запросил название города?
Сейчас можно бесконечно вводить города, и бот будет выводить данные.

import pyowm
from pyowm.owm import OWM
from pyowm.utils.config import get_default_config
import telebot
config_dict = get_default_config()
config_dict['language'] = 'ru'
owm = OWM('ded24f42ea01e055a761c651727ffaf3', config_dict)
mgr = owm.weather_manager()



bot = telebot.TeleBot("5188340734:AAHuYIaiLeL-3JQRGQwxcIFk_rUQP2kMd2c")

@bot.message_handler(commands=['weather'])
def send_message(message):
    bot.send_message(message.chat.id, "Введи название города.")
    @bot.message_handler(content_types = ['text'])
    def send_message(message):
        country = str("RU")
        city = (message.text)
        place = city + ", " + country

        observation = mgr.weather_at_place(message.text)
        w = observation.weather.detailed_status
        temp = temp_dict_celsius = observation.weather.temperature('celsius')

        answer = "Погода в городе " + city + ":" + "\n"
        answer += w + "\n"
        answer += "Температура воздуха " + str((temp['temp'])) + " по цельсию." + "\n"
        if temp['temp'] <= 0:
            answer += ('Стоит надеть пуховик!')
        elif (temp['temp'] >0) and (temp['temp'] <10):
            answer += ('Тепло будет и в легкой куртке!')
        elif (temp['temp'] >11) and (temp['temp'] <20):
            answer += ('Выходи без куртки, а то только вспотеешь.')
        elif temp['temp'] >= 20:
            answer += ('Лучше остаться дома и включить кондиционер')


        bot.send_message(message.chat.id, answer)


@bot.message_handler(commands=['start'])
def send_welcome(message):
	bot.send_message(message.chat.id, "Это тренировочный бот. Введи /weather, чтобы узнать информацию о погоде.")




bot.infinity_polling()
  • Вопрос задан
  • 693 просмотра
Решения вопроса 1
shurshur
@shurshur
Сисадмин, просто сисадмин...
Ох, ну тут всё неправильно.

Не надо пихать ещё одну функцию send_message внутри send_message. Их надо вынести на один уровень. И вообще, назвать более адекватно их содержанию. Ведь первая обрабатывает команду /weather, а вторая - название города. Странно называть их одинаково неопределённым send_message (чтоб враги не догадались?).

Что происходит в этом коде? Сначала мы регистрируем обработчики команд /weather и /start с помощью декоратора. При вызове /weather мы КАЖДЫЙ раз (ведь это часть функции-обработчика на следующем уровне вложенности!) заново определяем обработчик для content_type=text. Далее после первого вызова /weather этот обработчик начинает работать на все текстовые сообщения. Причём на сообщения ВСЕХ пользователей нашего бота. То есть реально, один вызывает /weather и тем самым изменяет поведение бота для всех пользователей сразу. Если в боте будет где-то ещё определяться таким же "внутренним" описанием ещё один обработчик content_type=text, то он будет всегда игнорироваться до следующего перезапуска бота, ведь один обработчик текстовых сообщений уже есть и он всегда будет применяться.

Чего удивительного в том, что бот работает ровно так же странно, как странно написано в его коде?

Надо понимать, что обработчик сообщения принимает ОДНО сообщение и его обрабатывает. Он не может принять сообщение и ещё сразу же следующее. Каждое обработается своим обработчиком. Чтобы обработка сообщений зависела от ряда сообщений, используют FSM (Finite State Machine), машину состояний. В telebot есть довольно простая в использовании FSM на основе вызова register_next_step_handler. Вызов register_next_step_handler переопределяет то, каким обработчиком будет обработано следующее сообщение с этим пользователем (точнее, в этом chat_id, который может быть и идентификатором группы).

Собственно, принцип работы такой: когда пользователь вызывает /weather, мы должны с помощью вызова bot.register_next_step_handler зарегистрировать кастомный обработчик следующего сообщения. Этот обработчик будет обрабатывать только сообщения этого пользователя, подобное поведение не будет влиять на других пользователей. Для более сложных взаимодействий можно делать длинные и даже ветвящиеся цепочки обработчиков, спрашивать у пользователя разные данные, предлагать изменить ранее введённые данные итд итп.

Официальный пример использования смотреть тут.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

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