在阅读this document关于线程安全的内容后,我感到文档中缺少某些内容,或者我的阅读内容或我的推理。
我们举一个简单的例子:
class HelloWorldNode(template.Node):
def render(self, context):
return "O HAI LOL"
@register.tag(name="hello_world")
def hello_world(parser, tokens):
"""
Greets the world with wide-eyed awe.
"""
return HelloWorldNode()
我理解这段代码,只要使用HelloWorldNode
标记,就构建hello_world
类的新实例。其他示例涉及将参数传递给构造函数,如下所示:
class HelloWorldNode(template.Node):
def __init__(self, message):
self.message = message
def render(self, context):
return "O HAI LOL " + message
@register.tag(name="hello_world")
def hello_world(parser, tokens):
"""
Greets the world with wide-eyed awe.
"""
message = tokens.split_contents()[1]
return HelloWorldNode(message)
因此,当执行hello_world
时,会创建一个新的HelloWorldNode实例,并且实例字典具有属性message
。此实例肯定必须仅用于呈现标记的给定实例,因为将其用于其他呈现将意味着绑定到它的数据将是不正确的。如果不是这种情况,那么参数会在标签的不同用途之间混淆。
查看文档中的其他示例,这是here的简化示例:
def do_current_time(parser, token):
tag_name, format_string = token.split_contents()
return CurrentTimeNode(format_string[1:-1])
由于这会从传递给函数的标记中获取数据,因此CurrentTimeNode可以工作的唯一方法是每次调用do_current_time
时都会实例化一个新的。
返回文档页面,其中不和之处。这是'坏'。
class CycleNode(Node):
def __init__(self, cyclevars):
self.cycle_iter = itertools.cycle(cyclevars)
def render(self, context):
return self.cycle_iter.next()
该文档说,如果使用相同标签的两个页面使用相同的节点可能会遇到竞争条件。 我不明白如果两个模板的渲染都可以独立实例化它们,那么它们最终会如何共享同一个实例。
解决这个问题的方法,说文档是这样的:
class CycleNode(Node):
def __init__(self, cyclevars):
self.cyclevars = cyclevars
def render(self, context):
if self not in context.render_context:
context.render_context[self] = itertools.cycle(self.cyclevars)
cycle_iter = context.render_context[self]
return cycle_iter.next()
这似乎用context.render_context
索引self
。其含义必须是self
用于以两种方式之一识别实例:
self
引用整个系统中该类的一个特定实例self
仅引用该类,并且为了引用该实例,需要渲染上下文如果1为真,为什么不将数据与self
相关联?
如果2为真,并且渲染上下文“与当前正在渲染的模板的上下文相关联”,如何在同一页面上区分模板标记的两个实例?
每次调用标记时,Node都会单独实例化吗?如果是这样,为什么并发问题呢?如果没有,为什么不呢?
答案 0 :(得分:0)
仔细阅读this。
模板在加载时编译。传递给标记函数的任何参数都是“静态”。它们是文字字符串,或者是用作标识符的字符串,用于在渲染上下文中查找绑定变量。
因此Node对象被实例化为每个标记,并且只要使用模板就可以随时使用(当然,模板可以在任意数量的线程中使用)。
因此,我的问题中的self
是模板中特定节点的标识。结合渲染上下文,它提供了一个挂起实例变量的唯一标识。