如何在 Python 中使用装饰器创建事件监听器?

lol*_*nut 0 python decorator discord

我想创建一个像这样的事件监听器:

@some.event
async def on_ready(some_info):
    print(some_info)

@some.event
async def on_error(err):
    print(err)
Run Code Online (Sandbox Code Playgroud)

因此,当某些内容准备就绪时,或者如果在 WebSocket 等中收到消息,请将此用于 Discord,因为某些信息仅在机器人被识别或准备就绪时可用

我见过类似的东西:

def add_listener(func, name):
   # ...

def remove_listener(func, name):
   # ...
Run Code Online (Sandbox Code Playgroud)

但我真的不知道如何使用它或创建一个

小智 7

这是我快速编码的一个简单的基于类的解决方案:

class Event:
    def __init__(self):
        # Initialise a list of listeners
        self.__listeners = []
    
    # Define a getter for the 'on' property which returns the decorator.
    @property
    def on(self):
        # A declorator to run addListener on the input function.
        def wrapper(func):
            self.addListener(func)
            return func
        return wrapper
    
    # Add and remove functions from the list of listeners.
    def addListener(self,func):
        if func in self.__listeners: return
        self.__listeners.append(func)
    
    def removeListener(self,func):
        if func not in self.__listeners: return
        self.__listeners.remove(func)
    
    # Trigger events.
    def trigger(self,args = None):
        # Run all the functions that are saved.
        if args is None:
            args = []
        for func in self.__listeners: func(*args)
Run Code Online (Sandbox Code Playgroud)

它允许您创建一个Event函数可以“订阅”的函数:

evn = Event()

# Some code...

evn.trigger(['arg x','arg y'])
Run Code Online (Sandbox Code Playgroud)

这些函数都可以使用装饰器订阅事件:

@evn.on
def some_function(x,y): pass
Run Code Online (Sandbox Code Playgroud)

或者用以下addListener方法:

def some_function(x,y): pass
evn.addListener(some_function)
Run Code Online (Sandbox Code Playgroud)

您还可以删除侦听器:

evn.removeListener(some_function)
Run Code Online (Sandbox Code Playgroud)

要创建类似于您要求的内容,您可以执行以下操作:

# some.py

from event import Event

class SomeClass:
    def __init__(self):
        # Private event variable
        self.__event = Event()
        # Public event variable (decorator)
        self.event = self.__event.on

some = SomeClass()
Run Code Online (Sandbox Code Playgroud)

然后像这样使用它:

# main.py

from some import some

@some.event
async def on_ready(some_info):
    print(some_info)

@some.event
async def on_error(err):
    print(err)
Run Code Online (Sandbox Code Playgroud)