最近在學習寫 telegram bot,在把教學的語法包裝成一個 class 的時候遇到了一些問題
import logging
from telegram import Update
from telegram.ext import Updater, MessageHandler, CommandHandler, CallbackContext, Filters
class Bot:
@staticmethod
def start(update: Update, context: CallbackContext):
context.bot.send_message(chat_id=update.effective_chat.id, text="這是一個機器人,輸入 /help 獲得更多使用說明")
@staticmethod
def help(update: Update, context: CallbackContext):
context.bot.send_message(chat_id=update.effective_chat.id, text="")
@staticmethod
def unknown(update: Update, context: CallbackContext):
context.bot.send_message(chat_id=update.effective_chat.id, text="未知的指令,輸入 /help 獲得更多使用說明")
def __init__(self):
self.updater = Updater(token='example')
self.dispatcher = self.updater.dispatcher
self.init_command()
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO)
self.updater.start_polling()
def init_command(self):
self.dispatcher.add_handler(CommandHandler('start', self.start)) # 處理 start command
self.dispatcher.add_handler(CommandHandler('help', self.help)) # 處理 help command
self.dispatcher.add_handler(MessageHandler(Filters.command, self.unknown)) # 處理所有上述以外的 command
if __name__ == "__main__":
bot = Bot()
為什麼在這邊 @staticmethod 這個 decorator 是必要的?
如果把 @staticmethod 取消後會讓 add_handler 裡面的 self.start/help/unknown 出現錯誤,錯誤訊息如下
Expected type '(Update, Any) -> Any' (matched generic type '(Update, CCT) -> RT'), got '(context: CallbackContext) -> None' instead
可以解釋為什麼當 class 調用內部的函數時會需要宣告成 staticmethod 呢?
因為如果取消 @staticmethod ,那物件的方法的第一個參數就是self,像下面這樣改試試吧
class Bot:
def start(self, update: Update, context: CallbackContext):
context.bot.send_message(chat_id=update.effective_chat.id, text="這是一個機器人,輸入 /help 獲得更多使用說明")
def help(self, update: Update, context: CallbackContext):
context.bot.send_message(chat_id=update.effective_chat.id, text="")
def unknown(self, update: Update, context: CallbackContext):
context.bot.send_message(chat_id=update.effective_chat.id, text="未知的指令,輸入 /help 獲得更多使用說明")
def __init__(self):
self.updater = Updater(token='example')
self.dispatcher = self.updater.dispatcher
self.init_command()
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO)
self.updater.start_polling()
def init_command(self):
self.dispatcher.add_handler(CommandHandler('start', self.start)) # 處理 start command
self.dispatcher.add_handler(CommandHandler('help', self.help)) # 處理 help command
self.dispatcher.add_handler(MessageHandler(Filters.command, self.unknown)) # 處理所有上述以外的 command
是說這邊用 staticmethod 實在不太對。
至於什麼時候用 staticmethod ...
https://ji3g4zo6qi6.medium.com/python-tips-5d36df9f6ad5
我個人是很少用,classmethod 比較常用。
你好,依照上面的寫法可以成功跑過,但是 IDE 會提示那幾個 function 應該是 static,可以為解釋一下為什麼 IDE 會這樣判斷嗎?
因為我是希望把機器人會用到的指令都包在同一個 class 裡面
IDE的提示貼出來我看看。
@cave_rabbit: 看圖片,我猜是這個的關係: Why does PyCharm propose to change method to static?
(因為圖片內容訊息太少 + 我去翻源碼也看不出所以然~所以用猜的~坐等 froce 大有空時給出的見解~)
應該就是stack overflow那篇說的,一個物件方法的第一個參數,你不是用一般method的self,也不是用classmethod的cls,那IDE就認為你用的是staticmethod,而提示你。
總之依你的場景用不到 staticmethod/classmethod。