2

I have the following simple class and am wondering if there is a simple way to use a lambda, decorator, or helper method, etc... to avoid the duplicated for loop that appears in each method in CODENAMES and ALL_DEFAULTS?

class classproperty(object):
    """
    When used to decorate a method in a class, that method will behave
    like as a class property.
    """
    def __init__(self, f):
        # f - the func that's being decorated
        self.f = f

    def __get__(self, obj, cls):
        # call the func on the class
        return self.f(cls)

class PermissionInfo(object):

    MODELS = ['ticket', 'person', 'role']
    PERMS = ['view', 'add', 'change', 'delete']

    @classproperty
    def CODENAMES(cls):
        codenames = []
        for p in cls.PERMS:
            for m in cls.MODELS:
                codenames.append('{}_{}'.format(p, m))
        return codenames

    @classproperty
    def ALL_DEFAULTS(cls):
        ret = {}

        for p in cls.PERMS:
            for m in cls.MODELS:
                ret["{}_{}".format(p, m)] = False

        return ret

Duplicated for loop is this section of each method:

# ...
for p in cls.PERMS:
    for m in cls.MODELS:
#...

3 Answers 3

5

You could use itertools.product within helper method to generate the names:

from itertools import product

def names(cls):
    yield from ('_'.join(x) for x in product(cls.PERMS, cls.MODELS))

Then you could change your class to utilize it:

@classproperty
def CODENAMES(cls):
    return list(names(cls))

@classproperty
def ALL_DEFAULTS(cls):
    return dict.fromkeys(names(cls), False)
Sign up to request clarification or add additional context in comments.

Comments

0

You could perhaps use something like:

MODEL_PERMS = list(map(lambda t: "{}_{}".format(t[0],t[1]), itertools.product(MODELS, PERMS)))

1 Comment

Meh. @niemmi's answer is better.
0
from itertools import product


class PermissionInfo(object):

    MODELS = ['ticket', 'person', 'role']
    PERMS = ['view', 'add', 'change', 'delete']
    PRODUCT = product(PERMS, MODELS)
    CODENAMES = ['{}_{}'.format(p, m) for (p, m) in PRODUCT]
    ALL_DEFAULTS = {codename: False for codename in CODENAMES}

ohhh shiny :-}

1 Comment

Note that this is different from the original code since ALL_DEFAULTS can be easily mutated. Assume you generate custom permissions like this: perm = PermissionInfo.ALL_DEFAULTS; perm['view_ticket'] = True. With original implementation this is not an issue but with your implementation defaults will change.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.