python使用裝飾器實現的事件中心(監聽器)

Excel2016發表於2024-06-10

其中GroupMessage,FriendMessage就是兩個python類
@evn.on(GroupMessage)與evn.trigger(GroupMessage, 'arg1', 'arg2')
裡面傳的GroupMessage代表事件名為<class 'mirai.models.events.GroupMessage'>作為字典的鍵

import functools

from mirai import GroupMessage,FriendMessage


class Event:
    def __init__(self, name, func):
        # 初始化事件物件,包含事件名稱和對應的函式
        self.name = name
        self.func = func


class EventCenter:
    def __init__(self):
        # 初始化一個字典來儲存事件名稱和對應的事件列表
        self.__listeners = {}

    @property
    def on(self):
        # 返回一個裝飾器工廠
        def add(event_name):
            def decorator(func):
                @functools.wraps(func)  # 應用於wrapper函式
                def wrapper(*args, **kwargs):
                    # 執行被裝飾的函式
                    return func(*args, **kwargs)

                # 建立Event物件並註冊事件監聽器
                event = Event(event_name, wrapper)
                self.addListener(event)
                return wrapper  # 返回wrapper函式,它現在是一個裝飾器

            return decorator

        return add

    def addListener(self, event: Event):
        # 新增事件監聽器到對應的事件名稱下
        event_name = self.__listeners.get(event.name)
        if event_name is None:
            self.__listeners[event.name] = []  # 如果事件名稱不存在,初始化一個空列表
        self.__listeners[event.name].append(event.func)  # 新增函式到對應的列表

    def removeListener(self, event: Event):
        # 移除事件監聽器
        if event.name in self.__listeners:
            self.__listeners[event.name].remove(event.func)

    def trigger(self, event_name, *args, **kwargs):
        # 觸發事件
        event_funcs = self.__listeners.get(event_name)
        if event_funcs:
            for func in event_funcs:
                func(*args, **kwargs)


evn = EventCenter()


@evn.on(GroupMessage)
def fun(x, y):
    # 定義事件1對應的函式
    print("group message", x, y)


@evn.on(FriendMessage)
def fun2(x, y):
    # 定義事件2對應的函式
    print("member message", x, y)


# 觸發事件,預期輸出 "aaa arg1 arg2" 和 "bbb arg1 arg2"
evn.trigger(GroupMessage, 'arg1', 'arg2')
evn.trigger(FriendMessage, 'arg1', 'arg2')


# 再次新增相同的函式到事件1
@evn.on(GroupMessage)
def fun3(x, y):
    """方法三"""
    print("group message again", x, y)


# 再次觸發事件1,預期會看到兩次輸出,因為新增了兩個不同的函式到同一個事件
evn.trigger(GroupMessage, 'arg1', 'arg2')

# 並且輸出方法也正確
f = evn.on(FriendMessage)(fun3)
print(f.__name__)
print(f.__doc__)

# 移除事件
evn.removeListener(Event(GroupMessage,fun3))

# 再次觸發事件 就只會觸發一次了
evn.trigger(GroupMessage, 'arg1', 'arg2')


最後輸出
group message arg1 arg2
member message arg1 arg2
group message arg1 arg2
group message again arg1 arg2
fun3
方法三
group message arg1 arg2

相關文章