5

As far as I know, this is like an Observer pattern. Scenario: A Center object keeps a list (queue) of all its clients. I'm using Twisted.

  1. One of client objects changes a variable in center object OR notify the center to change the variable,
  2. and then the center object detects the change immediately;
  3. then as soon as the detection, the center object invoke some function of next object in queue
  4. After the client changed the variable, the client object will be eliminated. The center will take care of next client object. So I imagine there's no any function chain between these objects. So it's a little bit different from observer pattern. (How to address this issue? Correct me if I'm wrong.)

following code is just for demo only:

    class client():
        def change(self):
            self.center.va = 1

        def inqueue(self):
            self.center.queue.enqueue(self)

        def function(self):
            pass

    class center():
        def __init__(self):
            self.queue = None
            self.va = 0

        ####  When the self.va changes, this func will be invoked
        def whenChanged(self):
            next = self.queue.dequeue()
            next.function()
Henry
  • 2,819
  • 3
  • 18
  • 33

2 Answers2

10

Make va a property.

class Center():
    def __init__(self):
        self.queue = None
        self._va = 0

    @property
    def va(self):
        return self._va

    @va.setter
    def va(self, value):
        self._va = value
        self.whenChanged()

    def whenChanged(self):
        next = self.queue.dequeue()
        next.function()
chepner
  • 497,756
  • 71
  • 530
  • 681
  • I assume that va setter will called in first client, right? So does this solve the issue that the first client will be eliminated before this setter invocation return? – Henry Sep 27 '16 at 16:47
  • The setter is invoked immediately upon `self.center.va = 1`, before `client.change` exits, so it runs before the client goes away. – chepner Sep 27 '16 at 16:49
  • What if the client must leave while or before this invocation chain returns? – Henry Sep 27 '16 at 16:50
  • btw, i cannot sue property since I'm inheriting old style class. – Henry Sep 27 '16 at 16:51
  • You appear to have left a lot of important context out of your question. – chepner Sep 27 '16 at 16:51
  • The client is a network connection, the center is like a service. So when the connection goes out, the service seek the next connection to serve. That's basically the specific use – Henry Sep 27 '16 at 16:53
  • You can also inherit from `object` to make it a new-style class. Your question needs a lot of work before you can get a proper answer: nothing in your question inherits from anything, and there is no mention of how `center` is used that would imply it can "go away". – chepner Sep 27 '16 at 16:56
  • The center will always be there, alive. but the client will die. When the client is about to die, it wanna "notify the center that I'm going to die", then after the notification, the client dies and center will use next client in queue to serve. – Henry Sep 27 '16 at 16:59
  • The client *cannot* go away before one of its method calls exits, at least not as shown in the question. You mentioned Twisted in another comment, but make no mention of it in the question itself. – chepner Sep 27 '16 at 17:00
  • I looked at other related post, they talked about observer pattern, that's why I didn't mention twisted ---- no idea about if twisted could have an impact on this. – Henry Sep 27 '16 at 17:03
  • So the only thing I can do is polling? I don't see any fundamental solution from twisted perspective. – Henry Sep 27 '16 at 17:14
  • this should be the preferred way to the core python `__setattr__`. – stucash Apr 24 '20 at 15:27
6

Whenever a property of class is changed, setattr() function is called. You can override this by defining __setattr__(self, property, value) function in your class.

You need to make your required function call within this __ setattr__(). Below is the sample example based on your requirement:

class Centre(object):
    def __init__(self):
        self.queue = None
        self.va = 0

    def whenChanged(self):
        next = self.queue.dequeue()
        next.function()

    def __setattr__(self, key, value):
        self.key = value
        self.whenChanged()  # <-- Your function

Whenever you will attempt to change the value of any of class's property, this __settattr__ function will be called.

Moinuddin Quadri
  • 46,825
  • 13
  • 96
  • 126
  • I'm using Twisted, and it seems that I cannot use new-style class. Can I still use this? – Henry Sep 27 '16 at 16:49
  • It is the part of core Python. You can use it with any flavor of Python. Made an edit with sample code – Moinuddin Quadri Sep 27 '16 at 17:00
  • you said: " this `__settattr__` function will be called." but `__setattr__` will be called by who? – Henry Sep 27 '16 at 18:59
  • 1
    Did you checked the document linked to `__setattr__()`? Whenever a value is assigned to class's property,this function is called. For example, on doing `self.va = 9`, for assigning the value as `9`, this function is called – Moinuddin Quadri Sep 27 '16 at 19:38
  • Yes, I checked that out. So I assume that if I have this assignment: `center.va = 9` in a `client` object, then the `center` object will invoke the `__setattr__()` and there's no function invocation chain between `center` object and `client` object, right? – Henry Sep 27 '16 at 19:41
  • Yes, you are right. `setattr` of only `centre` will be executed in this case. – Moinuddin Quadri Sep 27 '16 at 19:45