Twisted中的putChild和getChild
2016-03-05 21:03
441 查看
Twisted的官方文档上对于putChild的解释是“Register a static child”(点击打开链接),即为当前资源节点注册一个静态子资源节点。实际上,Resource类中的putChild实现的是IResource接口中的putChild方法(点击打开链接)。
Resource类中还有一个getChild方法,官方文档的解释是“Retrieve a 'child' resource from me. Implement this to create dynamic resource generation -- resources which are always available may be registered with self.putChild()”(点击打开链接)。这两句话说明getChild的作用是从当前资源节点获取子资源节点。但是,与putChild不同,getChild方法能够创建动态资源。
理解putChild和getChild的关键在于理解“静态资源”和“动态资源”两个概念。下面先看一个书上(Twisted Network Programming Essentials)的例子:
假设上面代码在本地运行,如果我们访问localhost:8000,CalendarHome的实例root的getChild会被调用,此时传给getChild的name实参为“”,getChild返回实例自身(self);同时,该实例调用render_GET函数渲染自己。如果访问localhost:8000/2016,此时传给getChild的name实参为"2016",这时,getChild负责新建一个YearPage实例,该实例调用render_GET函数渲染自己。如果在浏览器中打开localhost:8000/2016页面,每次刷新都将调用root的getChild函数,而每次调用都会创建一个新的YearPage实例。因此,那些像YearPage一样、访问时才被创建的资源,就是“动态资源”。
现在把上面的代码稍加改写,如下所示:
与上一段代码不同,这段代码在CalendarHome实例构造阶段就用putChild函数为该实例添加了两个子资源节点:home对应一个HomePage实例,“year”对应一个YearPage实例。如果用浏览器打开localhost:8000/year,无论反复刷新多少次,得到的都是来自同一个YearPage实例的响应。同理,用浏览器分别打开localhost:8000/year/help,localhost:8000/home和localhost:8000/home/room,反复刷新,相应的实例不会反复重新生成,响应浏览器GET请求的都是相应的父资源节点调用putChild函数时注册生成的那一个。因此,这些实例一旦被创建就会驻留在内存中,被反复使用。这就是“静态资源”的含义。
再对上面的代码中CalendarHome的构造函数稍作修改:
如上面代码所示,将HomePage实例注册在CalendarHome“根目录”下。这时就会出现一个问题:getChild函数要求当name为“”,即访问localhost:8000时,返回CalendarHome实例自身,然后调用自身的render_GET函数渲染;而putChild函数似乎要求访问localhost:8000时返回一个HomePage实例。到底听谁的?实验证明,听putChild的,即访问localhost:8000时,将调用HomePage实例的render_GET函数进行渲染。事实上,只有当某个资源节点没有被putChild函数注册生成时,getChild函数才会被调用,用于查找并返回相应的资源。
需要注意的是,此时访问localhost:8000/room会出现404错误。实际上,这是CalendarHome的getChild函数在作怪。因为getChild函数中写得清清楚楚,当name不为“”时,一律返回NoResource。如果把getChild代码删掉,再访问localhost:8000/room呢?答案依然是404。这是因为CalendarHome的getChild方法继承自Resource类,而Resource类中的getChild源码如下:
可见,如果CalendarHome不重写父类中的getChild方法,一旦CalendarHome的getChild被调用,直接返回NoResource。
Resource类中还有一个getChild方法,官方文档的解释是“Retrieve a 'child' resource from me. Implement this to create dynamic resource generation -- resources which are always available may be registered with self.putChild()”(点击打开链接)。这两句话说明getChild的作用是从当前资源节点获取子资源节点。但是,与putChild不同,getChild方法能够创建动态资源。
理解putChild和getChild的关键在于理解“静态资源”和“动态资源”两个概念。下面先看一个书上(Twisted Network Programming Essentials)的例子:
from twisted.internet import reactor from twisted.web.resource import Resource, NoResource from twisted.web.server import Site from calendar import calendar class YearPage(Resource): def __init__(self, year): Resource.__init__(self) self.year = year def render_GET(self, request): return "<html><body><pre>%s</pre></body></html>" % (calendar(self.year), ) class CalendarHome(Resource): def getChild(self, name, request): if name == "": return self if name.isdigit(): return YearPage(int(name)) else: return NoResource() def render_GET(self, request): return "<html><body>Welcome to the calendar server!</body></html>" root = CalendarHome() factory = Site(root) reactor.listenTCP(8000, factory) reactor.run()
假设上面代码在本地运行,如果我们访问localhost:8000,CalendarHome的实例root的getChild会被调用,此时传给getChild的name实参为“”,getChild返回实例自身(self);同时,该实例调用render_GET函数渲染自己。如果访问localhost:8000/2016,此时传给getChild的name实参为"2016",这时,getChild负责新建一个YearPage实例,该实例调用render_GET函数渲染自己。如果在浏览器中打开localhost:8000/2016页面,每次刷新都将调用root的getChild函数,而每次调用都会创建一个新的YearPage实例。因此,那些像YearPage一样、访问时才被创建的资源,就是“动态资源”。
现在把上面的代码稍加改写,如下所示:
from twisted.internet import reactor from twisted.web.resource import Resource, NoResource from twisted.web.server import Site from calendar import calendar class HelpPage(Resource): isLeaf = True def render_GET(self, request): return "<html><body>help</body></html>" class YearPage(Resource): def __init__(self, year): Resource.__init__(self) self.year = year self.putChild("help", HelpPage()) def render_GET(self, request): return "<html><body><pre>%s</pre></body></html>" % (calendar(self.year), ) class RoomPage(Resource): isLeaf = True def render_GET(self, request): return "<html><body>room</body></html>" class HomePage(Resource): def __init__(self): Resource.__init__(self) self.putChild("room", RoomPage()) def render_GET(self, request): return "<html><body>home</body></html>" class CalendarHome(Resource): def __init__(self): Resource.__init__(self) self.putChild("home", HomePage()) self.putChild("year", YearPage(2016)) def getChild(self, name, request): if name == "": return self return NoResource() def render_GET(self, request): return "<html><body>Welcome to the calendar server!</body></html>" root = CalendarHome() factory = Site(root) reactor.listenTCP(8000, factory) reactor.run()
与上一段代码不同,这段代码在CalendarHome实例构造阶段就用putChild函数为该实例添加了两个子资源节点:home对应一个HomePage实例,“year”对应一个YearPage实例。如果用浏览器打开localhost:8000/year,无论反复刷新多少次,得到的都是来自同一个YearPage实例的响应。同理,用浏览器分别打开localhost:8000/year/help,localhost:8000/home和localhost:8000/home/room,反复刷新,相应的实例不会反复重新生成,响应浏览器GET请求的都是相应的父资源节点调用putChild函数时注册生成的那一个。因此,这些实例一旦被创建就会驻留在内存中,被反复使用。这就是“静态资源”的含义。
再对上面的代码中CalendarHome的构造函数稍作修改:
class CalendarHome(Resource): def __init__(self): Resource.__init__(self) self.putChild("", HomePage()) self.putChild("year", YearPage(2016)) def getChild(self, name, request): if name == "": return self return NoResource() def render_GET(self, request): return "<html><body>Welcome to the calendar server!</body></html>"
如上面代码所示,将HomePage实例注册在CalendarHome“根目录”下。这时就会出现一个问题:getChild函数要求当name为“”,即访问localhost:8000时,返回CalendarHome实例自身,然后调用自身的render_GET函数渲染;而putChild函数似乎要求访问localhost:8000时返回一个HomePage实例。到底听谁的?实验证明,听putChild的,即访问localhost:8000时,将调用HomePage实例的render_GET函数进行渲染。事实上,只有当某个资源节点没有被putChild函数注册生成时,getChild函数才会被调用,用于查找并返回相应的资源。
需要注意的是,此时访问localhost:8000/room会出现404错误。实际上,这是CalendarHome的getChild函数在作怪。因为getChild函数中写得清清楚楚,当name不为“”时,一律返回NoResource。如果把getChild代码删掉,再访问localhost:8000/room呢?答案依然是404。这是因为CalendarHome的getChild方法继承自Resource类,而Resource类中的getChild源码如下:
161 def getChild(self, path, request): 162 """ 163 Retrieve a 'child' resource from me. 164 165 Implement this to create dynamic resource generation -- resources which 166 are always available may be registered with self.putChild(). 167 168 This will not be called if the class-level variable 'isLeaf' is set in 169 your subclass; instead, the 'postpath' attribute of the request will be 170 left as a list of the remaining path elements. 171 172 For example, the URL /foo/bar/baz will normally be:: 173 174 | site.resource.getChild('foo').getChild('bar').getChild('baz'). 175 176 However, if the resource returned by 'bar' has isLeaf set to true, then 177 the getChild call will never be made on it. 178 179 Parameters and return value have the same meaning and requirements as 180 those defined by L{IResource.getChildWithDefault}. 181 """ 182 return NoResource("No such child resource.")
可见,如果CalendarHome不重写父类中的getChild方法,一旦CalendarHome的getChild被调用,直接返回NoResource。
相关文章推荐
- Python动态类型的学习---引用的理解
- Python3写爬虫(四)多线程实现数据爬取
- 垃圾邮件过滤器 python简单实现
- 下载并遍历 names.txt 文件,输出长度最长的回文人名。
- install and upgrade scrapy
- Scrapy的架构介绍
- Centos6 编译安装Python
- 使用Python生成Excel格式的图片
- 让Python文件也可以当bat文件运行
- [Python]推算数独
- Python中zip()函数用法举例
- Python中map()函数浅析
- Python将excel导入到mysql中
- Python在CAM软件Genesis2000中的应用
- 使用Shiboken为C++和Qt库创建Python绑定
- FREEBASIC 编译可被python调用的dll函数示例