i was going through a post post about how observer pattern can be implemented in python . on the same post there are these comments.
1) In python you may as well just use plain functions, the ‘Observer’
class isnt really needed.
2) This is great example of what Java programmers are trying to do once
they switch to Python – they feel like Python is missing all that crap
and try to “port” it.
These comments imply that the observer pattern is not really useful in python and there exists other ways to achieve the same effect. is that true and if how can that be done?
Here is the code of observer pattern:
class Observable(object):
def __init__(self):
self.observers = []
def register(self, observer):
if not observer in self.observers:
self.observers.append(observer)
def unregister(self, observer):
if observer in self.observers:
self.observers.remove(observer)
def unregister_all(self):
if self.observers:
del self.observers[:]
def update_observers(self, *args, **kwargs):
for observer in self.observers:
observer.update(*args, **kwargs)
from abc import ABCMeta, abstractmethod
class Observer(object):
__metaclass__ = ABCMeta
@abstractmethod
def update(self, *args, **kwargs):
pass
class AmericanStockMarket(Observer):
def update(self, *args, **kwargs):
print("American stock market received: {0}\n{1}".format(args, kwargs))
class EuropeanStockMarket(Observer):
def update(self, *args, **kwargs):
print("European stock market received: {0}\n{1}".format(args, kwargs))
if __name__ == "__main__":
observable = Observable()
american_observer = AmericanStockMarket()
observable.register(american_observer)
european_observer = EuropeanStockMarket()
observable.register(european_observer)
observable.update_observers('Market Rally', something='Hello World')
解决方案
There are many different ways you can "observe" something in python. Use property descriptors, custom __setattr__, decorators...
Here is a simple example that uses first class functions:
class Foo(object):
def __init__(self):
self.observers = []
def register(self, fn):
self.observers.append(fn)
return fn #
def notify_observers(self, *args, **kwargs):
for fn in self.observers:
fn(*args, **kwargs)
You can then register any callable.
class Bar(object):
def do_something(self, *args, **kwargs):
pass # do something
foo = Foo()
bar = Bar()
foo.register(bar.do_something)
This will work properly. The call to do_something will have the correct self value. Because an object's methods are callable objects which carry a reference to the instance they are bound to.
This might help understanding how it works under the hood:
>>> bar
>>> bar.do_something
>
>>> type(bar.do_something)
>>> bar.do_something.__self__
[edit: decorator example]
You may also use the register method we defined above as a decorator, like this:
foo = Foo()
@foo.register
def do_something(*args, **kwargs):
pass # do something
For this to work, just remember that register needs to return the callable it registered.