Ну, ответ, который вы получите, - это именно то, что можно ожидать от этого:
response = self.command(command)
self.handle_command(response, channel)
и это:
def command(self, func):
"""
Simple wrapper for bot commands
"""
def wrapper_command():
func()
return wrapper_command
Вы вызываете self.command(...)
и передаете результат в self.handle_command()
, self.command()
возвращает функцию, поэтому self.handle_command()
получает этот вопрос в качестве параметра response
.
Вы все еще не объяснили, что ожидали command()
, когда будете использовать его в качестве декоратора, но я предполагаю, что вы хотите использовать декорированную функцию в качестве обработчика для данной «команды» (параметр, а не функция - подсказка: используйте разные имена для разных вещей), т.е. self.command('greet')
должен вызывать функцию greet
.
Самое первое, что вам нужно, - это использовать различные методы для выполнения команд и их регистрации - поэтому мы назовем эти методы execute_command
и register_command
- и пока мы будем работать, мы переименуем "handle_command" "to" send_response ", потому что это то, что он действительно делает:
def startup(self):
#Startup the client
if slack_client.rtm_connect(with_team_state=False):
print("Slack Bot connected and running!")
# Read bot's user ID by calling Web API method `auth.test`
self.starterbot_id = slack_client.api_call("auth.test")["user_id"]
while True:
command, channel = self.parse_bot_commands(slack_client.rtm_read())
if command:
response = self.execute_command(command)
self.send_response(response, channel)
time.sleep(self.RTM_READ_DELAY)
else:
print("Connection failed. Exception traceback printed above.")
def execute_command(self, command):
"""
Executes bot command if the command is known
"""
# mock it for the moment
return "this is a mockup"
def send_response(self, response, channel):
# Default response is help text for the user
default_response = "Not sure what you mean. Try *{}*.".format(self.EXAMPLE_COMMAND)
# Sends the response back to the channel
slack_client.api_call("chat.postMessage", channel=channel, text=response or default_response)
def register_command(self, func):
"""
TODO
"""
Теперь для декоратора. Обертывание функций в другие функции, которые будут выполнять «вокруг» декорированной, является распространенным случаем для декораторов, но это не означает, что это обязательно. технически «декоратор» - это просто «функция более высокого порядка»: функция, которая принимает функцию в качестве аргумента и возвращает функцию в качестве результата. На самом деле, синтаксис @decorator
является только синтаксическим сахаром, поэтому
@decorate
def func():
pass
это просто причудливый способ написать
def func():
pass
func = decorate(func)
и как только вы поймете это, вы также поймете, что здесь нет абсолютно ничего волшебного.
Теперь вернемся к нашему register_command
декоратору. Мы хотим сохранить аргумент (функцию), чтобы мы могли получить его по его имени. Это легко сделать с помощью dict и func.__name__
:
def __init__(self, ...):
# init code here
self._commands = {}
def register_command(self, func):
self._commands[func.__name__] = func
# and that's all - no wrapper needed here
return func
Так что теперь вы можете использовать
@bot.register_command:
def greet():
return "Hello"
, а затем bot._commands
должен содержать 'greet': <function greet @...>
.
Теперь для метода execute_command
- это довольно просто: ищите self._commands, если что-то найдено, вызывайте его и возвращайте ответ, иначе возвращайте ответ по умолчанию:
def execute_command(self, command):
handler = self._commands.get(command)
if handler:
return handler()
# default:
return "Not sure what you mean. Try *{}*.".format(self.EXAMPLE_COMMAND)
и теперь мы можем упростить send_response()
, поскольку execute_command
позаботится о предоставлении ответа по умолчанию:
def send_response(self, response, channel):
# Sends the response back to the channel
slack_client.api_call("chat.postMessage", channel=channel, text=response)