Defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

You have two classes, the subject and an observer which registers itself with the subject and receives notification callbacks when data changes in the subject.

Here are the two most important methods of a subject:

Attach(obs):
Attach an observer. Observers are notified after each step (the Update() method of the observers are called).
Detach(obs):
Remove an observer.

Furthermore, subjects have two methods used to prevent multiple calls to the observers if a complicated change (consisting of many small changes) is made to the subject:

BundleOn():
To be called before a compound change is made to the subject. Observers are not informed before the corresponding call to BundleOff().
BundleOff():
If the subject has been modified, observers are called, and further changes to the subject will cause observers to be called immediately. If calls to BundleOn/BundleOff are nested, only the outhermost call to BundleOff will cause notification of the observers.

The method making an object an observer is Update():

Update():
This function is called whenever the subject has changed.

Often observer objects have an optional argument to their constructor, called interval. interval=N specifies that only every N'th call to Update() has an effect.

Examples of attaching observers to a dynamics object is given in the section on trajectories.

The ListOfAtoms and Dynamics classes are derived from a common Subject class (ASE.Utilities.Subject.Subject). The implementation of the Subject class is quite simple:

class Subject:
    def __init__(self):
        self.observers = []
        self.bundling = 0
        self.pending_notify = False

    def Attach(self, observer):
        if observer not in self.observers:
            self.observers.append(observer)

    def Detach(self, observer):
        if observer in self.observers:
            self.observers.remove(observer)

    def Notify(self):
        if self.bundling:
            self.pending_notify = True
        else:
            for observer in self.observers:
                observer.Update()

    def BundleOn(self):
        self.bundling += 1

    def BundleOff(self):
        self.bundling -= 1
        if self.bundling < 0:
            raise ValueError

        if self.pending_notify and not self.bundling:
            self.Notify()
            self.pending_notify = False