【问题标题】:How to track nested decorators depth?如何跟踪嵌套装饰器的深度?
【发布时间】:2019-11-07 04:01:32
【问题描述】:

为简化起见,我指的是 HTML 代码,尽管它有所不同。

我使用装饰器来生成这样的代码。

我必须通过缩进来格式化输出。 我认为我需要跟踪嵌套级别以适应缩进,但我不知道是否以及如何跟踪嵌套级别。 举个例子(https://www.thecodeship.com/patterns/guide-to-python-function-decorators/

def p_decorate(func):
   def func_wrapper(name):
       return "<p>{0}</p>".format(func(name))
   return func_wrapper

def strong_decorate(func):
    def func_wrapper(name):
        return "<strong>{0}</strong>".format(func(name))
    return func_wrapper

def div_decorate(func):
    def func_wrapper(name):
        return "<div>{0}</div>".format(func(name))
    return func_wrapper


get_text = div_decorate(p_decorate(strong_decorate(get_text)))

@div_decorate
@p_decorate
@strong_decorate
def get_text(name):
   return "lorem ipsum, {0} dolor sit amet".format(name)

print(get_text("John"))

# Outputs <div><p><strong>lorem ipsum, John dolor sit amet</strong></p></div>

我想使用通用算法获得,

<div>
    <p>
        <strong>lorem ipsum, John dolor sit amet</strong>
    </p>
</div>

有可能吗?以及如何?

我有一个代码,但它很长。

编辑:由于人们在这里要求提供真实示例,因此您得到了我想要获得的输出

config vdom
edit <vdom>
config router static
    edit <number>
        set dst <ip> <netmask>
        set gateway <ip>
        set device <intf>
    next
end
end

谢谢,

【问题讨论】:

  • 请显示一些代码
  • edit你的问题和一些例子来说明你的意思。为什么要跟踪嵌套级别和装饰器的外观?
  • 你试过elementtree吗? docs.python.org/3/library/xml.etree.elementtree.html,这就是你所需要的。
  • 为什么要使用装饰器?你把这个问题复杂化了
  • 那么展示一个例子,看看它们是什么样子的?那里有很多配置解析库

标签: python nested decorator nested-forms


【解决方案1】:

您可以使用递归来构建列表的嵌套列表来存储整体结构。由于您的装饰器遵循{tag}_decorate 的类似模式,因此可以使用带有__getattr__ 的类来消除为每个所需的HTML 标记创建单独的装饰器函数的需要。可以递归遍历返回的嵌套列表以生成所需的结构。 traverse 函数存储了一个计数器来跟踪缩进:

class HTML:
   def __getattr__(self, tag):
      def outer(f):
        def wrapper(name):
            return [tag, f(name)]
        return wrapper
      return outer


def traverse(d, c = 0):
   a, b = d
   if not isinstance(b, list):
      return f'{"  "*c}<{a}>{b}</{a}>'
   return f'{"  "*c}<{a}>\n{" "*(c+1)}{traverse(b, c+1)}\n{"   "*c}</{a}>'

html = HTML()

@html.div
@html.p
@html.strong
def get_text(name):
  return "lorem ipsum, {0} dolor sit amet".format(name)

print(traverse(get_text("John")))

输出:

<div>
   <p>
      <strong>lorem ipsum, John dolor sit amet</strong>
   </p>
</div>

【讨论】:

    【解决方案2】:

    感谢大家的贡献。最终我结束了这个。 egt_stack_size 取自这个答案

    How do I get the current depth of the Python interpreter stack?(第二个回答,不知道有没有直接链接)

    import sys
    TAB=" "
    def get_stack_size():
        size = 2  # current frame and caller's frame always exist
        while True:
            try:
                sys._getframe(size)
                size += 1
            except ValueError:
                return size - 1  # subtract current frame
    
    def p_decorate(func):
        def func_wrapper(name):
            ind=get_stack_size()-2
            ret = ind*TAB+"<p>\n"+ \
                  "{0}\n".format(func(name))+ \
                  ind*TAB+"</p>"
            return ret
        return func_wrapper
    
    def strong_decorate(func):
        def func_wrapper(name):
            ind=get_stack_size()-2
            ret = ind*TAB+"<strong>\n"+ \
                  "{0}\n".format(func(name))+ \
                  ind*TAB+"</strong>"
            return ret
        return func_wrapper
    
    def div_decorate(func):
        def func_wrapper(name):
            ind=get_stack_size()-2
            ret = ind*TAB+"<div>\n"+ \
                  "{0}\n".format(func(name))+ \
                  ind*TAB+"</div>"
            return ret
        return func_wrapper
    
    #get_text = div_decorate(p_decorate(strong_decorate(get_text)))
    
    @strong_decorate
    @div_decorate
    @p_decorate
    def get_text(name):
        ind=get_stack_size()-2
        return ind*TAB+"lorem ipsum, {0} dolor sit amet".format(name)
    
    print(get_text("John"))
    

    正如@brunodesthuilliers 指出的那样,我的方法可能不是最好的方法。 @Ajax1234 我担心你的对我不起作用,因为开始和结束标签不仅仅是一个单词,而是一个句子,因此我应该处理标签的名称以获得正确的“标签”,但你的标签是一个很好的练习节省了大量代码:-)

    【讨论】:

      猜你喜欢
      • 2019-01-12
      • 1970-01-01
      • 1970-01-01
      • 2016-08-01
      • 2010-10-25
      • 1970-01-01
      • 2012-02-18
      • 2015-09-23
      • 2016-06-11
      相关资源
      最近更新 更多