0

How can I update an instance variable based on another instance? Is there a way to get a many-to-many dependency between objects in Python?

  • Deptest is a class which can be either ONLINE or OFFLINE, and it has a dictionary instance variable called "Dependencies" which is setup like so {"CONDITION STRING":instance.instancevariable == value}
  • S1 and S2 are instances of Deptest
  • S1 requires S2 to be ONLINE in order to be made ONLINE
  • If UP is pressed, S1's dependencies are checked. If they are met, S1 is now online.
  • If DOWN is pressed, S2's dependencies are checked. Since it has none, it is made online.

What happens: - S1's definition for S2 being online is never changed from its initial value. I'm not sure why, because it is called to be updated every cycle.

NOTE: S1 may be dependent on more than one attribute from s2, or may even be dependent on an S3, s4, basically an arbitrary number of dependencies.

This is what I've tried so far:

import pygame
from pygame.locals import *

pygame.init()

class deptest():
    def __init__(self,name):
        self.name = name
        self.status = ""
        self.dependencies = {}

    def updatestatus(self):
        if self.checkdependencies():
            self.status = "ONLINE"
        else:
            self.status = "OFFLINE"

    def checkdependencies(self):
        if self.dependencies:
            for dv in self.dependencies.values():
                dv=dv
            if not all(dv for dv in self.dependencies.values()):
                print("{}: Still waiting".format(self.name))
                for ds,dv in self.dependencies.items():
                    print("{}: {}".format(ds,dv))
                return False
            else:
                print("{}: Good to go".format(self.name))
                return True
        else:
            print("{}: Good to go".format(self.name))
            return True

s1 = deptest("s1")
s2 = deptest("s2")
s1.dependencies = {"S2 ONLINE":s2.status == "ONLINE"}

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True
        if event.type == KEYDOWN:
            if event.key == pygame.K_UP:
                print("PRESSED UP")
                if s1.checkdependencies():
                    s1.status = "ONLINE"
            if event.key == pygame.K_DOWN:
                print("PRESSED DOWN")
                if s2.checkdependencies():
                    s2.status = "ONLINE"
    for s in [s1,s2]:
        s.updatestatus()

pygame.quit()
sys.exit()

Is this a misunderstanding on my part about how classes and instances work?

EDIT: Looking around a bit, I think this might be the 'Observer' design pattern. EDIT: Or maybe 'Mediator'-- I'm not really sure.

Metalgearmaycry
  • 271
  • 1
  • 2
  • 7

2 Answers2

0

A lot of better ways to do this, but based on your answer in the comment, one way is not to use a dictionary for dependancies, but use something like a list, and have a method that populates it with the dependency, and then your checkstatus checks the active state and not the state that it was when you added it.

Add this to your class:

def __init__(self, name):
    ... ## all the other stuff
    self.dependencies = []

def add_dependency(self, dependency):
    self.dependencies.append(dependency)

and to checkdependencies:

def checkdependencies(self):
    if self.dependencies:
        if all(s.status for s in self.dependencies):
             return True
    else:
    ...

and to add the dependency:

s1 = deptest('s1')
s2 = deptest('s2')

s1.add_dependency(s2)

... ## do the same check that you are doing here. 
salparadise
  • 5,699
  • 1
  • 26
  • 32
  • Okay I can understand that. But how would this work for checking the actual value of the instance variable, or other instance variables; say s1 in my example required s2.status = "ONLINE" as well as s2.var == 3? – Metalgearmaycry Jul 16 '17 at 20:07
  • Easy `all(s.status == 'ONLINE' and s.var == 3 for s in...` – salparadise Jul 16 '17 at 20:11
  • I've edited my question to clarify: how would this work for an arbitrary number of systems and dependencies? Is there a design pattern I can use? – Metalgearmaycry Jul 16 '17 at 21:32
  • @Metalgearmaycry this will work fine for any number of dependencies, why do you think it wouldn't? – salparadise Jul 16 '17 at 23:45
  • My understanding of list comprehension may be off, but if I need s2 == "ONLINE" and s3 == 3, and I've got s1.dependencies=[s2,s3], then go to check all(s.status == 'ONLINE' and s.var === 3), the list will check s2 = "ONLINE" and s2.var == 3 (don't need it), and s3 == "ONLINE" (don't need it) and s3.var == 3. Is that right? – Metalgearmaycry Jul 17 '17 at 11:58
0

The first thing to understand is that you're not capturing some sort of reference to an expression in your dictionary... you're just capturing the current value. See if this helps to understand that point:

>>> a = "not ready"
>>> dependencies = {"a": a == "ready"}
>>> dependencies
{'a': False}
>>> a = "ready"
>>> dependencies
{'a': False}

Note that changing the value of a does not change the value in the dictionary.

There are a few ways to accomplish your goal, but I think the method that will work best for your use case is to store a function and execute it each time we want to check the value:

>>> a = "not ready"
>>> dependencies = {"a": lambda: a == "ready"}
>>> dependencies
{'a': <function <lambda> at 0x10fc0cf28>}
>>> dependencies["a"]()
False
>>> a = "ready"
>>> dependencies["a"]()
True

In your example, you would do something like this to set up the dependencies:

s1.dependencies = {"S2 ONLINE": lambda: s2.status == "ONLINE"}

And then you would need to call each function to check on the dependencies:

if not all(f() for f in self.dependencies.values()):
user94559
  • 59,196
  • 6
  • 103
  • 103