【问题标题】:Missing local variable in a function factory in PythonPython中的函数工厂中缺少局部变量
【发布时间】:2017-05-31 08:07:16
【问题描述】:

我正在使用Python 3.5。我想创建一个工厂,外部函数的局部变量可以被用户 kwargs 覆盖。

这样做的时候,我发现有些变量没有明显的原因没有定义在内部范围内。

这是一个函数工厂的MWE:

def TicksFormatterFactory( \
    title=None, target='xaxis', limits=100 \
   ,major_locator=None, major_format=None, major_gridstyle=None, major_rotation=90, major_fontsize=7 \
   ,minor_locator=None, minor_format=None, minor_gridstyle=None, minor_rotation=None, minor_fontsize=None \
   ,title_kw=dict() \
):
    pprint.pprint(locals())   # (1)
    varKeys = locals().keys() # (2)
    def inner(axe, **kwargs):

        pprint.pprint(locals())   # (5)

        # Allow User to overwrite settings using kwargs:
        settings = dict()
        for k in varKeys:
            settings[k] = kwargs.get(k, locals().get(k)) # (3)

        pprint.pprint(settings) # (4)

    return inner

对工厂及其内部函数的简单调用:

test = TicksFormatterFactory(minor_fontsize=4)
fig, axe = plt.subplots()
test(axe, title='Hello world')

导致:

# (1)
{'limits': 100,
 'major_fontsize': 7,
 'major_format': None,
 'major_gridstyle': None,
 'major_locator': None,
 'major_rotation': 90,
 'minor_fontsize': 4,
 'minor_format': None,
 'minor_gridstyle': None,
 'minor_locator': None,
 'minor_rotation': None,
 'target': 'xaxis',
 'title': None,
 'title_kw': {}}

# (5)
{'axe': <matplotlib.axes._subplots.AxesSubplot object at 0x0000027793B02BE0>,
 'kwargs': {'title': 'Hello world'},
 'major_fontsize': 7,
 'major_format': None,
 'major_gridstyle': None,
 'major_locator': None,
 'major_rotation': 90,
 'minor_fontsize': 4,
 'minor_format': None,
 'minor_gridstyle': None,
 'minor_locator': None,
 'minor_rotation': None,
 'target': 'xaxis',
 'varKeys': dict_keys(['major_gridstyle', 'major_format', 'minor_format', 'target', 'minor_gridstyle', 'major_fontsize', 'minor_rotation', 'minor_locator', 'major_rotation', 'major_locator', 'title_kw', 'title', 'limits', 'minor_fontsize'])}

# (4)
{'limits': None,
 'major_fontsize': 7,
 'major_format': None,
 'major_gridstyle': None,
 'major_locator': None,
 'major_rotation': 90,
 'minor_fontsize': 4,
 'minor_format': None,
 'minor_gridstyle': None,
 'minor_locator': None,
 'minor_rotation': None,
 'target': 'xaxis',
 'title': 'Hello world',
 'title_kw': None}

我看到的更深:

'limits' 键指向的变量未在内部范围内定义:

locals()[k] # (3')

'limits' 键失败(实际上是第三个工厂参数,无论它被调用什么都不会传递给内部)。这就是我从 # (3') 更改为 # (3) 的原因,并且我必须使用 # (2) 存储来自外部范围的密钥,以便跟踪密钥并使 MWE 正常工作。

这让我很困惑!

我的问题是:为什么我的一些 locals 变量没有到达我工厂的内部范围?

【问题讨论】:

  • 顺便说一句,我猜您发布的函数工厂中缺少return inner
  • 我很惊讶# (5) 打印除axekwargsvarKeys 之外的任何内容,因为您没有引用任何其他局部变量(当然是内部函数的局部变量) )。你确定这是产生输出的代码(当然是return inner 修复)吗?如果是 - 你正在使用一些非常奇特的 Python 解释器!
  • 顺便说一句。不相关 - 我认为外部函数定义中的 title_kw=dict() 不会像你认为的那样 - 它只会在评估函数时创建一次字典,并且该字典将用于对该函数的所有后续调用。如果您要在范围内的任何位置修改title_kw,它将在下一个省略title_kw 参数的调用中保持修改状态。永远不要使用可变参数作为函数参数,除非这正是你所寻求的行为,而且它并不比它更频繁。
  • @zwer:感谢您指出您需要引用外部变量才能使其出现在嵌套函数的局部变量中。我相应地更新了我的答案。我的猜测是,在inner 的原始版本中,OP 引用了除limits 之外的所有外部函数参数。
  • @zwer,你说得对,这就是我观察到的原因,抱歉,如果我没有说清楚。

标签: python-3.x factory locals


【解决方案1】:

我尝试了你的 MWE,它给了我不同的结果(Python 3.5.2):

>>> test = TicksFormatterFactory(minor_fontsize=4)
{'limits': 100,
 'major_fontsize': 7,
 'major_format': None,
 'major_gridstyle': None,
 'major_locator': None,
 'major_rotation': 90,
 'minor_fontsize': 4,
 'minor_format': None,
 'minor_gridstyle': None,
 'minor_locator': None,
 'minor_rotation': None,
 'target': 'xaxis',
 'title': None,
 'title_kw': {}}
>>> test(1, title='Hello')
{'axe': 1,
 'kwargs': {'title': 'Hello'},
 'varKeys': dict_keys(['title_kw', 'minor_fontsize', 'minor_rotation', 'minor_gridstyle', 'minor_format', 'minor_locator', 'major_fontsize', 'major_rotation', 'major_gridstyle', 'major_format', 'major_locator', 'limits', 'target', 'title'])}
{'limits': None,
 'major_fontsize': None,
 'major_format': None,
 'major_gridstyle': None,
 'major_locator': None,
 'major_rotation': None,
 'minor_fontsize': None,
 'minor_format': None,
 'minor_gridstyle': None,
 'minor_locator': None,
 'minor_rotation': None,
 'target': None,
 'title': 'Hello',
 'title_kw': None}

这是我所期望的。在inner 内部调用locals() 不应返回外部函数的参数,因为它们不是inner 的本地参数,除非您引用它们。

你需要通过这种方式访问​​TicksFormatterFactory的本地人:

def TicksFormatterFactory( \
    title=None, target='xaxis', limits=100 \
   ,major_locator=None, major_format=None, major_gridstyle=None, major_rotation=90, major_fontsize=7 \
   ,minor_locator=None, minor_format=None, minor_gridstyle=None, minor_rotation=None, minor_fontsize=None \
   ,title_kw=dict() \
):
    pprint.pprint(locals())   # (1)
    localVars = locals() # (2)
    def inner(axe, **kwargs):

        pprint.pprint(locals())   # (5)

        # Allow User to overwrite settings using kwargs:
        settings = dict()
        for k in localVars:
            settings[k] = kwargs.get(k, localVars.get(k)) # (3)

        pprint.pprint(settings) # (4)

    return inner

产量:

>>> test = TicksFormatterFactory(minor_fontsize=4)
{'limits': 100,
 'major_fontsize': 7,
 'major_format': None,
 'major_gridstyle': None,
 'major_locator': None,
 'major_rotation': 90,
 'minor_fontsize': 4,
 'minor_format': None,
 'minor_gridstyle': None,
 'minor_locator': None,
 'minor_rotation': None,
 'target': 'xaxis',
 'title': None,
 'title_kw': {}}
>>> test(1, title='Hello')
{'axe': 1,
 'kwargs': {'title': 'Hello'},
 'localVars': {'limits': 100,
               'major_fontsize': 7,
               'major_format': None,
               'major_gridstyle': None,
               'major_locator': None,
               'major_rotation': 90,
               'minor_fontsize': 4,
               'minor_format': None,
               'minor_gridstyle': None,
               'minor_locator': None,
               'minor_rotation': None,
               'target': 'xaxis',
               'title': None,
               'title_kw': {}}}
{'limits': 100,
 'major_fontsize': 7,
 'major_format': None,
 'major_gridstyle': None,
 'major_locator': None,
 'major_rotation': 90,
 'minor_fontsize': 4,
 'minor_format': None,
 'minor_gridstyle': None,
 'minor_locator': None,
 'minor_rotation': None,
 'target': 'xaxis',
 'title': 'Hello',
 'title_kw': {}}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多