0

I have a function called set_func that is 25 lines long. Inside it calls update.

def set_func(table: str, identifier=None, **kwargs) -> None:
    ... # does stuff with arguments
    query = update(table, kwargs, identifier)
    ...
    execute(query)

I want to declare a function called delete_func that does the exact same thing, but instead of calling update it would call delete.

My code:

def delete_func(table: str, identifier=None) -> None:
    global update
    backup_update = deepcopy(update)
    assert backup_update is not update

    update = delete
    try:
        return set_func(table, identifier)
    finally:
        update = backup_update

This works, buy it seems bad practice. Is there another way to do this without changing set_func? Is it bad code?

  • 1
    You can make a function that takes in the operation ('set' or 'delete') and call different functions based on that. – Fractalism Jan 28 '23 at 17:19
  • 1
    Write a function that accepts either `update` or `delete` as an argument, then call whatever function is passed. No global variables are needed. – chepner Jan 28 '23 at 17:19
  • 1
    Why not change `set_func`? Is it third-party code? – wjandrea Jan 28 '23 at 17:20
  • 1
    At the very least, you don't need to *copy* the function. `backup_update = update; update = delete; ...; update = backup_update` will suffice. The assignments don't affect the old value of the name. – chepner Jan 28 '23 at 17:22
  • For a general answer: [Why are global variables evil?](/q/19158339/4518341) – wjandrea Jan 28 '23 at 17:23
  • I'll could do some type of "function inheritance" like Fractalism and chepner proposed. Buy I asked if my code has a bad smell. It looks this way simpler I believe. – Lucas Napon Jan 28 '23 at 17:33
  • 1
    @LucasNapon It definitely does not look good. And it does not really seem simpler. – Unmitigated Jan 28 '23 at 17:38
  • you might alter `set_func()` to accept a work function then pass either `update()` or `delete()` to it. – JonSG Jan 28 '23 at 17:55
  • Functions are first-class values; passing a function as an argument is no more like inheritance than passing an `int` value. Even `update` and `delete` are just variable with values of type `function`, not the functions themselves. (The only difference is that the names were assigned the values by a `def` statement, rather than an assignment statement.) – chepner Jan 28 '23 at 18:10

1 Answers1

1

Since functions are first class, I would probably pass whatever work was to be done into your method as a parameter. Alternatively, you could pass in a flag and internally determine how to process the work. I would definitely NOT change the implementation as you have done here even if it technically worked.

I might do something like this:

def fn_update(table: str, identifier, **kwargs) -> None:
    # do whatever you do to just update
    return "query"

def fn_delete(table: str, identifier, **kwargs) -> None:
    # do whatever you do to just delete
    return "query"

def set_func(fn_work, table: str, identifier=None, **kwargs) -> None:
    ... # does stuff with arguments
    query = fn_work(table, identifier, kwargs)
    ...
    execute(query)
JonSG
  • 10,542
  • 2
  • 25
  • 36