Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/357.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Jinja中的多态宏_Python_Jinja2 - Fatal编程技术网

Python Jinja中的多态宏

Python Jinja中的多态宏,python,jinja2,Python,Jinja2,我正在寻找一种方法,使Jinja宏能够根据所传递对象的类型调用不同的实现。基本上,标准Python方法是多态的。现在,我正在使用一个类似于以下内容的丑陋解决方案: {% macro menuitem(obj) %} {% set type = obj.__class__.__name__ %} {% if type == "ImageMenuItem" %} {{ imagemenuitem(obj) }} {% elif type == "FoobarMenuItem" %

我正在寻找一种方法,使Jinja宏能够根据所传递对象的类型调用不同的实现。基本上,标准Python方法是多态的。现在,我正在使用一个类似于以下内容的丑陋解决方案:

{% macro menuitem(obj) %}
  {% set type = obj.__class__.__name__ %}
  {% if type == "ImageMenuItem" %}
    {{ imagemenuitem(obj) }}
  {% elif type == "FoobarMenuItem" %}
    {{ foobarmenuitem(obj) }}
  {% else %}
    {{ textmenuitem(obj) }}
  {% endif %}
{% endmacro %}
在纯Python中,您可以随意使用模块环境,例如,
globals()[x+'menuitem']
,这虽然不漂亮,但效果很好。我尝试过使用Jinja上下文进行类似的操作,但后者似乎不包含宏定义


有什么更好的方法可以实现我所追求的目标?

面向对象的本质:多态性

Create a presentation Layer for your objects:

class MenuPresentation:
    def present(self):
        raise NotImplementedException()

class ImageMenuPresentation(MenuPresentation):
   def present(self):
       return "magic url "

class TextMenuPresentation(MenuPresentation):
   def present(self):
      return "- text value here"
然后将只是一个问题:

{% macro menuitem(obj) %}
  {{ obj.present() }}
{% endmacro %}

我现在已经解决了我的问题,与fabrizioM的建议类似,但有一个显著的区别:由于菜单项表示可以(而且大多数情况下确实)包含HTML,我不希望直接在
present
方法中乱用HTML标记。因此,我最终用Python实现了菜单定义,用Jinja实现了菜单定义,相互递归弥补了这一差距

不同类型的菜单项由不同的子类表示:

上面引用的
macromap
是将菜单项类型映射到实现其表示的宏的dict。所有这些都在Jinja中定义:

要开始演示,模板必须调用顶层部分的
present
方法,传递宏映射以指定如何显示菜单,例如
main\u menu.present(默认映射)
。正如在
部分
宏中可以看到的那样,菜单项可以要求其子菜单项显示自己,其
present
方法将递归调用另一个Jinja宏,以此类推


必须显式地传递宏映射不是很漂亮,但它提供了一个有价值的好处:现在可以轻松地呈现菜单数据的不同表示形式,而无需触及菜单定义。例如,可以定义宏地图来呈现网站主菜单,或移动设备的变体(如果CSS不够),或XML站点地图,甚至是纯文本版本。(事实上,我们在网站菜单和站点地图案例中使用了这个系统。)

多态性确实适用于这个问题。但是,演示文稿必须包含HTML,我真的希望将其分离为Jinja模板。你的建议为我解决这个问题提供了最后的线索——非常感谢!
class MenuItem(object):
    def present(self, macromap):
        return macromap[type(self).__name__](self, macromap)

class TextLink(MenuItem):
    def __init__(self, url, text):
        self.url, self.text = url, text

class Section(MenuItem):
    def __init__(self, text, items):
        self.text, self.items = text, items

class ImageLink(MenuItem):
    ...
{% macro TextLink(l, macromap) %}
  <a class="menuitem" href="{{l.url|escape}}">
    {{ l.text|escape }}
  </a>
{% endmacro %}

{% macro Section(s, macromap) %}
  <div class="heading">{{s.text}}</div>
  <ul class="items">
    {% for item in s.items %}
      <li>{{ item.present(macromap) }}</li>
    {% endfor %}
  </ul>
{% endmacro %}

{% set default_map = {'TextLink': TextLink, 'Section': Section, ...}
main_menu = section("Main Menu", [
    section("Product Line 1", [
        TextLink("/products/...", "A product"),
        ...
    ]),
    section(...),
])