Package: observed
observedallows you to to sign up functions or methods to "observe"
other functions or methods:fromobservedimportobservable_function@observable_functiondefobserved_func(arg):print("observed_func:%s"%(arg,))defobserver_func(arg):print("observer_func:%s"%(arg,))observed_func.add_observer(observer_func)observed_func('banana')>>>observed_func:banana>>>observer_func:bananaYou can also register observers for bound methods:fromobservedimportobservable_methodclassFoo:def__init__(self,name):self.name=name@observable_method()defbar(self,arg):print("Object%sinvoked bar with arg='%s'"%(self.name,arg))defbaz(self,arg):print("Object%sinvoked baz with arg='%s'"%(self.name,arg))defcallback(arg):print("callback was invoked with arg='%s'"%(arg,))a=Foo('a')b=Foo('b')a.bar.add_observer(b.bar)a.bar.add_observer(b.baz)a.bar.add_observer(callback)a.bar('banana')>>>Objectainvokedbarwitharg='banana'>>>Objectbinvokedbarwitharg='banana'>>>Objectbinvokedbazwitharg='banana'>>>callbackwasinvokedwitharg='banana'You can ask that the observed object pass itself as the first argument
whenever it calls observers:fromobservedimportobservable_function@observable_functiondefobserved_func():print("observed_func: I was called")defobserver_func(observed):print("observer_func:%scalled me"%(observed.__name__,))observed_func.add_observer(observer_func,identify_observed=True)observed_func()>>>observed_func:Iwascalled>>>observer_func:observed_funccalledmeWhen observed bound methods pass themselves as the observed object, keep in
mind that you can always access the associated instance via__self__:fromobservedimportobservable_methodclassFoo:def__init__(self,name):self.name=name@observable_method()defbar(self):print("Object%sinvoked bar"%(self.name,))defcallback(observed):print("callback was invoked by='%s'"%(observed.__self__.name,))a=Foo('a')a.bar.add_observer(callback,identify_observed=True)a.bar()>>>Objectainvokedbar>>>callbackwasinvokedbyaNotable features include:A function or bound method is not kept alive just because it is
observing something else. This is because the observed object does
not keep any strong references to the observing objects. In CPython
this means that your observers are automatically detached whenever the
reference count to that observer goes to zero.The observable_method decorator can be used on methods in classes
which are unhashable types, and can be used on an arbitrary number of
methods in each class......but the descriptor which handles observable_method does not paste
any data onto the instances it manages. There is zero chance of name
collision on the observed instances.Installationobservedexists on the python package index, so you can dopip install observedto install it. Alternatively, you can
download the source distribution and in the root directory of the
distribution do$ python setup.py installNewsSee the file NEWS for the user-visible changes from previous releases.LicenseSeeLICENSE.txt.Downloadingobserved can be obtained from thepython package index ator viaGitHub.DocumentationBasic usage is illustrated at the top of this file. Further examples are
given inexample.py.Developmentobserved development is hosted on github. The current working repository
is given in the Downloading section above.Bug ReportingPlease submit bug tickets on theGitHub tracking system.