@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()
  • Вопрос задан
  • 495 просмотров
Решения вопроса 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 зарегистрировать кастомный обработчик следующего сообщения. Этот обработчик будет обрабатывать только сообщения этого пользователя, подобное поведение не будет влиять на других пользователей. Для более сложных взаимодействий можно делать длинные и даже ветвящиеся цепочки обработчиков, спрашивать у пользователя разные данные, предлагать изменить ранее введённые данные итд итп.

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

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

Войти через центр авторизации
Похожие вопросы