Python发布/订阅取消订阅问题

2024-04-28 07:06:12 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个出版商类的问题。我希望这个班超过3分就退订。我可以让所有这些工作,但问题是取消订阅是随机获取订阅订阅。在

class Publisher:
    def __init__(self):
        self.sub_list  = []

    def subscribe(self, subscriber):
        if subscriber in self.sub_list:
            raise ValueError("Multiple subscriptions are not allowed")
        self.sub_list.append(subscriber)

    def unsubscribe(self, subscriber):
        if subscriber not in self.sub_list:
            raise ValueError("Can only unsubscribe subscribers")
        self.sub_list.remove(subscriber)
    def publish(self, s):
        for subscriber in self.sub_list:
            subscriber(s)


if __name__ == '__main__':

    class SimpleSubscriber:
        def __init__(self, name, publisher):
            self.name = name
            self.publisher = publisher
            self.count = 0
            publisher.subscribe(self.process)
            self.count += 1
        def process(self, s):
            self.count +=1
            if self.count > 3:

                self.publisher.unsubscribe(self.publisher.sub_list[0])
            print(self, ":", s.upper())
        def __repr__(self):
            return self.name
    publisher = Publisher()
    for i in range(6): 
        newsub = SimpleSubscriber("Sub"+str(i), publisher)
        line = input("Input {}: ".format(i))
        publisher.publish(str(line))

输出为:

^{pr2}$

我希望输入5是SUB3,SUB4,SUB5。我知道问题是Publisher.publish正在尝试命中移动目标,而“取消订阅”正在从子列表中删除内容。我不知道如何创建一个不变的列表Publisher.publish叫什么?我想做self.sub_列表一本字典,但我不知道该怎么用。有更好的方法吗?在


Tags: nameinself列表ifinitdefcount
1条回答
网友
1楼 · 发布于 2024-04-28 07:06:12

你关于移动目标的想法是完全正确的,但是让我们让大家更清楚一点:

首先,我清理了一些东西并添加了一些调试输出:

class Publisher:
    def __init__(self):
        self.sub_list = []

    def subscribe(self, subscriber):
        if subscriber in self.sub_list:
            raise ValueError("Multiple subscriptions are not allowed")
        self.sub_list.append(subscriber)

    def unsubscribe(self, subscriber):
        if subscriber not in self.sub_list:
            raise ValueError("Can only unsubscribe subscribers")
        self.sub_list.remove(subscriber)

    def publish(self, s):
        for subscriber in self.sub_list:
            subscriber(s)

class Subscriber:
    def __init__(self, name, publisher):
        self.publisher = publisher
        publisher.subscribe(self.process)
        self.name = name
        self.calls = 0

    def process(self, s):
        print("  call {}".format(self.name))   # debug on call
        self.calls += 1
        if self.calls <= 3:
            print("{} call #{}: {}".format(self.name, self.calls, s.upper()))
        else:
            print("  remove {}".format(self.name))    # debug on remove
            self.publisher.unsubscribe(self.process)

if __name__ == '__main__':
    pub = Publisher()
    for i in range(6): 
        Subscriber("Sub"+str(i), pub)
        pub.publish("test" + str(i))
        print()

产生

^{pr2}$

这其实很简单,但被所有开销掩盖了:

如果您正在遍历一个列表,并且删除了当前项,则将跳过以下项。所以

    def publish(self, s):
        for subscriber in self.sub_list:
            subscriber(s)    # if subscriber deletes itself from .sub_list,
                             #  next subscriber does not get called

相反,我建议跟踪要删除的项目,并进行单独的清理过程:

class Publisher:
    def __init__(self):
        self.sub_list = []
        self.deleted = set()

 ...

    def unsubscribe(self, subscriber):
        if subscriber not in self.sub_list:
            raise ValueError("Can only unsubscribe subscribers")
        self.deleted.add(subscriber)

    def publish(self, s):
        for subscriber in self.sub_list:
            subscriber(s)
        if self.deleted:
            self.sub_list = [sub for sub in self.sub_list if sub not in self.deleted]
            self.deleted = set()

在这些更改(并删除调试输出)之后,您将获得

Sub0 call #1: TEST0

Sub0 call #2: TEST1
Sub1 call #1: TEST1

Sub0 call #3: TEST2
Sub1 call #2: TEST2
Sub2 call #1: TEST2

Sub1 call #3: TEST3
Sub2 call #2: TEST3
Sub3 call #1: TEST3

Sub2 call #3: TEST4
Sub3 call #2: TEST4
Sub4 call #1: TEST4

Sub3 call #3: TEST5
Sub4 call #2: TEST5
Sub5 call #1: TEST5

一如预期。在

相关问题 更多 >