• 设计Twisted应用程序

    by{ guangboo }, published {2009-11-12}, Tag { Python / Twisted / }

    2.4 设计Twisted应用程序

    2.4.1 目标

    本文讲述好的Twisted应用是如何构造的,对Twisted初学者来说这很有用的,他们希望书写整洁,易维护的代码,这反映了良好的编程习惯。 读者会想熟悉使用Twisted来进行Deferreds异步(8页)及服务端(13页)和客户端(17页)编程。

    2.4.2 标准设计的示例: TwistedQuotes

    TwistedQuotes是一个很简单的插件,它很好的展示了Twisted的强大,它会输出很小的内核功能 ——每日报价——它能通过Twisted的支持接口来访问:网页、email、即时消息、特定的每日报价协议等。 设置项目TwistedQuotes查看《建立TwistedQuotes项目目录》(22页)。

    应用核心预览quoters.py

    from random import choice
    from zope.interface  import implements
    from TwistedQuotes import  quoteproto
    
    class StaticQuoter:
        """
        Return a static quote.
        """
        implements(quoteproto.IQuoter)
        def __init__(self, quote):
        	self.quote = quote
            
        def getQuote(self):
        	return self.quote
        
    class FortuneQuoter:
        """
        Load quotes from a fortune-format file.
        """
        implements(quoteproto.IQuoter)
        def __init__(self, filenames):
        	self.filenames = filenames
        
        def getQuote(self):
            quoteFile =  file(choice(self.filenames))
            quotes =  quoteFile.read().split('\n%\n')
            quoteFile.close()
            return choice(quotes) 
    

    此代码清单为我们展示了Twisted Quotes系统是怎么一回事,该代码没有任何与外界交流的方式,但它提供了一个简介和明确的抽象:“给我每日报价”。

    注意,此模块还没有导入任何Twisted功能!这种方式是为了系统的集成。如果你的“业务对象”没有卡在UI中,你就可以让这个模块以不同的协议、GUI、文件格式等集成那些对象。拥有这样的类就提供了相互之间分离的方式,允许彼此见单独使用。

    这种方式下,Twisted本身对你的程序逻辑的影响是微乎其微的,尽管Twisted“dot products”具有很强的交互性,他们也采用这种做法。你可以单独使用他们,因为彼此独立。他们以明确的方式通信,并且只在通信提供了一些额外的特性。因此,你可以拿twisted.enterprise和twisted.web一起使用,但两者并不彼此依赖,因为他们都围绕着Deferreds来集成(102页)。

    你的Twisted应用也应该尽量做到这种方式,有(至少)一个实现你特定功能的模块独立于任何UI代码。

    下一步,我们会需要以展示给用户的方式来想象这个抽象逻辑。我们要通过编写Twisted服务端协议来实现,它会响应连接它的客户端,给客户端发生一个报价,然后关闭连接。注意:不要太注重它的细节——90%的用户接口实现都和Twisted没有关系,有大量的文章介绍不同的实现方式。

    quoteproto.py

    from zope.interface  import Interface
    from  twisted.internet.protocol import Factory, Protocol
    
    class IQuoter(Interface):
        """
        An object that returns quotes.
        """
        def getQuote():
            """
            Return a quote.
            """
            
    class QOTD(Protocol):
        def connectionMade(self):
        	self.transport.write(self.factory.quoter.getQuote()+'\r\n')
        	self.transport.loseConnection()
    
    class  QOTDFactory(Factory):
        """
        A factory for the Quote of the Day  protocol.
        @type quoter: L{IQuoter} provider
        @ivar quoter: An object which provides  L{IQuoter} which will be used by
        the L{QOTD} protocol to get quotes to emit.
        """
        protocol = QOTD
        def __init__(self, quoter):
        	self.quoter = quoter 
    

    这是一个非常简单的Protocol实现,这里再次介绍了这个模式。Protocol基本上没有自己的逻辑,刚好可以与一个生成报价(一个Quoter)的对象和可以向TCP连接(一个Transport)传输字节的对象绑在一起。当客户端连接服务器时,QOTD实例被创建,它的connectionMade方法被调用。

    QOTDFactory的作用是指定Twisted框架如何创建可以处理连接的Protocol实例,Twisted不会实例化QOTDFactory,你要之后在Twisted插件中自己完成。

    注意:你可以在《服务端》(13页)中查阅关于Protocol和Factory更多信息。

    我们只要有了抽象——Quoter——我们就有了将其连接到网络的机制——QOTD协议——下一步要做的事情就是将功能链上的最好一环节摆在抽象和用户间。该环节允许用户选择一个Quoter并配置协议,编写该配置在《Applicatoin HOWTO》介绍(160页)。

  • 建立 Twistedquotes应用

    by{ guangboo }, published {2009-11-12}, Tag { Python / Twisted / }

    2.3 建立 TwistedQuotes应用

    2.3.1 目标.

    本文档介绍如何使用其他一些文档来建立TwistedQuotes应用,例如Twisted应用设计(24页)。

    2.3.2 建立TwistedQuotes项目目录

    为运行Twisted Quotes示例,你会需要做下面的工作:

    1. 在系统中创建TwistedQuotes目录;
    2. 将下面的文件放到TwistedQuotes目录下:
      __init__.py
      """Twisted  Quotes."""
      
      quoters.py
      from random import choice
      from zope.interface import implements
      from TwistedQuotes import quoteproto
       
      class StaticQuoter:
          """
          Return a static quote.
          """
          implements(quoteproto.IQuoter)
          def __init__(self, quote):
              self.quote = quote
              
          def getQuote(self):
              return self.quote
          
      class FortuneQuoter:
          """
          Load quotes from a fortune-format file.
          """
          implements(quoteproto.IQuoter)
          def __init__(self, filenames):
              self.filenames = filenames
          def getQuote(self):
              quoteFile = file(choice(self.filenames))
              quotes = quoteFile.read().split('\n%\n')
              quoteFile.close()
              return choice(quotes)
      
      quoteproto.py
      from zope.interface import Interface
      from twisted.internet.protocol import Factory, Protocol
       
      class IQuoter(Interface):
          """
          An object that returns quotes.
          """
          def getQuote():
          """
          Return a quote.
          """
       
      class QOTD(Protocol):
          def connectionMade(self):
              self.transport.write(self.factory.quoter.getQuote()+'\r\n')
              self.transport.loseConnection()
       
       
      class QOTDFactory(Factory):
          """
          A factory for the Quote of the Day protocol.
          @type quoter: L{IQuoter} provider
          @ivar quoter: An object which provides L{IQuoter} which will be used by
          the L{QOTD} protocol to get quotes to emit.
          """
          protocol = QOTD
          def __init__(self, quoter):
              self.quoter = quoter
      
      plugins.tml
      register("Quote of the Day TAP Builder",
               "TwistedQuotes.quotetap",
               description="""
               Example of a TAP builder module.
               """,
               type="tap",
               tapname="qotd")
      
    3. 将TwsitedQuotes目录的上一级目录添加到Python path,例如,如果TwistedQuotes目录是/tmp/TwistedQuotes,那么就将/tmp添加到Python path。在Unix下,可以使用export PYTHONPATH=/my/stuff:$PYTHONPATH,Winodws下,在系统变量PYTHONPATH前添加/my/stuff;。
    4. 在Python解释器中试着导入包:
      Python 2.1.3 (#1, Apr 20  2002, 22:45:31)
      [GCC 2.95.4 20011002  (Debian prerelease)] on linux2
      Type  "copyright", "credits" or "license" for more  information.
      >>> import  TwistedQuotes
      >>> # No  traceback means you’re fine.
      
  • Python装饰器

    by{ guangboo }, published {2009-11-09}, Tag { Python / }

    python装饰器介绍

    Python 2.2中引入的 classmethod() 和 staticmethod() 内置函数,你可以这样调用classmethod():

    class A:
        def foo(self, y):
            print y
        foo = classmethod(foo)
    

    也可以这样:

    class A:
        @classmethod
        def foo(self, y):
        	print y
    

    虽然classmethod是内置函数,但它和普通的函数没有两样,因此你也可以创建自己的函数转化逻辑,如:

    def  mydecorator(func):
    	print 'mydecorator was called.'
    	func.name = 'myfun'
    	return func
    

    该修饰器将稍微修改了原函数的逻辑:首先打印一段文字“mydecorator was called.”,然后给原函数添加了一个name属性,属性值为"myfun",之后再将函数放回,使用方法和调用结果如下:

    class A:
    	@mydecorator
    	def foo(self, y):
    		print y
    
    if __name__ ==  '__main__':
        a = A()
        a.foo(1)
    

    运行结果为:

    mydecorator was  called.
    1
    

    以上简介我们可以大致了解了python装饰器的作用。

    装饰器的调用逻辑

    如上一节的示例中我们发现,使用装饰器的时候是@mydecorator,或者是foo=mydecorator(foo),而不是@mydecorator(),或者foo=mydecorator(foo)()。显然,我们要的装饰器是个函数,而不是函数的结果。因为我们要将我们要修饰的函数foo(即老函数)传递给修饰函数mydecorator,并且修饰函数mydecorator也返回一个新函数(上一的新函数是在老函数的基础上添加了一个属性)。

    带参数装饰器

    上一节的介绍装饰器的调用过程,我们可以明白,@mydecorator是个函数,而且是个函数就可以,实际上是必须要实现__call__方法的对象就可以了。也就是说装饰器可以定义成实现了__call__方法的class也可以是其他的任何返回函数的“对象”,后者实现较复杂,但功能强大。

    实现__call__方法的class示例:

    class  mydecorator:
        def __init__(self, func):
        	self.func = func
        def __call__(self):
        	print “mydecorator was called.”
        	return self.func
    

    使用方法同前面的示例一样,因为我们可以像函数一样调用该类:mydecorator(),不同的是,该类是以被装饰的函数作为构造参数,而不是作为__call__的参数。更复杂的装饰器:

    def mydecorator(arg):
    	print “arg is ”, arg
    	def newdec(func):
    		print ‘new decorator was called.’
    		def replacedec(self):
    			print ‘replace decorator  was called.self.count=’,self.count
    			return func(self)
    		return replacedec
    	return newdec
    

    使用示例:

    class A2:
    	def __init__(self):
    		self.count = -1
        @mydecorator('yes')
    	def method(self):
    		print self.count
            
    if __name__ ==  '__main__':
    	a = A2()
    	a.method()
    

    输出结果:

    Args is yes
    new  decorator was called.
    decorator  was called. self.count=-1
    -1
    

    要注意的是replacedec函数,可以看出该函数有一个参数self,该参数就是method的self参数,即A2对象。可以进一步总结出,装饰器的调用过程,对装饰器嵌套函数的解释:首先将”yes”参数传递装饰器mydecorator,然后将被装饰的函数作为参数传递给newdec嵌套函数,然后将被装饰的函数的参数做为参数传递给下一层嵌套的函数replacedec。如图:

    多个参数的示例:

    def mydecorator(arg1, arg2):
        print "level 1 : Arg1=%s, arg2=%s" % (arg1, arg2)
        def newdec(func):
            print 'level 2 : newdec was called. the arg is func=%s' % func
            def replace(self, x, y):
                print "level 3 : replace was called. self is %s, x=%s, y=%s" % (str(self), str(x), str(y))
                return func(self, x, y)
            return replace
        return newdec
    
    class A2:
        def __init__(self):
            pass
    
        @mydecorator('Hello', 'word.')
        def method(self, x, y):
            print x, y
    
    if __name__ == '__main__':
        a = A2()
        a.method(1, 2)
    

     

    运行结果为:
    level 1 : Arg1=Hello, arg2=word.
    level 2 : newdec  was called. the arg is func=<function method at 0x04A06130>
    level 3 :  replace was called. self is <__main__.A2 instance at 0x04A05850>, x=1,  y=2
    1 2
    
  • Python开发Activex组件

    by{ guangboo }, published {2009-11-08}, Tag { Python / }

    Python强的功能就在于它无所不能。

    使用win32com模块开发window ActiveX的示例:(如果你还没有装win32com模块的话,请到http://python.net/crew/skippy/win32/Downloads.html下载)。

    # SimpleCOMServer.py
    
    class PythonUtilities:
        _public_methods_ = ['SplitString']
        _reg_progid_ = "Python.Utilities"
        _reg_clsid_ = "{A6688635-62F5-41cb-AF54-CBA84C2F0F86}"
    
        def SplitString(self, val):
            return "Hello world ", val
    
    if __name__ == '__main__':
        print "Registering COM server..."
        import win32com.server.register
        win32com.server.register.UseCommandLine(PythonUtilities)

    在console下运行:python SimpleCOMServer.py

    在HTML页面中调用该Activex组件:

    window.onload = function(){
    	var obj = new ActiveXObject("Python.Utilities");
    
    	alert(obj.SplitString("Hel"));
    }

  • Python Configparser模块

    by{ guangboo }, published {2009-10-18}, Tag { Python / }
    python

    ConfigParser – 配置文件解析

    该模块定义了ConfigParser类,该类实现了基本的配置文件的解析,配置文件提供了类似与WINDOWS下的INI文件结构。你可以使用该类编写最终用户很容易自定义的Python程序。

    警告:该库不包括值类型前缀,该前缀应用与INI语法的扩展版本—Windows Registry中。

    例如: [My Section]
    foodir: %(dir)s/whatever
    dir=frob

    将会解析“%(dir)s”为“dir”的值(这里是“frob”)。该模块包含所以需要的扩展。

    默认值可以通过他们作为字典传递给ConfigParser构造器来知道,另外还会默认传递给get()方法,它会覆盖其他所以方法。

    Class RawConfigParser([defaults])
    基本配置类,当传递defaults时,会初始化到内置字典中。该类不支持智能修复,2.3版本新特征。

    Class ConfigParser([defaults])
    继承之RawConfigParser类,实现了智能特性,为get(),items()方法添加了可选参数。Defaults中的值必须能填补“%()s”。注意__name__是内置的default;该值是section的名称,它会被defaults提供的任何值所覆盖。

    所以的用于填补的option名称都会通过optionxform()方法传递,就像其他任何option名称一样。例如,使用optionxform()的默认实现(将option名称转化成小写),“foo %(bar)s”和“foo %(BAR)s”的值相等。

    Class SafeConfigParser([defaults])
    继承至ConfigParser,实现了更多智能特征,实现更有可预见性,新的应用更偏好这个版本,如果他们不需要对python老版本的兼容性,2.3版本。

    Exception NoSectionError
    当没有发现给定section时抛出。

    Exception DuplicateSectionError
    如果add_section()方法被调用时,提供的section参数的值已经存在时抛出。

    Exception NoOptionError
    指定option不存在时抛出。

    Exception InterpolationError
    执行字符串填补时抛出的异常的基类。

    Exception InterpolationDepthError
    当填补字符串因为迭代次数超过了MAX_INTERPOLATION_DEPTH值时抛出的异常,InterpolationError的子类。

    Exception InterpolationMissingOptionError
    当option引用的值不存在时抛出,该异常为InterpolationError的子类,2.3版本新加。

    Exeption InterpolationSyntaxError
    当原文件格式没有遵守规定的语法时抛出的异常,继承至InterpolationError,2.3版本。

    Exception MissingSectionHeaderError
    尝试解析没有section头的文件时抛出。

    Exception ParsingError
    解析文件时发生错误。

    MAX_INTERPOLATION_DEPTH
    get()方法当raw参数为false时,递归的对大深度。只适用与ConfigParser类。

    RawConfigParser对象

    RawConfigParser实例的方法:

    defaults()
    返回全部示例中所以defaults。

    sections()
    返回有效的section列表,DEFAULT不包含在列表中。

    add_section(section)
    为实例添加一个section,如果给定的section名已经存在,将抛出DuplicateSectionError异常。

    has_section(section)
    判断给定的section名在配置文件中是否存在,DEFAULT section不包括。

    options(section)
    返回给定的section下的所有可用option的列表。

    has_option(section, option)
    如果section存在,并包含给定的option,返回true,放在返回false, 1.6版本新增。

    read(filenames)
    尝试解析文件列表,如果解析成功返回文件列表。如果filenames是string或Unicode string,将会按单个文件来解析。如果在filenames中的文件不能打开,该文件将被忽略。这样设计的目的是,让你能指定本地有可能是配置文件的列表(例如,当前文件夹,用户的根目录,及一些全系统目录),所以在列表中存在的配置文件都会被读取。如果文件都不存在,那么ConfigParser实例会包含空数据集。一个需要从配置文件读取初始化数据的应用程序,应该使用readfp()方法来加载所需要的文件,之后可以使用read()方法来获取任何可能的文件:

    import ConfigParser, os
    
    config = ConfigParser.ConfigParser()
    config.readfp(open('defaults.cfg'))
    config.read(['site.cfg', os.path.expanduser('~/.myapp.cfg')])
    

    2.4版本之后,返回成功解析的文件列表。

    readfp(fp[, filename])
    从文件或fp(值使用该对象的readline()方法)中的似文件类读取并解析配置数据,如果filename被省略,fp有一个name属性,该属性用于获取filename;默认是“<???>”。

    get(section, option)
    获取section下option的值。

    getint(section, option)
    强制指定section下的option的值,作为Int类型返回的方便方法。

    getfloat(section, option)
    强制section下的option值,作为float类型返回的方法方法。

    getboolean(section, option)
    强制section下的option值,作为布尔类型返回的方法方法。注意可接受的option的true值有“1”,“yes”,“true”及“on”,可接受的false值有“0”,“no”,“false”,“off”。字符串值不检测大小写,其他值会抛出ValueError异常。

    itmes(section)
    返回给定section下的所以option的(name, value)对列表。

    set(section, option, value)
    如果给定的setion存在,为option设定给定的值;否则抛出NoSectionError异常。当可能使用RawConfigParser(或者ConfigParser的参数raw为true)来在内部存储非字符串值,所以功能(包括填补和输出到文件)只能使用字符串值来归档。1.6版本新增。

    write(fileobject)
    将配置表示写入指定文件类,该表示以后可以通过调用read()来解析,1.6版本新增。

    remove_option(section, option)
    从指定section中删除指定option,如果section不存在,抛出NoSectionError异常;如果option存在,则删除,并返回True;否则返回false。1.6版本新增。

    remove_section(section)
    从配置文件中删除指定的section,如果section确实存在,返回true,否则返回false。

    optionxform(option)
    将输入文件中,或客户端代码传递的option名转化成内部结构使用的形式。默认实现返回option的小写形式;子类可能重写该方法或客户端代码可能将该方法作为实例的属性,以此来影响它的行为。将此用于str(),例如,会使option名称大小写敏感。

    ConfigParser对象

    ConfigParser类扩展了RawConfigParser的一些接口方法,添加了一些可选参数。

    get(section, option [, raw[, vars]])
    获取给定section下的option的值,所以“%”占位符在返回值中被填补,基于构造时传递的默认值,就像option,vars也被提供,除非raw参数为true。

    items(section, [, raw[, vars]])
    返回给定section下的所以option的(name, value)对列表。可选参数同get方法,2.3版本新增。

    SafeConfigParser对象

    SafeConfigParser类实现了ConfigParser相同的接口,新增如下方法:

    set(section, option, value)
    如果给定的section存在,给option赋值;否则抛出NoSectionError异常。Value值必须是字符串(str或unicode);如果不是,抛出TypeError异常,2.4版本新增。

  • Twisted指南

    by{ guangboo }, published {2009-09-17}, Tag { Python / Twisted / }

    2 指南

    2.1 服务端

    2.1.1 概述

    Twisted框架旨在构建灵活、强大的服务端,灵活性在于书写服务端程序的方式的层次性。

    本文档介绍Protocl层,该层你将进行协议的解析和处理。如果你正在实现或应用该层,那么首先要阅读如何使用Twisted编程、编写Twisted插件(143页)章节,然后在阅读该章节。该章节仅仅涉及到TCPSSLUnix socket服务端,后面会有单独的一章来介绍UDP(92)

    协议的处理类通常是twisted.internet.protocol.Protocol的子类。大多数协议处理都继承自该类或其更高级的子类。协议类对根据需要为每一个连接都示例化一个对象,然后在连接完成后销毁。Protocol没有保存持久化的配置[J1] 

    持久化配置保存在工厂类中,它通常继承至twisted.internet.protocol.Factory。默认的工厂类会在每个Protocol对象中实例化,并赋值给指向自己的factory属性。[J2] 并允许每个Protocol访问、甚至修改持久化配置。

    这为在多个不同的端口或地址能提供相同的服务很有用。这就是为什么Factory不监听连接的原因,事实上它根本对网络一无所知。了解更多请查看twisted.internet.interfaces.IReactorTCP.listenTCP,及其他IReactor*.listen* API

    该章节会解释每一步。

    2.1.2 Protocols

    如上所述,本节主要介绍辅助类和函数。Twisted协议使用异步方式处理数据,意思是说协议从不等待事件,而是一旦从网络接收到数据就会响应事件。

    简单示例如下:

    from twisted.internet.protocol import Protocol

    class Echo(Protocol):

    def dataReceived(self, data):

    self.transport.write(data)

    这是最简单的协议,它打印出所介绍到的数据,没有响应任何事件。下面是一个Protocol响应其他事件的例子:

    from twisted.internet.protocol import Protocol

    class QOTD(Protocol):

        def connectionMade(self):

    self.transport.write("An apple a day keeps the doctor away\r\n")

    self.transport.loseConnection()

    该协议一断简单的文字响应了初始连接,然后终止连接。

    ConnectionMade事件通常是设置连接对象的建立时期,就像一些初始问候语(就像上面的QOTD协议,它基于RFC865规范)。connectionLost事件发生于特定连接销毁之后。如示例:

    from twisted.internet.protocol import Protocol

    class Echo(Protocol):

    def connectionMade(self):

    self.factory.numProtocols = self.factory.numProtocols+1

    if self.factory.numProtocols > 100:

    self.transport.write("Too many connections, try later")

    self.transport.loseConnection()

    def connectionLost(self, reason):

    self.factory.numProtocols = self.factory.numProtocols-1

    def dataReceived(self, data):

    self.transport.write(data)

    这里的connectionMadeconnectionLost协助完成统计工厂内活动协议的个数。当出太多活动协议时connectionMade立即关闭连接。

    使用Protocol

    本节,介绍测试协议的简单方法。(为观察如何编写产品级的Twisted服务端,尽管,你还需要阅读编写Twisted插件章节(143页))。

    下面是前面讨论的QOTD服务端的运行。

    from twisted.internet.protocol import Protocol, Factory

    from twisted.internet import reactor

    class QOTD(Protocol):

    def connectionMade(self):

    self.transport.write("An apple a day keeps the doctor away\r\n")

    self.transport.loseConnection()

    # Next lines are magic:

    factory = Factory()

    factory.protocol = QOTD

    # 8007 is the port you want to run under. Choose something >1024

    reactor.listenTCP(8007, factory)

    reactor.run()

    不用在意最好6行代码—-不久就会在本章节学到。

    Protocol帮助

    很多协议都构建在类似低级抽象之上,最流行的网络协议以行为基础,而行通常以CR-LF组合来结束。

    然而,不少协议是混合型的——基于行的部分和原始数据部分。示例中包括HTTP/1.1和自由网络协议。

    针对这些情况,出现了一个LineReceiver协议。该协议使用两个不同的事件处理——lineReceivedrawDataReceived。默认的,只有lineReceived会对每一行各调用一次。然而,如何setRawMode被调用的话,协议将会调用rawDataReceived,直到setLineMode被调用,它才返回使用lineReceived

    使用行接收器的简单应用:

    from twisted.protocols.basic import LineReceiver

    class Answer(LineReceiver):

    answers = {’How are you?’: ’Fine’, None : "I don’t know what you mean"}

    def lineReceived(self, line):

    if self.answers.has_key(line):

    self.sendLine(self.answers[line])

    else:

    self.sendLine(self.answers[None])

    注意分隔线不是行的一部分。

    还有一些其他不太流行的辅助类,如基于netstring协议和prefixed-message-length 协议。

    状态机

    很多Twisted的协议处理都需要写状态机来记录它们的状态。这里有一下对写状态机有帮助的建议:

    l  不要写太大的状态机。宁可一次写一个处理一级抽象的状态机。

    l  使用Python的动态性,创建开放式的状态机。参见SMTP客户端代码。

    l  不要使用Protocol处理代码与特定的应用程序代码混淆。当协议不得不调用特定应用程序的代码的时,也一定要确保作为一个方法来调用。

    2.1.3 工厂

           如上所述,一般使用twisted.internet.protocol.Factory类,没有必要使用其子类。然而,有时会有协议的特定工厂配置或其他考虑。这时,有必要派生Factory的子类。

           对于简单的特定协议的工厂类实例化,简单的实例化Factory,设置给protocol属性。

    from twisted.internet.protocol import Factory

    from twisted.protocols.wire import Echo

    myFactory = Factory()

    myFactory.protocol = Echo

           如果有必要为特定的配置构造简单的工厂,那么工厂函数通常很有用:

    from twisted.internet.protocol import Factory, Protocol

    class QOTD(Protocol):

    def connectionMade(self):

    self.transport.write(self.factory. quote+’\r\n’)

    self.transport.loseConnection()

    def makeQOTDFactory(quote=None):

    factory = Factory()

    factory.protocol = QOTD

    factory.quote = quote or ’An apple a day keeps the doctor away’

    return factory

        Factory有两个方法来执行特定应用程序的构建和销毁(当Factory经常被持久化时,往往不适合在__init____del__方法中做这些工作,这往往太早或太迟)。

        允许工厂的Protocol记录指定日志文件的示例:

    from twisted.internet.protocol import Factory

    from twisted.protocols.basic import LineReceiver

    class LoggingProtocol(LineReceiver):

    def lineReceived(self, line):

    self.factory.fp.write(line+’\n’)

    class LogfileFactory(Factory):

    protocol = LoggingProtocol

    def __init__(self, fileName):

    self.file = fileName

    def startFactory(self):

    self.fp = open(self.file, ’a’)

    def stopFactory(self):

    self.fp.close()

    放在一起

    现在,你知道什么是工厂了,并想要使用配置引用服务端来运行QOTD,不是吗?没问题,代码如下:

    from twisted.internet.protocol import Factory, Protocol

    from twisted.internet import reactor

    class QOTD(Protocol):

    def connectionMade(self):

    self.transport.write(self.factory.quote+’\r\n’)

    self.transport.loseConnection()

    class QOTDFactory(Factory):

    protocol = QOTD

    def __init__(self, quote=None):

    self.quote = quote or ’An apple a day keeps the doctor away’

    reactor.listenTCP(8007, QOTDFactory("configurable quote"))

    reactor.run()

    可能不理解的就是最好两行代码。

    listenTCP是连接Factory到网络的方法。它使用了反应器的接口,可以让很多不同的循环处理网络代码,无需修改最终用户代码。如上所述,如果你想编写产品级的Twisted服务端代码,而不仅仅是20行的小程序,你会希望使用Application对象(160页)。

     


     [J1]This means that persistent configuration is not saved in the Protocol.

     [J2]then sets on it an attribute called factory which points to itself.