我正在研究一个主要返回闭包而不是传统的基于类的方法的Python项目.例如:
def term(token):
def fn(text):
return (...)
return fn
Run Code Online (Sandbox Code Playgroud)
可以想象,调试和测试闭包是一个噩梦,特别是如果我在整个代码中使用相同的名称来封闭.例如:
>>> term('t')
<function fn at 0x...>
Run Code Online (Sandbox Code Playgroud)
所以我尝试将它包装在一个类中以__repr__从namedtuple中获取特殊处理:
def rr(cls, attrs):
T = namedtuple(cls, attrs)
class G(object):
__slots__ = ()
def __init__(self, repr_message, callable):
self.callable = callable
self.repr_message = repr_message
def __call__(self, *args, **kwargs):
return self.callable(*args, **kwargs)
def __repr__(self):
return self.repr_message
K = type(cls, (G,), {})
def wrapper(fn):
def init(*args, **kwargs):
t = T(*args, **kwargs)
return K(
repr(t),
fn(*args, **kwargs),
)
return init
return wrapper
Run Code Online (Sandbox Code Playgroud)
这样:
>>> rr('Term', ['token'])(term)('$')
Term(token='$')
Run Code Online (Sandbox Code Playgroud)
你可以想象这可能会对性能产生影响.我的问题是,如果这种包装更可取,如果更多的是Pythonic而不仅仅是返回"丑陋"的封闭?
更轻松的方法是简单地修改闭包的func_name属性.结果不如代码生成的结果那么漂亮,但它对RAM和性能的影响最小.
def term(token):
def fn(text):
return text.split(token)
fn.func_name = "term(token={0!r})".format(token)
return fn
s = 'splitthistestup'
f = term('t')
g = term('i')
print(f, f(s))
print(g, g(s))
Run Code Online (Sandbox Code Playgroud)
典型输出
<function term(token='t') at 0xb74878b4> ['spli', '', 'his', 'es', 'up']
<function term(token='i') at 0xb74878ec> ['spl', 'tth', 'stestup']
Run Code Online (Sandbox Code Playgroud)
对于Python 3,您需要做一些稍微不同的事情.
fn.func_name = ...
Run Code Online (Sandbox Code Playgroud)
变为:
fn.__qualname__ = ...
Run Code Online (Sandbox Code Playgroud)