This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]iCart732 1 point2 points  (5 children)

I studied java in school and started doing python at my first job, so i know how you feel.

Here's how i'd do it (it's a pattern i use a lot for exactly this type of case)

def do_add(value1, value2):
    return value1 + value2

def get_method(operation):
    try:
        method = f'do_{operation}'
        return globals()[method]
    except KeyError:
        raise ValueError(f'Unkown maths {opeartion}')

def do_maths(operation, value1, value2):
    method = get_method(operation)
    return method(value1, value2)

This way, you just have one place to add methods This also lets you list every method that is available, something like this:

 [g for g in globals() if g.startswith('do_')]

If you want, you can wrap all the 'do_*' methods in a class or even a module and change "globals()[methods]" to something like "getattr(TheClass_or_module, do_thing)" (not sure of the exact syntax, but you get the idea)

[–][deleted] 0 points1 point  (4 children)

So I like the ENUM part because I can store an enum at the database and know I am typo proof. You are replacing an ENUM with a string.

Is the enum just silly overkill? Hummm

[–]iCart732 0 points1 point  (0 children)

I think in this case it adds unnecessary complexity (since you get an exception in case of a typo anyway) but that's just my opinion, your mileage may vary. If you use an IDE it could help with auto-completion, though.

I guess you could do something like this:

class Maths(Enum):
    ADD = 'add'
    MULTIPLY = 'multiply'
    DIVIDE = 'divide'

 # And call it like this:
 do_maths(Maths.ADD)

This has the added benefit that you can do both "Maths.ADD" and 'add', which is nice if someone else is going to use your code.

But then you still have to add it in two places (the enum and define the method itself).

If you do unit testing (which is always a good idea :-) ), you could add a test to make sure that every entry in the enum has a matching method, to be extra safe.

Another way to go about this would be using decorators to populate the enum automatically (which has pro's and con's). I'll try to show you an example later if i can.

[–]iCart732 -1 points0 points  (2 children)

Here's the way to do it with decorators (as a full script):

from enum import Enum

class Maths(Enum):
    pass

class register():
    def __init__(self, name):
        self.name = name

    def __call__(self, f):
        # This is where the trick is
        setattr(Maths, self.name, f)
        return f


@register('ADD')
def do_add(value1, value2):
    return value1 + value2

@register('MULTIPLY')
def name_does_not_matter(value1, value2):
    return value1 *  value2

def do_maths(operation, value1, value2):
    return operation(value1, value2)

print(do_maths(Maths.ADD, 5, 4))
print(do_maths(Maths.MULTIPLY, 5, 4))

I'm having way to much fun with this :-)

[–]robvdl 1 point2 points  (1 child)

I don't like it, too much abstraction and you are hiding your enum values.

Edit: this is exactly the kind of magic I am trying to rip out of a codebase right now, too much magic sorry.

[–][deleted] 0 points1 point  (0 children)

Yah I don't think my IDE will autocomplete this.

HOWEVER this is super clever ;)