5

我有一组我经常使用的函数,所以我想将它们收集到一个库中。在开始编写库之前,我在考虑将影响某些函数行为的常量存储在哪里。

使用该库时我想写的内容如下:

import tools
tools.collect(object_a, object_b, mode=tools.collect.RECURSIVE)

一般来说,函数应该能够接受的常量应该存储在函数本身中。

为了实现这一点,我创建了一个装饰器函数,将传递的属性分配给装饰函数。

def attr_decorator(**attrs):
    def decorator(f):
        for k, v in attrs.iteritems():
            setattr(f, k, v)
        return f
    return decorator

这个装饰器可以这样使用:

@attr_decorator(
    FLAT = 1 << 0,
    RECURSIVE 1 << 1,
)
def collect(a, b, mode):
    # ...

到目前为止,这工作得很好。

但是默认参数呢?

@attr_decorator(
    FLAT = 1 << 0,
    RECURSIVE 1 << 1,
)
def collect(a, b, mode=collect.RECURSIVE):
    # ...

这不起作用,因为在存储模式参数的默认值时未定义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

不需要天才就可以认识到这并不好阅读:

collect_d = attr_decorator(
    FLAT = 1 << 0,
    RECURSIVE = 1 << 1,
)
@collect_d
def collect(root, callback, mode=collect_d.RECURSIVE):
    # ...

问题:

你能想出更好的方法吗?我真的很想坚持“一个声明来装饰”的事情。

4

2 回答 2

1

您可以使用特殊变量作为对正在定义的函数的引用。

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
于 2012-09-23T16:53:45.270 回答
0

一般来说,函数应该能够接受的常量应该存储在函数本身中。

我不同意这种说法。这些常量是函数外部接口的一部分,供调用者使用。将它们定义为 的一部分有什么问题tools

COLLECT_RECURSIVE=0
COLLECT_NONRECURSIVE=1
COLLECT_OTHER=2

def collect(a,b,mode):
    pass

呼叫者,召集者:

import tools
tools.collect(object_a, object_b, mode=tools.COLLECT_RECURSIVE)
于 2012-09-23T17:10:11.467 回答