简体   繁体   中英

Can Twisted Python interface instance not implementing all functions of that interface?

As I am going through the example in this blog , I found that when ClientFactory instance, which is an argument to PoetryClientFactory, or Protocol instance, which is an argument to PoetryProtocol, is not implementing all the functions defined for ClientFactory or Protocol interface. ClientFactory interface implements startedConnecting, clientConnectionFailed, and clientConnectionLost, but PoetryClientFactory does not implement startedConnecting and clientConnectionLost. What is happening?

# This is the Twisted Get Poetry Now! client, version 2.0.

# NOTE: This should not be used as the basis for production code.

import datetime, optparse

from twisted.internet.protocol import Protocol, ClientFactory


def parse_args():
    usage = """usage: %prog [options] [hostname]:port ...

This is the Get Poetry Now! client, Twisted version 2.0.
Run it like this:

  python get-poetry.py port1 port2 port3 ...

If you are in the base directory of the twisted-intro package,
you could run it like this:

  python twisted-client-2/get-poetry.py 10001 10002 10003

to grab poetry from servers on ports 10001, 10002, and 10003.

Of course, there need to be servers listening on those ports
for that to work.
"""

    parser = optparse.OptionParser(usage)

    _, addresses = parser.parse_args()

    if not addresses:
        print parser.format_help()
        parser.exit()

    def parse_address(addr):
        if ':' not in addr:
            host = '127.0.0.1'
            port = addr
        else:
            host, port = addr.split(':', 1)

        if not port.isdigit():
            parser.error('Ports must be integers.')

        return host, int(port)

    return map(parse_address, addresses)


class PoetryProtocol(Protocol):

    poem = ''
    task_num = 0

    def dataReceived(self, data):
        self.poem += data
        msg = 'Task %d: got %d bytes of poetry from %s'
        print  msg % (self.task_num, len(data), self.transport.getPeer())

    def connectionLost(self, reason):
        self.poemReceived(self.poem)

    def poemReceived(self, poem):
        self.factory.poem_finished(self.task_num, poem)


class PoetryClientFactory(ClientFactory):

    task_num = 1

    protocol = PoetryProtocol # tell base class what proto to build

    def __init__(self, poetry_count):
        self.poetry_count = poetry_count
        self.poems = {} # task num -> poem

    def buildProtocol(self, address):
        proto = ClientFactory.buildProtocol(self, address)
        proto.task_num = self.task_num
        self.task_num += 1
        return proto

    def poem_finished(self, task_num=None, poem=None):
        if task_num is not None:
            self.poems[task_num] = poem

        self.poetry_count -= 1

        if self.poetry_count == 0:
            self.report()
            from twisted.internet import reactor
            reactor.stop()

    def report(self):
        for i in self.poems:
            print 'Task %d: %d bytes of poetry' % (i, len(self.poems[i]))

    def clientConnectionFailed(self, connector, reason):
        print 'Failed to connect to:', connector.getDestination()
        self.poem_finished()


def poetry_main():
    addresses = parse_args()

    start = datetime.datetime.now()

    factory = PoetryClientFactory(len(addresses))

    from twisted.internet import reactor

    for address in addresses:
        host, port = address
        reactor.connectTCP(host, port, factory)

    reactor.run()

    elapsed = datetime.datetime.now() - start

    print 'Got %d poems in %s' % (len(addresses), elapsed)


if __name__ == '__main__':
    poetry_main()

I don't think I'm quite sure what you're asking, but essentially if you don't need to act on a certain event (such as when a client starts connecting or a connection is lost), you don't need to implement that function. It's just an interface mostly. If you don't implement those functions, an empty function that does nothing is called, from ClientFactory or Protocol , or whichever class you inherit from..

If you are implementing an interface yourself, it looks like this:

from zope.interface import implementer
from twisted.internet.interfaces import IProtocol
@implementer(IProtocol)
class MyProtocol(object):
    " ... "

In this case, you do need to implement all methods, because this @implementer declaration is just saying that you intend to provide all the relevant methods.

However, the more common thing to do in Twisted is to subclass, like this:

from twisted.internet.protocol import Protocol
class MyProtocol(Protocol, object):
    " ... "

In this case, you do not need to implement all methods, because the Protocol super-class already provides implementations of all the methods on IProtocol . In general, Twisted provides a superclass that has default or empty versions of all the methods for many of the more frequently-used interfaces that Twisted application developers must implement.

I'm not quite sure what you're asking, too.

IMO, reaching github for their source code is the fastest way to learn. As you can see, there are default implementation for startedConnecting and clientConnectionLost (empty code, though).

Therefore, you just need to implement callbacks you need but not all methods defined in that interface.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM