是否可以在没有 exec() 的情况下自动使模块的所有 public class 方法成为全局函数? turtle.py为例

Is it possible to automatically make all of a module's public class methods global functions without exec()? turtle.py as an example

我看到它声称 exec() 从来都不是必需的,应该始终避免。虽然在 99.9% 的时间里显然有更好的方法来做事,但我在查看 turtle.py 时发现了这个:

## The following mechanism makes all methods of RawTurtle and Turtle available
## as functions. So we can enhance, change, add, delete methods to these
## classes and do not need to change anything here.

__func_body = """\
def {name}{paramslist}:
    if {obj} is None:
        if not TurtleScreen._RUNNING:
            TurtleScreen._RUNNING = True
            raise Terminator
        {obj} = {init}
    try:
        return {obj}.{name}{argslist}
    except TK.TclError:
        if not TurtleScreen._RUNNING:
            TurtleScreen._RUNNING = True
            raise Terminator
        raise
"""

def _make_global_funcs(functions, cls, obj, init, docrevise):
    for methodname in functions:
        method = getattr(cls, methodname)
        pl1, pl2 = getmethparlist(method)
        if pl1 == "":
            print(">>>>>>", pl1, pl2)
            continue
        defstr = __func_body.format(obj=obj, init=init, name=methodname,
                                    paramslist=pl1, argslist=pl2)
        exec(defstr, globals())
        globals()[methodname].__doc__ = docrevise(method.__doc__)

_make_global_funcs(_tg_screen_functions, _Screen,
                   'Turtle._screen', 'Screen()', _screen_docrevise)
_make_global_funcs(_tg_turtle_functions, Turtle,
                   'Turtle._pen', 'Turtle()', _turtle_docrevise)

这段代码就是为什么使用 turtle 模块对初学者如此方便的原因。除了 Turtle class 实例根据需要自动为自己分配 Screens 之外,这种“机制”自动使每个 public class 方法成为一个全局函数。这就是为什么这样的代码,从不直接实例化任何海龟 classes,有效:

import turtle
turtle.forward(100)
turtle.mainloop()

这将实例化一个 Screen,实例化一个 Turtle,将 Screen 分配给 Turtle,调用该 Turtle 实例的方法来绘制一条线,并调用该 Screen 的方法以保持 window 打开, 都带有自动生成的全局函数。这是我见过的 exec() 的最佳用例。

有没有办法在没有 exec() 的情况下更像 python 一样做到这一点?

这里是如何在没有 exec() 的情况下复制它......有点。

exec() 仍然需要以显式方式将旧的调用签名分配给新的全局函数,没有方便的方法为函数提供新的调用签名。

然而,作为我的问题的答案,闭包用于将方法变成全局函数,调用签名必须是 *args, **kwargs

下面的代码似乎可以代替我发布的代码并回答我的问题标题,如何在没有 exec 的情况下复制制作方法全局函数,尽管我认为由于缺乏准确的签名,它不是更 pythonic :

def __turtle_func_closure(obj, init, name):
    """Wraps class methods as global functions."""

    def func(*args, **kwargs):
        """Global function equivalent ofor class methods."""
        obj_ = getattr(Turtle, obj, None)
        if obj_ is None:
            if not TurtleScreen._RUNNING:
                TurtleScreen._RUNNING = True
                raise Terminator
            obj_ = init()
        try:
            return getattr(obj_, name)(*args, **kwargs)
        except TK.TclError:
            if not TurtleScreen._RUNNING:
                TurtleScreen._RUNNING = True
                raise Terminator
            raise

    return func


def _make_global_funcs(functions, cls, obj, init, docrevise):
    for methodname in functions:
        method = getattr(cls, methodname)

        globals()[methodname] = __turtle_func_closure(obj, init, methodname)
        globals()[methodname].__doc__ = docrevise(method.__doc__)

_make_global_funcs(_tg_screen_functions, _Screen,
                   'Turtle._screen', Screen, _screen_docrevise)
_make_global_funcs(_tg_turtle_functions, Turtle,
                   'Turtle._pen', Turtle, _turtle_docrevise)