问题描述
我已经看到它声称 exec()
从来没有必要,应该始终避免.虽然有99.9%的时间有更好的做事方式,但我在看turtle.py时发现了这一点:
I've seen it claimed that exec()
is never necessary and should always be avoided. While there are clearly better ways to do things 99.9% of the time, I was looking at turtle.py and found this:
## 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类实例根据需要自动为自己分配屏幕外,这种机制"还包括自动将每个公共类方法转换为全局函数.这就是为什么这样的代码(从不直接实例化任何乌龟类)起作用的原因:
This code is why using the turtle module is so convenient for beginners. In addition to Turtle class instances automatically assigning themselves Screens as necessary, this "mechanism" automatically makes every public class method into a global function. This is why code like this, which never directly instantiates any turtle classes, works:
import turtle
turtle.forward(100)
turtle.mainloop()
这将实例化一个Screen,实例化一个Turtle,将该Screen分配给该Turtle,调用该Turtle实例的方法以画一条线,并调用该Screen的方法以保持窗口打开,所有这些都将自动生成全局职能.这是我所见过的exec()的最佳用例.
This will instantiate a Screen, instantiate a Turtle, assign the Screen to the Turtle, call a method of that Turtle instance to draw a line, and call a method of that Screen to keep the window open, all with automatically generated global functions. This is the best use case for exec() I've ever seen.
有没有办法在没有exec()的情况下更Python地做到这一点?
Is there a way to do this more pythonically without exec()?
推荐答案
以下是在没有 exec()
...的情况下如何进行复制的方法.
Here is how this could be replicated without exec()
... somewhat.
exec()
,没有方便的方法为函数提供新的调用签名.
exec()
is still necessary for assigning the old call signature to the new global functions in an explicit way, there is no convenient way to give a function a new call signature.
但是,作为对我的问题的回答,闭包可以使方法成为全局函数,因此调用签名必须为 * args,** kwargs
.
However, as an answer to my question, a closure works for making the methods into global functions, the call signature just has to be *args, **kwargs
.
以下内容似乎可以代替我发布的代码,并回答我的问题的标题:如何在不使用exec的情况下复制生成方法的全局函数,尽管我会说由于缺乏准确的签名,它不是更pythonic的:/p>
The following seems to work in the place of the code I posted and answers my question's title, how to replicate making methods global functions without exec, though I would argue it is not more pythonic due to the lack of accurate signatures:
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)
这篇关于是否可以在没有exec()的情况下自动使模块的所有公共类方法成为全局函数?以turtle.py为例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!