Yesterday we upgraded our slackclient module in python and needed to change some code based on this migration guide for the RTM API.
https://github.com/slackapi/python-slackclient/wiki/Migrating-to-2.x
Here is my code...
import slack
slack_token = os.environ['SLACK_BOT_TOKEN']
rtmclient = slack.RTMClient(token=slack_token)
@slack.RTMClient.run_on(event='message')
def parse_message(**payload):
data = payload['data']
channel_id = data['channel']
print(data)
print(channel_id)
rtmclient.start()
I had never worked with a Python decorator before this.
After reading up on decorators, it was my understanding that the decorator slack.RTMClient.run_on
would be called if I were to call the function parse_message
.
This code appears to be doing the opposite.
Why/how does this code work when rtmclient.start()
is called?
Not familiar with that particular API, but
@slack.RTMClient.run_on(event='message')
def parse_message(**payload):
...
is essentially the same as
def parse_message(**payload):
...
parse_message = slack.RTMClient.run_on(event='message')(parse_message)
The decorator is not called when the function is called, but when it is declared. It will then usually define and return a new function that will be called instead of the original function, e.g. with additional logging, memoization, and the like.
But it is also perfectly possible for a decorator to just return the original version of the function,1 but e.g. register that function as a callback for some events.
A very much simplified example:
my_callbacks = []
def register(f):
my_callbacks.append(f)
return f
@register
def foo():
print("calling foo")
for f in my_callbacks:
f()
1) As noted in comments, this decorator seems to not even return the original function but None
, meaning that the function will no longer be directly callable after being decorated, only via the callback.