我尝试创建一个简单的装饰器来与 Slack API 一起使用,以进行进一步的编码,以便以后更容易、更有组织地改进功能(比如说,在将来,我希望包含一个我想要的新函数/命令)机器人要做的事)
但它没有按我的预期工作。让我解释一下,这是我的代码(我省略了大量代码,例如实例化、 token 等,以保持问题简短并说明要点)它包含一个简单的函数,该函数应该在松弛 channel :
class Bot(object):
def __init__(self):
# Bot's user ID in Slack: value is assigned after the bot starts up
self.starterbot_id = None
# Declare constants
self.RTM_READ_DELAY = 1 # 1 second delay between reading from RTM
self.EXAMPLE_COMMAND = "do"
self.MENTION_REGEX = "^<@(|[WU].+?)>(.*)"
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.command(command)
self.handle_command(response, channel)
time.sleep(self.RTM_READ_DELAY)
else: print("Connection failed. Exception traceback printed above.")
def handle_command(self, response, channel):
"""
Executes bot command if the command is known
"""
# 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 command(self, func):
"""
Simple wrapper for bot commands
"""
def wrapper_command():
func()
return wrapper_command
'''USAGE:'''
bot = Bot()
bot.startup()
@bot.command
def greet():
response = "Hi there I am CodeMonkey"
return response
我正在寻找的是 greet()
命令来让机器人输出 “嗨,我是 CodeMonkey”
机器人确实做出了回应,但没有打招呼。相反,它返回对象。这是我从 channel 中的机器人得到的响应:
CodeMonkey APP [11:40 PM]
<function Bot.command.<locals>.wrapper_command at 0x1083281e0>
我仍在学习使用装饰器,我觉得它们会让我的 Slack Bot 编码变得更容易、更有组织,但我做错了什么?
最佳答案
嗯,您得到的响应正是人们所期望的:
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”重命名为“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)
关于python - 将装饰器与 Python Slack API 一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54199411/