Credit: Thanks Glyph Lefkowitz for pointing out some of the reasons people think Twisted is hard.
Note: Please treat this talk, and all alternative versions, as CC-BY:
This work is licensed under a Creative Commons Attribution 3.0 Unported License.
Alternative versions:
Twisted is easy. It makes it easy to write high-performance networking code. Yes, really easy. The reason we write papers like “Quantum electronics and Twisted” is because Twisted makes it so easy, we enjoy doing complicated things with it.
There are some things which just should not be complicated. Writing a custom protocol implementation should not be complicated. Writing a simple web interface should not be be complicated. Most importantly, writing code that exposes a set of objects through several protocols should not be complicated. How easy is it to do these things with twisted?
First, here is how to do nothing with Twisted:
from twisted.internet import reactor reactor.run()
Yes, it’s not the zero program. However, doing nothing with most other frameworks takes considerably more set-up code. But you don’t want to do nothing! You want to do something! Something like implementing a network protocol, maybe?
from twisted.internet import reactor, protocol
That’s the import line. That’s not interesting.
class Echo(protocol.Protocol): def dataReceived(self, data): self.transport.write(data)
That’s the actual code. Echo is a real network protocol, which is specified to parrot back its input.
factory = protocol.Factory() factory.protocol = Echo reactor.listenTCP(1033, factory)
Now we set up the factory, get it to listen on a network port, and…
reactor.run()
We’re done! That’s all there is to it. Maybe, instead, you want to write a web application. While Twisted supports WSGI natively, so you can use any Python web framework, maybe you just want to write your code already, dammit! No problems:
from twisted.internet import reactor from twisted.web import resource, server
Imports. Yawn.
class Resource(resource.Resource): isLeaf = True users = 0 def render_GET(self, request): self.users += 1 return "Welcome user number %d" % self.users
Ooooh, that looks interesting, doesn’t it? isLeaf means that all URLs under this resource will be rendered with the resource itself, without trying to find children. The render_GET method is called when GET HTTP requests are received, and its output is displayed. The output is actually HTML, but for brevity, and because browsers survive it, we did not add any tags.
reactor.listenTCP(1080, server.Site(Resource()))
Set-up. We’ve seen this earlier, this isn’t interesting anymore.
reactor.run()
We finish with the nothing.
But so what? You already had a way to write web services and network protocols. But Twisted allows you to have them communicate in fun ways. A good example would be a game where you want to be able to show the highscore table on the web, as the players keep playing through an application-specific protocol. Writing the whole game is beyond my scope, but here are the core ideas in Twisted that would apply:
from twisted.internet import reactor, protocol from twisted.web import resource, server
Imports…but here comes the exciting part!
class Counter(object): count = 0 def add(self, number): self.count += number
A POPO (Plain Old Python Object) if you will. This object just increments a counter. Not interesting until you do something with it…
class ByteCount(protocol.Protocol): def dataReceived(self, data): self.factory.counter.add(len(data))
…like use it in a protocol. We count the total number of bytes we get. Nothing here should look strange, by now.
class Resource(resource.Resource): isLeaf = True users = 0 counter = None def render_GET(self, request): self.users += 1 return "Received %d bytes" % self.counter.count
By now, we have seen most everything. But where does the “counter” object come from?
factory = protocol.Factory() factory.protocol = ByteCount factory.counter = Counter() resource = Resource() resource.counter = factory.counter
Object set-up. Here we create all the objects we need, wiring them up correctly.
reactor.listenTCP(1033, factory) reactor.listenTCP(1080, server.Site(resource))
Networking set-up — we’ve seen this earlier.
reactor.run()
The loop.
That’s it! That’s how easy it is to write a multiprotocol application in Twisted. Did you notice, by the way, how easy it was to count total users? Try doing it with Django sometimes, just for fun!