首页 > 解决方案 > 当一个python函数被修饰时,那个修饰在哪些范围内可见?

问题描述

例如...给定

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

模块 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

标签: pythonpython-importpython-decorators

解决方案


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

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


推荐阅读