【问题标题】:when a python function is decorated, in which scopes is that decoration visible?当一个 python 函数被修饰时,该修饰在哪些范围内可见?
【发布时间】:2019-11-18 20:13:30
【问题描述】:

例如...给定

  1. 环境 (A) [在其中加载模块 (B)] 提供了一个功能,例如,“注册”
  2. 模块 (C) [由 (B) 导入] 提供了一组实用程序来加载/运行其他脚本/模块/等
  3. 模块 (D) 是那些“其他脚本”之一 - 它在其主线(最外层)范围内调用“register()”,因此 至于传达 D 的主要入口点(执行/启动 D 的服务/工作的功能)以及其他项目(包括,例如参数和适当的默认值) - 和
  4. 模块 (B) 提供了一个函数 (runScript(filename...)),当它被调用时 -
    • a) 验证请求,
    • b) 装饰“注册”,这样当 (D) 作为导入/加载的一部分被加载和执行时,“注册”的调用由装饰器处理,该装饰器捕获随后要调用的入口点,
    • c) 调用 C 中的实用程序过程,该过程处理可用导入机制的细微差别,然后
      • i) 加载脚本(通过导入它)[它应该执行脚本,它应该执行函数调用 register,它应该调用装饰器,它应该捕获并保存“注册”入口点],并且那么
      • ii) 检索并调用保存的“注册”入口点

(A) 和 (D) 都不能修改 - 我们只能修改 B 和/或 C 中的代码。

似乎当 B.runScript(filename) 被调用时,除了包装器之外,一切都按预期工作。脚本确实被加载了[即,如果它有一个 Do 方法,它将被调用。 *1] 但是如果没有 Do 方法,注册没有捕获入口点。

对于我的误解和/或误解/实施,我提前道歉

模块 B (runScript - runScript.py):

import os
import App
def getEntryPoint(pi_registration):
    def registration(*args, **kwargs):
          App.plugin_EntryPoint = args[10]
          return True
    return registration

def runScript(filename):
    global register
    try:
        os.stat(filename)
        register = getEntryPoint(register)  # apply decorator
        App.Do("RunScript", { 'FileName' : filename })
    except:
        print "script inaccessible ("+filename+")"

模块 C(应用程序(控制/仿真...)App.py):

import sys
import os
import path
import gimp
# etc...
plugin_EntryPoint = None

def Do(procedureName, options)
    # ...
    if procedureName == 'RunScript':
        filename = options['FileName'}
        # determine import mechanisms available --
        isimport = False
        isimportSFL = False
        isimportUtil = False
        isimportable = False
        try:
            import imp
            isimport = True
        except:
            pass
        if not isimport:
            # try alternative version's loader mechanism versions...
            try:
                from importlib.machinery import SourceFileLoader
                isimportSFL = True

            except: 
                pass
            if not isimportSFL:
                try:
                    import importlib.util
                    isimportUtil = True
                except:
                    pass

        plugin_EntryPoint = None
        if isimport:
            moduleD = imp.load_source("module_D", filename)
        elif isimportSFL:
            moduleD = SourceFileLoader("module_D", filename)
        elif isimportUtil:
            modspec = importlib.util.spec_from_file_location("module_D", filename)
            moduleD = importlib.util.module_from_spec(spec)
            spec.loader.exec_module(moduleD)

        if hasattr(moduleD, 'Do')
            moduleD.Do()                    # try conventional entry point...
        elif plugin_EntryPoint is None:     # try 'registered' entry point...
            raise AppTerminate, "no entry point registered"
        else
            pluginEntryPoint(App.plugin_Args)
    # ...

Module D(服务插件'moduleD.py'):

def myEntrypoint():
    print "entered"

register("myName", "", "", "", "", "", "", "", [], [], myEntrypoint)

if __name__ == '__main__":
    main()

环境(A): 坦率地说,因为我无法确切地看到环境 (gimpfu) 是如何设置它的,所以我只能推测手头问题的 可能 等价性:

#!/usr/bin/python

def register(name, a, b, c, d, e, f, g, h, i, entrypoint):
     print "Plugin "+name+ " Entrypoint "+str(entrypoint)

import RunScript
RunScript._runScript("moduleD")
import _RunScript

【问题讨论】:

  • 我承认我没有阅读整个问题,但该代码中没有装饰函数......也许你误解了“装饰”的含义?
  • 我认为装饰:register = getEntryPoint(register) 仅适用于模块 B。register 变量是全局,但仅在模块 B 中。如果另一个模块加载 D,它会看到原版。您可能正在修补之后。
  • @Error-SyntacticalRemorse:但这装饰器在幕后实际工作的方式。
  • 你能推导出一个最小的工作示例@ChrysG吗?我认为答案很简单,但很难克服这个问题(甚至更难测试任何东西,因为您的代码不可运行)。
  • 正如您在问题中提到的那样,函数装饰只不过是为对象分配名称,例如当您执行func = decorator(func) 时,使用此范围的func 名称的代码将使用修饰函数。当您使用不同的名称时更容易想象:func_decorated = decorator(func)。所有有权访问func_decorated 的代码都将使用修饰版本,所有有权访问func 的代码将使用未修饰版本。与func = decorator(func) 的唯一区别是可能会覆盖名称func。您可以使用不同的名称进行追踪。

标签: python python-import python-decorators


【解决方案1】:

这最终会转移到 Python 的静态与动态范围问题——因此,函数的范围是静态的,并且仅在模块中可见,而不是它本身可能导入的任何模块。

评论:噢,糟了。我猜在做了很多系统编程工作之后,我们将一层“滑入”功能堆栈中(拦截较低层的服务请求而不影响堆栈中它上面的层(发出服务请求),我希望有将是一种方式,某种方式,来完成同样的事情。[c'est la guerre]

【讨论】:

    猜你喜欢
    • 2014-11-06
    • 2020-04-19
    • 1970-01-01
    • 2011-02-12
    • 1970-01-01
    • 2021-10-05
    • 1970-01-01
    • 1970-01-01
    • 2017-03-07
    相关资源
    最近更新 更多