【问题标题】:Failed module import when applying decorator应用装饰器时模块导入失败
【发布时间】:2018-07-17 07:31:52
【问题描述】:

我有一个用作装饰器的模块 - 修改我递归使用的函数。

该模块优化了tail call 以避免递归限制 - 请参阅下面的学分。

如果我将代码复制粘贴到控制台上,首先是模块,然后是修饰函数,它可以正常工作。

但是如果我导入模块,我会收到模块无法导入 sys 的错误 - 尽管我在模块的第一行中导入了它。

    Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "TailRecurseException.py", line 18, in func
    f = sys._getframe()
NameError: global name 'sys' is not defined
>>> 

我以为我以错误的方式导入模块:

我试过了

from TailRecurseException import tail_call_optimized

from TailRecurseException import *

@tail_call_optimized
def recursive_activations( ...)

但结果相同。

由于无法导入系统,我在装饰另一个功能的模块中会做错什么?


这是我的子模块:

import sys


class TailRecurseException:
  def __init__(self, args, kwargs):
    self.args = args
    self.kwargs = kwargs


def tail_call_optimized(g):
  """
  This function decorates a function with tail call
  optimization. It does this by throwing an exception
  if it is it's own grandparent, and catching such
  exceptions to fake the tail call optimization.

  This function fails if the decorated
  function recurses in a non-tail context.
  """
  def func(*args, **kwargs):
    f = sys._getframe()
    if f.f_back and f.f_back.f_back \
        and f.f_back.f_back.f_code == f.f_code:
      raise TailRecurseException(args, kwargs)
    else:
      while 1:
        try:
          return g(*args, **kwargs)
        except TailRecurseException, e:
          args = e.args
          kwargs = e.kwargs
  func.__doc__ = g.__doc__
  return func

致谢:https://mail.python.org/pipermail//python-list/2006-February/407243.html

【问题讨论】:

  • 您确定您运行的代码与您向我们展示的代码相同吗?异常表示名称 sys 不可访问,如果 import sys 行在模块顶部运行,则不会发生这种情况。确保您没有运行旧版本的代码(如果异常发生更改,则提供更新的回溯)。
  • 在 Python 2.7 和 Python 3 语法修复后都无法重现。您具体使用的是什么版本?并请给minimal reproducible example 展示问题。
  • 嗨,我确定我正在运行我向您展示的内容。可能是由于虚拟环境中的一些配置?在虚拟环境中使用 2.7 版。

标签: python decorator python-decorators sys


【解决方案1】:

如果我复制粘贴您附加到tcr.py 的子模块代码,那么就这样做

from tcr import tail_call_optimized

@tail_call_optimized
def recursive_activations(x):
    pass

一切正常。

(顺便说一句,您需要将 except TailRecurseException, e: 更改为 except TailRecurseException as e: 以符合现代 Python。)

【讨论】:

    猜你喜欢
    • 2019-05-18
    • 1970-01-01
    • 2015-05-15
    • 2019-04-28
    • 1970-01-01
    • 1970-01-01
    • 2016-01-22
    • 2017-12-26
    相关资源
    最近更新 更多