Nik*_*s R 5 python constants decorator syntactic-sugar
我有一组经常使用的函数,所以我想在库中收集它们.在我开始编写库之前,我在考虑在哪里存储影响某些函数行为的常量.
使用该库时我想写的内容如下:
import tools
tools.collect(object_a, object_b, mode=tools.collect.RECURSIVE)
Run Code Online (Sandbox Code Playgroud)
一般来说,函数应该能够接受的常量应该存储在函数本身中.
为了实现这一点,我创建了一个装饰器函数,将传递的属性分配给修饰函数.
def attr_decorator(**attrs):
def decorator(f):
for k, v in attrs.iteritems():
setattr(f, k, v)
return f
return decorator
Run Code Online (Sandbox Code Playgroud)
这个装饰器可以像这样使用:
@attr_decorator(
FLAT = 1 << 0,
RECURSIVE 1 << 1,
)
def collect(a, b, mode):
# ...
Run Code Online (Sandbox Code Playgroud)
到目前为止这个工作非常好.
@attr_decorator(
FLAT = 1 << 0,
RECURSIVE 1 << 1,
)
def collect(a, b, mode=collect.RECURSIVE):
# ...
Run Code Online (Sandbox Code Playgroud)
这不起作用,因为在存储mode参数的default-value时未定义collect函数(因此甚至没有修饰).
我能够提出的唯一解决方案导致了一种笨拙的语法,它看起来并不好看.我给装饰器函数提供了与要装饰的函数相同的属性.
def attr_decorator(**attrs):
def decorator(f):
for k, v in attrs.iteritems():
setattr(f, k, v)
return f
for k, v in attrs.iteritems():
setattr(decorator, k, v)
return decorator
Run Code Online (Sandbox Code Playgroud)
天才不会认识到这不好看:
collect_d = attr_decorator(
FLAT = 1 << 0,
RECURSIVE = 1 << 1,
)
@collect_d
def collect(root, callback, mode=collect_d.RECURSIVE):
# ...
Run Code Online (Sandbox Code Playgroud)
你能想到一个更好的方法吗?我真的很想留下"一个声明到装饰"的东西.
您可以使用特殊变量作为对正在定义的函数的引用。
class Attr(object):
def __init__(self, name): self.name = name
class Attributor(object):
def __getattr__(self, x): return Attr(x)
_ = Attributor()
def attr_decorator(**attrs):
def decorator(f):
for k, v in attrs.iteritems():
setattr(f, k, v)
f.func_defaults = tuple(attrs[t.name] if isinstance(t, Attr) else t for t in f.func_defaults)
return f
return decorator
@attr_decorator(
FLAT = 1 << 0,
RECURSIVE = 1 << 1,
)
def collect(a, b, mode=_.RECURSIVE, foo=123):
print a, b, mode, foo
collect(100,200) # 100 200 2 123
Run Code Online (Sandbox Code Playgroud)