Constants and sugar

I have a set of functions that I use very often, so I would like to collect them in the library. Before starting to write the library, I thought about where to store the constants that affect the behavior of some of the functions.

What I would like to write when using the library was as follows:

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

Generally speaking, the constants that a function must accept must be stored in the function itself.

To achieve this, I created a decorator function that assigns the passed attributes to the decorated function.

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

This decorator can be used as follows:

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

It works very well so far.

But what about the default arguments?

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

This does not work because the collection function is not defined (and therefore not even decorated) at the point where the default value for the mode argument is stored.

It looks good

, , , . - , , .

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):
    # ...

:

? " ".

+5
2

.

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
+1

, , , .

. , . 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)
0

All Articles