pitón programación básica: marco de análisis de Tornado profundidad de Python motor incorporado de la plantilla

motor de plantillas marco de desarrollo web es responsable de la visualización de las teclas de front-end, aquí llegamos a ejemplos de profundidad en el marco analítico del tornado de Python incorporada motor de plantillas para aprender cómo escribir una plantilla Tonardo.
plantilla método _Parse es la gramática de análisis de la plantilla , mientras que este documento cocinero cocinar varios nodo y el bloque, es decir, los resultados del análisis portadores, lo que significa que después de análisis sintáctico posterior tratamiento, que entramos en el tornado html plantilla se convierte en una colección de varios bloques.
Estos padres de bloque y de nodo es esta categoría "abstracto", _Node, que define define tres métodos, el método debe ser proporcionada implementado por una subclase (I llamo categoría "abstracto") que generan.
En teoría, cuando se convierte en una clase de padres de clase, debe significar que esta clase contiene un comportamiento común en la subclase, entonces el método _Node expuesta desde el punto de vista de que todas las subclases se teóricamente tienen el siguiente características:

  1. Puede ser utilizado como un contenedor (each_child, find_named_blocks)
  2. generar
    Por supuesto, lo ideal es siempre lleno, la realidad también siempre hay algo mal, para algunos niños y nietos, sus características no parecen tan complicado, como _TEXT.
    _TEXT generar esta clase utiliza este método sólo para el texto (HTML, JS) después del ajuste añade a la corriente de entrada, si lo llamas each_child o find_named_blocks, por supuesto, puede hacerlo, pero no tiene sentido.
    Hablando método anterior repetidamente _Parse, devuelve los resultados de un ejemplo _ChunkList, y la herencia y _ChunkList _Node. Esta es una manifestación de las características de la clase de contenedor _Node reemplaza el método y el método de generar each_child, y el método es seguido básicamente todos los elementos relevantes dentro de sólo las llamadas de contenedores.
    _Nodes muchos hijos y nietos de la más maravillosa es _ExtendsBlock esta clase, el tipo no hace nada (Eso es cierto), se parece a otra "clase abstracta", sino que en realidad se inicializan a _Parse mango se extiende este token (terminología tornado). Me pregunto, una vez que estos productos son generar, no lanzar una excepción fuera de la madera?
    También es interesante el número real de métodos, tienen un patrón común, con _ApplyBlock ejemplifica
    en _ApplyBlock, el método es interesante para generar
def generate(self, writer): 
  method_name = "apply%d" % writer.apply_counter 
  writer.apply_counter += 1
  writer.write_line("def %s():" % method_name, self.line) 
  with writer.indent(): 
    writer.write_line("_buffer = []", self.line) 
    writer.write_line("_append = _buffer.append", self.line) 
    self.body.generate(writer) 
    writer.write_line("return _utf8('').join(_buffer)", self.line) 
  writer.write_line("_append(%s(%s()))" % ( 
    self.method, method_name), self.line) 

En términos simples, esta función hace dos cosas:
definir una función llamada de archivos global pitón applyXXX ():, donde XXX es un número entero, el valor de incremento, el valor de retorno es una cadena UTF-8.
ApplyXXX realizar esta función, la salida a continuación, como una función de esta entrada self.método esta función.
Por lo tanto, si una de estas plantillas son similares

{%apply linkify%} {{address}} {%end%} 

Será similar al siguiente resultado:

r = applyXXX() 
r = linkify(r) 
_append(r) 

mecanismo de plantillas de tornado, en esencia, es permitir que los desarrolladores tienen HTML + plantilla de manera marcador para escribir la plantilla de vista, pero detrás, tornado ver estas plantillas mediante el procesamiento de la plantilla en el código Python puede ser compilado.
Tome el código anterior forma en alta mar otoño de ejemplo, relativamente fácil de entender:
Ver Plantilla

<html> 
  <head> 
    <title>{{ title }}</title> 
  </head> 
  <body> 
    hello! {{ name }} 
  </body> 
</html>

Después del tratamiento _

buffer = [] 
_buffer.append('<html>\\n<head>\\n<title>') 
  
_tmp = title 
if isinstance(_tmp, str): _buffer.append(_tmp) 
elif isinstance(_tmp, unicode): _buffer.append(_tmp.encode('utf-8')) 
else: _buffer.append(str(_tmp)) 
  
_buffer.append('</title>\\n</head>\\n<body>\\n') 
_buffer.append('hello! ') 
  
_tmp = name 
if isinstance(_tmp, str): _buffer.append(_tmp) 
elif isinstance(_tmp, unicode): _buffer.append(_tmp.encode('utf-8')) 
else: _buffer.append(str(_tmp)) 
  
_buffer.append('\\n</body>\\n</html>\\n') 
return ''.join(_buffer)\n" 

Análisis de casos
plantilla tornado básicamente en template.py este documento, a más de 800 líneas de código para lograr la plantilla básica disponible, por lo que descubrimos poco a poco su rostro.
En primer lugar, vamos a ver cómo compilar tornado plantilla, aquí hay una simple plantilla

t = Template("""\ 
{%if names%} 
  {% for name in names %} 
    {{name}} 
  {%end%} 
{%else%} 
no one 
{%end%} 
""") 

El último tornado compilar el código de la siguiente manera:

 def _tt_execute(): # <string>:0 
  _tt_buffer = [] # <string>:0 
  _tt_append = _tt_buffer.append # <string>:0 
  if names: # <string>:1 
    _tt_append('\n  ') # <string>:2 
    for name in names: # <string>:2 
      _tt_append('\n    ') # <string>:3 
      _tt_tmp = name # <string>:3 
      if isinstance(_tt_tmp, _tt_string_types): _tt_tmp = _tt_utf8(_tt_tmp) # <string>:3 
      else: _tt_tmp = _tt_utf8(str(_tt_tmp)) # <string>:3 
      _tt_tmp = _tt_utf8(xhtml_escape(_tt_tmp)) # <string>:3 
      _tt_append(_tt_tmp) # <string>:3 
      _tt_append('\n  ') # <string>:4 
      pass # <string>:2 
    _tt_append('\n') # <string>:5 
    pass # <string>:5 
  else: # <string>:5 
    _tt_append('\nno one\n') # <string>:7 
    pass # <string>:1 
  _tt_append('\n') # <string>:8 
  return _tt_utf8('').join(_tt_buffer) # <string>:0 

Sí, has leído bien, tornado compilador es traducirlo en un bloque de código, que finalmente pasó a través exec para ejecutar _tt_execute función de los parámetros de espacio de nombres.
Contiene cuatro Nodo Nodo predefinido, _ControlBlock, _expression, _TEXT, cada nodo nodo tiene su propio camino en nuestras plantillas de generación.
Por ejemplo nodo de expresión de expresión de la época, que es nuestra plantilla {{nombre}}, encontrado que cuando el análisis _parse '{' seguido o '{' que es el nodo de expresión,

class _Expression(_Node): 
  def __init__(self, expression, line, raw=False): 
    self.expression = expression 
    self.line = line 
    self.raw = raw 
  
  def generate(self, writer): 
    writer.write_line("_tt_tmp = %s" % self.expression, self.line) 
    writer.write_line("if isinstance(_tt_tmp, _tt_string_types):"
             " _tt_tmp = _tt_utf8(_tt_tmp)", self.line) 
    writer.write_line("else: _tt_tmp = _tt_utf8(str(_tt_tmp))", self.line) 
    if not self.raw and writer.current_template.autoescape is not None: 
      # In python3 functions like xhtml_escape return unicode, 
      # so we have to convert to utf8 again. 
      writer.write_line("_tt_tmp = _tt_utf8(%s(_tt_tmp))" %
               writer.current_template.autoescape, self.line) 
    writer.write_line("_tt_append(_tt_tmp)", self.line) 

Será llamado cuando los métodos de última generación generan nodos, self.expression está por encima de nombre, por lo que cuando Exec cuando se anexará el valor de nombre a la lista de los internos.
Al igual que si, para, etc., son nodos de control, que se definen como sigue:

 class _ControlBlock(_Node): 
  def __init__(self, statement, line, body=None): 
    self.statement = statement 
    self.line = line 
    self.body = body 
  
  def each_child(self): 
    return (self.body,) 
  
  def generate(self, writer): 
    writer.write_line("%s:" % self.statement, self.line) 
    with writer.indent(): 
      self.body.generate(writer) 
      # Just in case the body was empty 
      writer.write_line("pass", self.line)

El método de nodo de control genera un poco de sentido, ya que si, por y también lo es la línea siguiente se sangra requerido, por lo que la llamada continúe con writer.indent control de sangría, puede mirar
método guión del _CodeWriter.
Nodo más interesante es _ExtendsBlock, que es un nodo basado en objetivos,

class _ExtendsBlock(_Node): 
  def __init__(self, name): 
    self.name = name 

Hemos encontrado que el método no define generar, heredó cuando se genera no está siendo dado que nodo? Echemos un vistazo a algunos ejemplos

loader = Loader('.') 
t=Template("""\ 
{% extends base.html %} 
{% block login_name %}hello world! {{ name }}{% end %} 
""",loader=loader) 

Base.html directorio actual de la siguiente manera:

<html>  
<head>  
<title>{{ title }}</title>  
</head>  
<body>  
{% block login_name %}hello! {{ name }}{% end %}  
</body>  
</html>

Podemos ver nodo analiza, Aquí Insertar imagen Descripción
porque hemos heredado base.html, por lo que debemos base.html generador de plantilla, y utilizar el bloque que acaba de definir en el bloque en lugar de base.html,
esta es la idea de lo normal, tornado de hecho es tan seco, pero no procesada en _ExtendsBlock.
Y es _generate_python en la plantilla

def _generate_python(self, loader, compress_whitespace): 
   buffer = StringIO() 
   try: 
     # named_blocks maps from names to _NamedBlock objects 
     named_blocks = {} 
     ancestors = self._get_ancestors(loader) 
     ancestors.reverse() 
     for ancestor in ancestors: 
       ancestor.find_named_blocks(loader, named_blocks) 
     writer = _CodeWriter(buffer, named_blocks, loader, ancestors[0].template, 
               compress_whitespace) 
     ancestors[0].generate(writer) 
     return buffer.getvalue() 
   finally: 
     buffer.close() 
  
 def _get_ancestors(self, loader): 
   ancestors = [self.file] 
   for chunk in self.file.body.chunks: 
     if isinstance(chunk, _ExtendsBlock): 
       if not loader: 
         raise ParseError("{% extends %} block found, but no "
                 "template loader") 
       template = loader.load(chunk.name, self.name) 
       ancestors.extend(template._get_ancestors(loader)) 
   return ancestors 

llamar _generate_python en _get_ancestors hacer que la plantilla actual plantilla padre, para ver si tenemos _ExtendsBlock plantilla nodo _FILE actual tiene un padre en nombre de la plantilla padre y cargar la plantilla por loader.load, cuando la plantilla padre ya se analiza _ PRESENTAR el nodo. Así, en la plantilla de encima, son antepasados [actual nodo de plantilla _FILE, el padre del nodo plantilla _FILE], ancestors.reverse (después) de hecho antepasados [0] es la plantilla padre, que finalmente están viendo a través de los antepasados [0]. generar (escritor) para generar el código. Así es como la plantilla actual para reemplazar el contenido de la plantilla padre bloquearlo?
La figura de fantasía, login_name bloque en _generate_python se sustituye por el ancestor.find_named_blocks llamando resuelto _NamedBlock,
plantilla padre _NamedBlock.

for ancestor in ancestors:
    ancestor.find_named_blocks(loader, named_blocks)
ancestor其实就是_FILE节点,find_named_blocks将遍历_FILE节点中所有节点并调用find_named_blocks
  
class _NamedBlock(_Node): 
  def find_named_blocks(self, loader, named_blocks): 
    named_blocks[self.name] = self
    _Node.find_named_blocks(self, loader, named_blocks) 

Find_named_blocks no hacer nada otros nodos, _NamedBlock por named_blocks [self.name] = auto _NamedBlock reemplazado con la plantilla actual, antepasados porque la plantilla padre primero, después de la plantilla actual, el uso final de la plantilla _NamedBlock actual.
Después de generar el código generará espacio de nombres de código exec dada

def generate(self, **kwargs): 
  """Generate this template with the given arguments."""
  namespace = { 
    "escape": escape.xhtml_escape, 
    "xhtml_escape": escape.xhtml_escape, 
    "url_escape": escape.url_escape, 
    "json_encode": escape.json_encode, 
    "squeeze": escape.squeeze, 
    "linkify": escape.linkify, 
    "datetime": datetime, 
    "_tt_utf8": escape.utf8, # for internal use 
    "_tt_string_types": (unicode_type, bytes_type), 
    # __name__ and __loader__ allow the traceback mechanism to find 
    # the generated source code. 
    "__name__": self.name.replace('.', '_'), 
    "__loader__": ObjectDict(get_source=lambda name: self.code), 
  } 
  namespace.update(self.namespace) 
  namespace.update(kwargs) 
  exec_in(self.compiled, namespace) 
  execute = namespace["_tt_execute"] 
  # Clear the traceback module's cache of source data now that 
  # we've generated a new template (mainly for this module's 
  # unittests, where different tests reuse the same name). 
  linecache.clearcache() 
  return execute() 

Datetime se puede utilizar en la plantilla, se inyectan a través de la plantilla donde, por supuesto, hay otros por
web.py inyectado en get_template_namespace

 def get_template_namespace(self): 
  """Returns a dictionary to be used as the default template namespace. 
 
  May be overridden by subclasses to add or modify values. 
 
  The results of this method will be combined with additional 
  defaults in the `tornado.template` module and keyword arguments 
  to `render` or `render_string`. 
  """
  namespace = dict( 
    handler=self, 
    request=self.request, 
    current_user=self.current_user, 
    locale=self.locale, 
    _=self.locale.translate, 
    static_url=self.static_url, 
    xsrf_form_html=self.xsrf_form_html, 
    reverse_url=self.reverse_url 
  ) 
  namespace.update(self.ui) 
  return namespace 

Vamos a ver cómo la ayuda de la plantilla de tornado para el módulo de interfaz de usuario.

{% for entry in entries %} 
 {% module Entry(entry) %} 
{% end %}

Cuando se utiliza el módulo de nodo generará _Module

class _Module(_Expression): 
  def __init__(self, expression, line): 
    super(_Module, self).__init__("_tt_modules." + expression, line, 
                   raw=True) 

De hecho, vemos nodo _Module se hereda de nodo _expression, la ejecución final es _tt_modules.Entry (entrada)
_tt_modules RequestHandler define en el web.py

self.ui["_tt_modules"] = _UIModuleNamespace(self,application.ui_modules)

Y se inyecta en la plantilla por el get_template_namespace anteriormente.

class _UIModuleNamespace(object): 
  """Lazy namespace which creates UIModule proxies bound to a handler."""
  def __init__(self, handler, ui_modules): 
    self.handler = handler 
    self.ui_modules = ui_modules 
  
  def __getitem__(self, key): 
    return self.handler._ui_module(key, self.ui_modules[key]) 
  
  def __getattr__(self, key): 
    try: 
      return self[key] 
    except KeyError as e: 
      raise AttributeError(str(e)) 

Así que cuando se realiza _tt_modules.Entry (entrada) para el acceso de _UIModuleNamespace __getattr__, después de visitar __getitem__, la última llamada
handler._ui_module (clave, self.ui_modules [clave] ),

def _ui_module(self, name, module): 
  def render(*args, **kwargs): 
    if not hasattr(self, "_active_modules"): 
      self._active_modules = {} 
    if name not in self._active_modules: 
      self._active_modules[name] = module(self) 
    rendered = self._active_modules[name].render(*args, **kwargs) 
    return rendered 
  return render 

_tt_modules.Entry (entrada) en el interior de la entrada será pasado para hacer _ui_module, es decir, entrada = args
self._active_modules [Nombre] = Module1 (Self) en este momento es, después de la UIModule instanciación, llamadas para hacer que el contenido representado adquirió

class Entry(tornado.web.UIModule): 
  def render(self, entry, show_comments=False): 
    return self.render_string( 
      "module-entry.html", entry=entry, show_comments=show_comments)

Por supuesto, si lo hace sentir que problemas, también puede utilizar el tornado viene TemplateModule, que hereda de UIModule,
se puede utilizar de manera

{% module Template("module-entry.html", show_comments=True) %} 

Puede hacer referencia a los archivos estáticos requeridos por los set_resources en module_entry.html

{{ set_resources(embedded_css=".entry { margin-bottom: 1em; }") }} 

Debe tenerse en cuenta que: la función set_resources sólo se puede utilizar en el archivo html plantilla citado como set_resources es una función interna de TemplateModule.render

 class TemplateModule(UIModule): 
  """UIModule that simply renders the given template. 
  
  {% module Template("foo.html") %} is similar to {% include "foo.html" %}, 
  but the module version gets its own namespace (with kwargs passed to 
  Template()) instead of inheriting the outer template's namespace. 
  
  Templates rendered through this module also get access to UIModule's 
  automatic javascript/css features. Simply call set_resources 
  inside the template and give it keyword arguments corresponding to 
  the methods on UIModule: {{ set_resources(js_files=static_url("my.js")) }} 
  Note that these resources are output once per template file, not once 
  per instantiation of the template, so they must not depend on 
  any arguments to the template. 
  """
  def __init__(self, handler): 
    super(TemplateModule, self).__init__(handler) 
    # keep resources in both a list and a dict to preserve order 
    self._resource_list = [] 
    self._resource_dict = {} 
  
  def render(self, path, **kwargs): 
    def set_resources(**kwargs): 
      if path not in self._resource_dict: 
        self._resource_list.append(kwargs) 
        self._resource_dict[path] = kwargs 
      else: 
        if self._resource_dict[path] != kwargs: 
          raise ValueError("set_resources called with different "
                   "resources for the same template") 
      return "" 
    return self.render_string(path, set_resources=set_resources, 
                 **kwargs)

Por último, se recomienda una muy amplia recolección de recursos de aprendizaje pitón, [haga clic para entrar] , he aquí mi colección antes de la experiencia de aprendizaje, el aprendizaje de la pluma

Recuerde, hay un rayo de experiencia corporativa, y se calmó a cero sobre la base de los datos reales del proyecto, podemos también por debajo del mensaje, no el

Comprender propuesta, vamos a estudiar juntos el progreso

Publicado 60 artículos originales · ganado elogios 25 · Vistas a 80000 +

Supongo que te gusta

Origin blog.csdn.net/haoxun11/article/details/105169357
Recomendado
Clasificación