I created a variable conID in one function and I want to use it in another. Both functions are inside a class.
The problem is that in the second function the first function is called, so self.reqSecDefOptParams calls the first function. And after that conID receives it value. If I try to output condID in the second function I can't, it says its value is still None. Is there a way to first call the first function and then output the value in the same function?
The first function:
def contractDetails(self, reqId: int, contractDetails: ContractDetails):
string = str((contractDetails))
letter_list = string.split(",")
print(letter_list)
conID = letter_list[90] # the variable I need
The second function:
def start(self):
# using the variable again
self.reqSecDefOptParams(1, contract.symbol, "", "STK", conID)
Update: I get an error connecting to the socket. What can I do?
Error: 4 10167 Requested market data is not subscribed. Displaying delayed market data.
Error: 4 10090 Part of requested market data is not subscribed. Subscription-independent ticks are still active.Delayed market data is available.AAPL NASDAQ.NMS/TOP/ALL
unhandled exception in EReader thread
Traceback (most recent call last):
File "C:\Programming\TWS\source\pythonclient\ibapi\reader.py", line 34, in run
data = self.conn.recvMsg()
File "C:\Programming\TWS\source\pythonclient\ibapi\connection.py", line 99, in recvMsg
buf = self._recvAllMsg()
File "C:\Programming\TWS\source\pythonclient\ibapi\connection.py", line 119, in _recvAllMsg
buf = self.socket.recv(4096)
OSError: [WinError 10038] An operation was attempted on something that is not a socket
Process finished with exit code 0
Your last question had more information, I upvoted so I could find it but it disappeared. I will just fix up that code so you can see how it works in interaction with the API.
There are at least 2 ways to get option contracts. The first is just ask for them but don't fill out all the parameters, then contractDetails will return all matching contracts. The second is to just ask for all parameters but you won't know if all contracts are traded.
I put numbers in the code comments for an idea of how the program flow works.
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.common import TickerId, SetOfFloat, SetOfString, MarketDataTypeEnum
from ibapi.contract import Contract, ContractDetails
from ibapi.ticktype import TickType
class TestApp(EClient, EWrapper):
def __init__(self):
EClient.__init__(self, self)
self.underlyingContract = None
self.opts = []
self.optParams = ()
self.greeks = []
def error(self, reqId:TickerId, errorCode:int, errorString:str):
print("Error: ", reqId, "", errorCode, "", errorString)
def nextValidId(self, orderId):
self.start() #1
def contractDetails(self, reqId:int, contractDetails:ContractDetails, ):
if contractDetails.contract.secType == "OPT":#2,3 (2 contracts, P+C)
self.opts.append(contractDetails.contract)
if contractDetails.contract.secType == "STK":#4
self.underlyingContract = contractDetails.contract
self.reqSecDefOptParams(3,self.underlyingContract.symbol,"","STK",
self.underlyingContract.conId)#5
def contractDetailsEnd(self, reqId):
print("\ncontractDetails End\n")#3,4
def securityDefinitionOptionParameter(self, reqId:int, exchange:str,
underlyingConId:int, tradingClass:str, multiplier:str,
expirations:SetOfString, strikes:SetOfFloat):
#6
self.optParams = (exchange, underlyingConId, tradingClass, multiplier, expirations, strikes)
def securityDefinitionOptionParameterEnd(self, reqId:int):
print("SecurityDefinitionOptionParameterEnd. ReqId",reqId)
# make a contract out of params or just use contract from earlier
if len(self.opts) > 0:
self.reqMktData(4,self.opts[0],"",False,False,[])#7
def tickOptionComputation(self, reqId:TickerId, tickType:TickType,
impliedVol:float, delta:float, optPrice:float, pvDividend:float,
gamma:float, vega:float, theta:float, undPrice:float):
self.greeks.append([optPrice,delta,impliedVol,undPrice]) #8
# just stop after first callback but you could set a time or something else
# if you don't get data, the program won't end unless you ctrl-c or something
self.stop() #9
def start(self):
# get some option contracts, not all
opts = Contract()
opts.symbol = 'AAPL'
opts.secType = 'OPT'
opts.exchange = 'SMART'
opts.currency = 'USD'
opts.strike="140"
#opts.right="P" # ambiguous so as to get multiple contracts
opts.multiplier="100"
opts.lastTradeDateOrContractMonth = '20211015'
self.reqContractDetails(1, opts) #2
# get just underlying conId
underlying = Contract()
underlying.symbol = 'AAPL'
underlying.secType = 'STK'
underlying.exchange = 'SMART'
underlying.currency = 'USD'
self.reqContractDetails(2, underlying) #4
# in case you don't have data subscription
self.reqMarketDataType(MarketDataTypeEnum.DELAYED)
def stop(self):
self.disconnect() #10
app = TestApp()
app.connect("127.0.0.1", 7497, 123)
app.run() # starts a reader thread that will block until disconnect()
#11 after disconnect, program can continue
# I just do this so I can use spyder variable inspector but you could print
uc = app.underlyingContract
opts = app.opts
params = app.optParams
greeks = app.greeks
Welcome #LaForge1071! You have a few ways you can do this! One way you might do this is by passing the variable to the new function like this
def func_a():
foo = 'bar'
func_b(foo)
def func_b(var):
print(var)
func_a()
or, and I don't recommend this, you can use global scope to solve this like so,
def func_a():
global foo
foo = 'bar'
func_b()
def func_b():
print(foo)
func_a()
You said both function are in one class, so maybe declare the variable to be a class variable:
class A:
def __init__(self):
self.foo = None
def func_a(self):
self.foo = "Hello"
def func_b(self):
if self.foo is not None:
print(self.foo)
you can declare this variable in init funciton ,just like constrution function in c/c++.
def __init__(self):
self.foo = init_value
I am trying to write a class to handle signals using the signal python module. The reason for having a class is to avoid the use of globals. This is the code I came up with, but unfortunately it is not working:
import signal
import constants
class SignalHandler (object):
def __init__(self):
self.counter = 0
self.break = False
self.vmeHandlerInstalled = False
def setVmeHandler(self):
self.vmeBufferFile = open('/dev/vme_shared_memory0', 'rb')
self.vmeHandlerInstalled = True
signal.signal(signal.SIGUSR1, self.traceHandler)
signal.siginterrupt(signal.SIGUSR1, False)
#...some other stuff...
def setBreakHandler(self):
signal.signal(signal.SIGINT, self.newBreakHandler)
signal.siginterrupt(signal.SIGINT, False)
def newBreakHandler(self, signum, frame):
self.removeVMEHandler()
self.break = True
def traceHandler(self, signum, frame):
self.counter += constants.Count
def removeVMEHandler(self):
if not self.vmeHandlerInstalled: return
if self.vmeBufferFile is None: return
signal.signal(signal.SIGUSR1, signal.SIG_DFL)
self.vmeHandlerInstalled = False
On the main program I use this class in the following way:
def run():
sigHandler = SignalHandler()
sigHandler.setBreakHandler()
sigHandler.setVmeHandler()
while not sigHandler.break:
#....do some stuff
if sigHandler.counter >= constants.Count:
#...do some stuff
This solution is not working, as it appears that the handler for the signal.SIGUSR1 installed in the setVmeHandler method never gets called.
So my question is: is it possible to handle signal inside a class or shall I use globals?
To answer your question, I created the following simple code:
import signal
import time
class ABC(object):
def setup(self):
signal.signal(signal.SIGUSR1, self.catch)
signal.siginterrupt(signal.SIGUSR1, False)
def catch(self, signum, frame):
print("xxxx", self, signum, frame)
abc = ABC()
abc.setup()
time.sleep(20)
If I run it:
python ./test.py
Then in another window send a USR1 signal:
kill -USR1 4357
The process prints the expected message:
('xxxx', <__main__.ABC object at 0x7fada09c6190>, 10, <frame object at 0x7fada0aaf050>)
So I think the answer is Yes, it possible to handle signal inside a class.
As for why you code doesn't work, sorry, I have no idea.
I got a similar problem as toti08, referring to setVmeHandler(self), and found out the handler must have matching parameters i.e. (self, signum,frame).
I have a signal handler to handle ctrl-c interrupt. If in the signal handler I want to read a variable set in my main script, is there an alternative to using a "global" statement when setting the variable?
I don't mind doing this, but read this post (Do you use the "global" statement in Python?) in which someone commented that there should be no reason to ever use global.
What is the alternative in this case?
My code looks like this:
def signal_handler(signal, frame):
print "in sig handler - g_var=%s" % g_var
def main():
global g_var
g_var = "test"
time.sleep(120)
if __name__ == '__main__':
signal.signal(signal.SIGINT, signal_handler)
main()
You can use a closure as the signal handler that acquires its state from the main script:
import signal
import sys
import time
def main_function():
data_for_signal_handler = 10
def signal_handler(*args):
print data_for_signal_handler
sys.exit()
signal.signal(signal.SIGINT, signal_handler) # Or whatever signal
while True:
data_for_signal_handler += 1
time.sleep(0.5)
if __name__ == '__main__':
main_function()
You can use partial to create a "closure".
import signal
from functools import partial
def signal_handler(g_var, signal, frame):
print "in sig handler - g_var=%s" % g_var
def main():
g_var = "test"
signal.signal(signal.SIGINT, partial(signal_handler, g_var))
time.sleep(120)
if __name__ == '__main__':
main()
Within the object-oriented paradigm (OOP) it's quite convenient to use lambdas for that purpose. Using lambdas you could pass some additional context (like a self reference) and/or get rid of the unused arguments (signal, frame).
import time
import signal
class Application:
def __init__( self ):
signal.signal( signal.SIGINT, lambda signal, frame: self._signal_handler() )
self.terminated = False
def _signal_handler( self ):
self.terminated = True
def MainLoop( self ):
while not self.terminated:
print( "I'm just doing my job like everyone else" )
time.sleep( 3 )
app = Application()
app.MainLoop()
print( "The app is terminated, exiting ..." )
If you're just reading the variable, there should be no need to make the variable "global"
def foo():
print a
a = 3
foo() #3
global is necessary to allow you to change the variable and have that change propagate into the module namespace.
If you want to pass some state to your callback without using global, the typical way to do this us to use an instance method as the callback:
class foo(object):
def __init__(self,arg):
self.arg = arg
def callback_print_arg(self):
print self.arg
def call_callback(callback):
callback()
a = foo(42)
call_callback(a.callback_print_arg) #42
You can access outer-scope variables from within an inline-defined function, like so:
my_values = {'foo':'bar'}
def handler(signum, frame):
for key,val in my_values.items():
print key,val
my_values['bat']='baz'
#remember to use mutable types, like dicts or lists
signal.signal(signal.SIGINT, handler)
I'm getting segfaults when calling a dbus method inside a thread. This is my scenario: I have a program Service1 that exposes a method test. A second program Service2 exposes a method expose. As this method does some serious numerical computation, I pass some params from expose to a running thread reader. This thread, in turn, calls the method test of Service1 when it ends its work. I'm geting segfaults in last dbus call.
The code:
# Service1.py
class Service1(Object):
def __init__(self, bus):
name = BusName('com.example.Service1', bus)
path = '/'
super(Service1, self).__init__(name, path)
#method(dbus_interface='com.example.Service1',
in_signature='s', out_signature='s')
def test(self, test):
print 'test being called'
return test
dbus_loop = DBusGMainLoop()
dsession = SessionBus(mainloop=dbus_loop)
loop = gobject.MainLoop()
gobject.threads_init()
im = Service1(dsession)
loop.run()
# Service2.py
dbus_loop = DBusGMainLoop()
dsession = SessionBus(mainloop=dbus_loop)
class Service2(Object):
def __init__(self, bus):
name = BusName('com.example.Service2', bus)
super(Service2, self).__init__(name, '/')
self.queue = Queue()
self.db = bus.get_object('com.example.Service1', '/')
self.dbi = dbus.Interface(self.db, dbus_interface='com.example.Service1')
#method(dbus_interface='com.example.Service2',
in_signature='', out_signature='')
def expose(self):
print 'calling expose'
self.queue.put(('params',))
def reader(self):
while True:
val = self.queue.get()
dd = self.dbi.test('test')
print dd
self.queue.task_done()
gobject.threads_init()
loop = gobject.MainLoop()
im = Service2(dsession)
reader = threading.Thread(target=im.reader)
reader.start()
loop.run()
To test, run Service1.py, Service2.py and later this snippet:
dbus_loop = DBusGMainLoop()
session = SessionBus(mainloop=dbus_loop)
proxy = session.get_object('com.example.Service2', '/')
test_i = dbus.Interface(proxy, dbus_interface='com.example.Service2')
test_i.expose()
Service2.py should crash after running this code a few times. But why?
gobject.threads_init() is not enough, you need to call dbus.mainloop.glib.threads_init() to make dbus-glib thread safe.
In Service1.py, Try calling gobject.threads_init() before assigning dbus_loop to DBusGMainLoop().
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
Are there any exemplary examples of the GoF Observer implemented in Python? I have a bit code which currently has bits of debugging code laced through the key class (currently generating messages to stderr if a magic env is set). Additionally, the class has an interface for incrementally return results as well as storing them (in memory) for post processing. (The class itself is a job manager for concurrently executing commands on remote machines over ssh).
Currently the usage of the class looks something like:
job = SSHJobMan(hostlist, cmd)
job.start()
while not job.done():
for each in job.poll():
incrementally_process(job.results[each])
time.sleep(0.2) # or other more useful work
post_process(job.results)
An alernative usage model is:
job = SSHJobMan(hostlist, cmd)
job.wait() # implicitly performs a start()
process(job.results)
This all works fine for the current utility. However it does lack flexibility. For example I currently support a brief output format or a progress bar as incremental results, I also support
brief, complete and "merged message" outputs for the post_process() function.
However, I'd like to support multiple results/output streams (progress bar to the terminal, debugging and warnings to a log file, outputs from successful jobs to one file/directory, error messages and other results from non-successful jobs to another, etc).
This sounds like a situation that calls for Observer ... have instances of my class accept registration from other objects and call them back with specific types of events as they occur.
I'm looking at PyPubSub since I saw several references to that in SO related questions. I'm not sure I'm ready to add the external dependency to my utility but I could see value in using their interface as a model for mine if that's going to make it easier for others to use. (The project is intended as both a standalone command line utility and a class for writing other scripts/utilities).
In short I know how to do what I want ... but there are numerous ways to accomplish it. I want suggestions on what's most likely to work for other users of the code in the long run.
The code itself is at: classh.
However it does lack flexibility.
Well... actually, this looks like a good design to me if an asynchronous API is what you want. It usually is. Maybe all you need is to switch from stderr to Python's logging module, which has a sort of publish/subscribe model of its own, what with Logger.addHandler() and so on.
If you do want to support observers, my advice is to keep it simple. You really only need a few lines of code.
class Event(object):
pass
class Observable(object):
def __init__(self):
self.callbacks = []
def subscribe(self, callback):
self.callbacks.append(callback)
def fire(self, **attrs):
e = Event()
e.source = self
for k, v in attrs.items():
setattr(e, k, v)
for fn in self.callbacks:
fn(e)
Your Job class can subclass Observable. When something of interest happens, call self.fire(type="progress", percent=50) or the like.
I think people in the other answers overdo it. You can easily achieve events in Python with less than 15 lines of code.
You simple have two classes: Event and Observer. Any class that wants to listen for an event, needs to inherit Observer and set to listen (observe) for a specific event. When an Event is instantiated and fired, all observers listening to that event will run the specified callback functions.
class Observer():
_observers = []
def __init__(self):
self._observers.append(self)
self._observables = {}
def observe(self, event_name, callback):
self._observables[event_name] = callback
class Event():
def __init__(self, name, data, autofire = True):
self.name = name
self.data = data
if autofire:
self.fire()
def fire(self):
for observer in Observer._observers:
if self.name in observer._observables:
observer._observables[self.name](self.data)
Example:
class Room(Observer):
def __init__(self):
print("Room is ready.")
Observer.__init__(self) # Observer's init needs to be called
def someone_arrived(self, who):
print(who + " has arrived!")
room = Room()
room.observe('someone arrived', room.someone_arrived)
Event('someone arrived', 'Lenard')
Output:
Room is ready.
Lenard has arrived!
A few more approaches...
Example: the logging module
Maybe all you need is to switch from stderr to Python's logging module, which has a powerful publish/subscribe model.
It's easy to get started producing log records.
# producer
import logging
log = logging.getLogger("myjobs") # that's all the setup you need
class MyJob(object):
def run(self):
log.info("starting job")
n = 10
for i in range(n):
log.info("%.1f%% done" % (100.0 * i / n))
log.info("work complete")
On the consumer side there's a bit more work. Unfortunately configuring logger output takes, like, 7 whole lines of code to do. ;)
# consumer
import myjobs, sys, logging
if user_wants_log_output:
ch = logging.StreamHandler(sys.stderr)
ch.setLevel(logging.INFO)
formatter = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s - %(message)s")
ch.setFormatter(formatter)
myjobs.log.addHandler(ch)
myjobs.log.setLevel(logging.INFO)
myjobs.MyJob().run()
On the other hand there's an amazing amount of stuff in the logging package. If you ever need to send log data to a rotating set of files, an email address, and the Windows Event Log, you're covered.
Example: simplest possible observer
But you don't need to use any library at all. An extremely simple way to support observers is to call a method that does nothing.
# producer
class MyJob(object):
def on_progress(self, pct):
"""Called when progress is made. pct is the percent complete.
By default this does nothing. The user may override this method
or even just assign to it."""
pass
def run(self):
n = 10
for i in range(n):
self.on_progress(100.0 * i / n)
self.on_progress(100.0)
# consumer
import sys, myjobs
job = myjobs.MyJob()
job.on_progress = lambda pct: sys.stdout.write("%.1f%% done\n" % pct)
job.run()
Sometimes instead of writing a lambda, you can just say job.on_progress = progressBar.update, which is nice.
This is about as simple as it gets. One drawback is that it doesn't naturally support multiple listeners subscribing to the same events.
Example: C#-like events
With a bit of support code, you can get C#-like events in Python. Here's the code:
# glue code
class event(object):
def __init__(self, func):
self.__doc__ = func.__doc__
self._key = ' ' + func.__name__
def __get__(self, obj, cls):
try:
return obj.__dict__[self._key]
except KeyError, exc:
be = obj.__dict__[self._key] = boundevent()
return be
class boundevent(object):
def __init__(self):
self._fns = []
def __iadd__(self, fn):
self._fns.append(fn)
return self
def __isub__(self, fn):
self._fns.remove(fn)
return self
def __call__(self, *args, **kwargs):
for f in self._fns[:]:
f(*args, **kwargs)
The producer declares the event using a decorator:
# producer
class MyJob(object):
#event
def progress(pct):
"""Called when progress is made. pct is the percent complete."""
def run(self):
n = 10
for i in range(n+1):
self.progress(100.0 * i / n)
#consumer
import sys, myjobs
job = myjobs.MyJob()
job.progress += lambda pct: sys.stdout.write("%.1f%% done\n" % pct)
job.run()
This works exactly like the "simple observer" code above, but you can add as many listeners as you like using +=. (Unlike C#, there are no event handler types, you don't have to new EventHandler(foo.bar) when subscribing to an event, and you don't have to check for null before firing the event. Like C#, events do not squelch exceptions.)
How to choose
If logging does everything you need, use that. Otherwise do the simplest thing that works for you. The key thing to note is that you don't need to take on a big external dependency.
How about an implementation where objects aren't kept alive just because they're observing something? Below please find an implementation of the observer pattern with the following features:
Usage is pythonic. To add an observer to a bound method .bar of instance foo, just do foo.bar.addObserver(observer).
Observers are not kept alive by virtue of being observers. In other words, the observer code uses no strong references.
No sub-classing necessary (descriptors ftw).
Can be used with unhashable types.
Can be used as many times you want in a single class.
(bonus) As of today the code exists in a proper downloadable, installable package on github.
Here's the code (the github package or PyPI package have the most up to date implementation):
import weakref
import functools
class ObservableMethod(object):
"""
A proxy for a bound method which can be observed.
I behave like a bound method, but other bound methods can subscribe to be
called whenever I am called.
"""
def __init__(self, obj, func):
self.func = func
functools.update_wrapper(self, func)
self.objectWeakRef = weakref.ref(obj)
self.callbacks = {} #observing object ID -> weak ref, methodNames
def addObserver(self, boundMethod):
"""
Register a bound method to observe this ObservableMethod.
The observing method will be called whenever this ObservableMethod is
called, and with the same arguments and keyword arguments. If a
boundMethod has already been registered to as a callback, trying to add
it again does nothing. In other words, there is no way to sign up an
observer to be called back multiple times.
"""
obj = boundMethod.__self__
ID = id(obj)
if ID in self.callbacks:
s = self.callbacks[ID][1]
else:
wr = weakref.ref(obj, Cleanup(ID, self.callbacks))
s = set()
self.callbacks[ID] = (wr, s)
s.add(boundMethod.__name__)
def discardObserver(self, boundMethod):
"""
Un-register a bound method.
"""
obj = boundMethod.__self__
if id(obj) in self.callbacks:
self.callbacks[id(obj)][1].discard(boundMethod.__name__)
def __call__(self, *arg, **kw):
"""
Invoke the method which I proxy, and all of it's callbacks.
The callbacks are called with the same *args and **kw as the main
method.
"""
result = self.func(self.objectWeakRef(), *arg, **kw)
for ID in self.callbacks:
wr, methodNames = self.callbacks[ID]
obj = wr()
for methodName in methodNames:
getattr(obj, methodName)(*arg, **kw)
return result
#property
def __self__(self):
"""
Get a strong reference to the object owning this ObservableMethod
This is needed so that ObservableMethod instances can observe other
ObservableMethod instances.
"""
return self.objectWeakRef()
class ObservableMethodDescriptor(object):
def __init__(self, func):
"""
To each instance of the class using this descriptor, I associate an
ObservableMethod.
"""
self.instances = {} # Instance id -> (weak ref, Observablemethod)
self._func = func
def __get__(self, inst, cls):
if inst is None:
return self
ID = id(inst)
if ID in self.instances:
wr, om = self.instances[ID]
if not wr():
msg = "Object id %d should have been cleaned up"%(ID,)
raise RuntimeError(msg)
else:
wr = weakref.ref(inst, Cleanup(ID, self.instances))
om = ObservableMethod(inst, self._func)
self.instances[ID] = (wr, om)
return om
def __set__(self, inst, val):
raise RuntimeError("Assigning to ObservableMethod not supported")
def event(func):
return ObservableMethodDescriptor(func)
class Cleanup(object):
"""
I manage remove elements from a dict whenever I'm called.
Use me as a weakref.ref callback to remove an object's id from a dict
when that object is garbage collected.
"""
def __init__(self, key, d):
self.key = key
self.d = d
def __call__(self, wr):
del self.d[self.key]
To use this we just decorate methods we want to make observable with #event. Here's an example
class Foo(object):
def __init__(self, name):
self.name = name
#event
def bar(self):
print("%s called bar"%(self.name,))
def baz(self):
print("%s called baz"%(self.name,))
a = Foo('a')
b = Foo('b')
a.bar.addObserver(b.bar)
a.bar()
From wikipedia:
from collections import defaultdict
class Observable (defaultdict):
def __init__ (self):
defaultdict.__init__(self, object)
def emit (self, *args):
'''Pass parameters to all observers and update states.'''
for subscriber in self:
response = subscriber(*args)
self[subscriber] = response
def subscribe (self, subscriber):
'''Add a new subscriber to self.'''
self[subscriber]
def stat (self):
'''Return a tuple containing the state of each observer.'''
return tuple(self.values())
The Observable is used like this.
myObservable = Observable ()
# subscribe some inlined functions.
# myObservable[lambda x, y: x * y] would also work here.
myObservable.subscribe(lambda x, y: x * y)
myObservable.subscribe(lambda x, y: float(x) / y)
myObservable.subscribe(lambda x, y: x + y)
myObservable.subscribe(lambda x, y: x - y)
# emit parameters to each observer
myObservable.emit(6, 2)
# get updated values
myObservable.stat() # returns: (8, 3.0, 4, 12)
Based on Jason's answer, I implemented the C#-like events example as a fully-fledged python module including documentation and tests. I love fancy pythonic stuff :)
So, if you want some ready-to-use solution, you can just use the code on github.
Example: twisted log observers
To register an observer yourCallable() (a callable that accepts a dictionary) to receive all log events (in addition to any other observers):
twisted.python.log.addObserver(yourCallable)
Example: complete producer/consumer example
From Twisted-Python mailing list:
#!/usr/bin/env python
"""Serve as a sample implementation of a twisted producer/consumer
system, with a simple TCP server which asks the user how many random
integers they want, and it sends the result set back to the user, one
result per line."""
import random
from zope.interface import implements
from twisted.internet import interfaces, reactor
from twisted.internet.protocol import Factory
from twisted.protocols.basic import LineReceiver
class Producer:
"""Send back the requested number of random integers to the client."""
implements(interfaces.IPushProducer)
def __init__(self, proto, cnt):
self._proto = proto
self._goal = cnt
self._produced = 0
self._paused = False
def pauseProducing(self):
"""When we've produced data too fast, pauseProducing() will be
called (reentrantly from within resumeProducing's transport.write
method, most likely), so set a flag that causes production to pause
temporarily."""
self._paused = True
print('pausing connection from %s' % (self._proto.transport.getPeer()))
def resumeProducing(self):
self._paused = False
while not self._paused and self._produced < self._goal:
next_int = random.randint(0, 10000)
self._proto.transport.write('%d\r\n' % (next_int))
self._produced += 1
if self._produced == self._goal:
self._proto.transport.unregisterProducer()
self._proto.transport.loseConnection()
def stopProducing(self):
pass
class ServeRandom(LineReceiver):
"""Serve up random data."""
def connectionMade(self):
print('connection made from %s' % (self.transport.getPeer()))
self.transport.write('how many random integers do you want?\r\n')
def lineReceived(self, line):
cnt = int(line.strip())
producer = Producer(self, cnt)
self.transport.registerProducer(producer, True)
producer.resumeProducing()
def connectionLost(self, reason):
print('connection lost from %s' % (self.transport.getPeer()))
factory = Factory()
factory.protocol = ServeRandom
reactor.listenTCP(1234, factory)
print('listening on 1234...')
reactor.run()
OP asks "Are there any exemplary examples of the GoF Observer implemented in Python?"
This is an example in Python 3.7. This Observable class meets the requirement of creating a relationship between one observable and many observers while remaining independent of their structure.
from functools import partial
from dataclasses import dataclass, field
import sys
from typing import List, Callable
#dataclass
class Observable:
observers: List[Callable] = field(default_factory=list)
def register(self, observer: Callable):
self.observers.append(observer)
def deregister(self, observer: Callable):
self.observers.remove(observer)
def notify(self, *args, **kwargs):
for observer in self.observers:
observer(*args, **kwargs)
def usage_demo():
observable = Observable()
# Register two anonymous observers using lambda.
observable.register(
lambda *args, **kwargs: print(f'Observer 1 called with args={args}, kwargs={kwargs}'))
observable.register(
lambda *args, **kwargs: print(f'Observer 2 called with args={args}, kwargs={kwargs}'))
# Create an observer function, register it, then deregister it.
def callable_3():
print('Observer 3 NOT called.')
observable.register(callable_3)
observable.deregister(callable_3)
# Create a general purpose observer function and register four observers.
def callable_x(*args, **kwargs):
print(f'{args[0]} observer called with args={args}, kwargs={kwargs}')
for gui_field in ['Form field 4', 'Form field 5', 'Form field 6', 'Form field 7']:
observable.register(partial(callable_x, gui_field))
observable.notify('test')
if __name__ == '__main__':
sys.exit(usage_demo())
A functional approach to observer design:
def add_listener(obj, method_name, listener):
# Get any existing listeners
listener_attr = method_name + '_listeners'
listeners = getattr(obj, listener_attr, None)
# If this is the first listener, then set up the method wrapper
if not listeners:
listeners = [listener]
setattr(obj, listener_attr, listeners)
# Get the object's method
method = getattr(obj, method_name)
#wraps(method)
def method_wrapper(*args, **kwags):
method(*args, **kwags)
for l in listeners:
l(obj, *args, **kwags) # Listener also has object argument
# Replace the original method with the wrapper
setattr(obj, method_name, method_wrapper)
else:
# Event is already set up, so just add another listener
listeners.append(listener)
def remove_listener(obj, method_name, listener):
# Get any existing listeners
listener_attr = method_name + '_listeners'
listeners = getattr(obj, listener_attr, None)
if listeners:
# Remove the listener
next((listeners.pop(i)
for i, l in enumerate(listeners)
if l == listener),
None)
# If this was the last listener, then remove the method wrapper
if not listeners:
method = getattr(obj, method_name)
delattr(obj, listener_attr)
setattr(obj, method_name, method.__wrapped__)
These methods can then be used to add a listener to any class method. For example:
class MyClass(object):
def __init__(self, prop):
self.prop = prop
def some_method(self, num, string):
print('method:', num, string)
def listener_method(obj, num, string):
print('listener:', num, string, obj.prop)
my = MyClass('my_prop')
add_listener(my, 'some_method', listener_method)
my.some_method(42, 'with listener')
remove_listener(my, 'some_method', listener_method)
my.some_method(42, 'without listener')
And the output is:
method: 42 with listener
listener: 42 with listener my_prop
method: 42 without listener