Decorator: function parameter problem

I have two functions that use a decorator, the problem is one has 2 parameters while the other only has one, which of these is best solution?

A)

@find_and_replace
def make_clozein(*args):
    matches, _ = args

B)

@find_and_replace
def make_clozein(*args):
    matches = args[0]

Both are brittle:

  • (A) assumes that len(args) == 2 and will raise a ValueError if this is not the case
  • (B) assumes that len(args) > 0 and will raise an IndexError if called without arguments

So, (B) is a bit more generally usable. But if none of the other arguments are used in make_clozein, then why not change the function signature to be

def make_clozein(matches):
      ...

This is clearer, and leaves less room for bugs to sneak in.
Otherwise, if you do use some of the other arguments later in the function (or if you have another reason for keeping the current signature), I would change it to sth like:

def make_clozein(*args):
      matches = args[0] if args else None
      ...
2 Likes

The decorator passes 2 arguments func(arg1, arg2) when calling the function which could be the one that has two parameters foo(param1, param2) or the other that has only one bar(param1) so def make_clozein(matches): wouldn’t work.

Ah, so if it must recieve either one or two arguments, with the first always being the one you want and the second discarded, why not do

@find_and_replace
def make_clozein(matches, *args):
    ...

Now the first argument is always mapped to matches, while the second, if present, is included in the args list, otherwise it is an empty list. Since you apparently don’t actually use the second argument, you can simply ignore args (and potentially name it something like, e.g. *unused instead).

However, this allows more than two arguments to be passed, so if you know you’re always going to get two and want to check for cases of >2, you could do, e.g.

@find_and_replace
def make_clozein(matches, _unused=None):
    ...
1 Like

That’s a more explicit way to do it. Can a class solve this problem more efficiently? Currently I remove the decorator because I screwed up, so I’m trying to learn unit testing so it won’t happen again.

Well, not really the described problem of parsing arguments as you intend, no. But I’m guessing you might be implying this is an XY problem, and you actually are asking about a better solution to whatever underlying problem for which you created and used the decorator (e.g. doing find and replace on the arguments to multiple functions?). In that case, it certainly could be one, yeah. Or simply a regular helper function that your function calls. It all depends on what you actually want to do and why; if you could provide more details about about that, perhaps we could suggest something.

1 Like

So the original problem is I have a function to find a cloze pattern and shuffle them (because the flashcard app I’m using doesn’t have a shuffle mode), but I created another function that modified the clozes, which I realize I’m just copying the first function with just a little difference.

Now I’m wondering what the decorator is really intended for.