0

Is it possible to generate dynamically class methods which are very similar one another?

Say I have a class like this one:

class KitchenDrawer:

    def _check_if_tool_available(self, tool) -> bool:
        # check if "tool" is in the drawer

    def is_knife_available(self) -> bool:
        return self._check_if_tool_available("knife")

    def is_spoon_available(self) -> bool:
        return self._check_if_tool_available("spoon")

    def is_fork_available(self) -> bool:
        return self._check_if_tool_available("fork")

Is there a way to generate is_knife_available(), is_spoon_available(), is_fork_available() dynamically, so there is not so much repeated code?

(Some of you might suggest to simply make _check_if_tool_available(self, tool) a public facing method and carry on with my life. Fair. But more than the sensible solution, I am interested in the nitty gritty issue here.)

Thanks!

4
  • 4
    Just use the solution in the last paragraph. Dynamic function creation is possible, but there's 0 reason to use it here (or really, is the vast majority if not all of circumstances). You'd use something like eval to create the functions, but that would just be a hacky way of emulating a parameter. Commented Apr 28, 2024 at 14:24
  • 1
    There a lots of SO questions with answers returned by a simple "python create method dynamically" Google search, what exactly didn't answer your question in them? Commented Apr 28, 2024 at 14:37
  • You could override getattr, but that would be a lot of trouble when you could just use a parameter. Commented Apr 28, 2024 at 14:43
  • 2
    It’s possible and not terrible in Python (without eval), but it’s just better practice to not make use of Python’s dynamic features – static analysis (both by tools and humans) is so valuable. I would write out the list of repetitive methods, assuming they’re this simple in reality. Commented Apr 28, 2024 at 14:45

2 Answers 2

2

Yes, it is possible, but it can be hard-debuggable approach. You can use setattr() for this purposes.

For example, you can implement smth like this:

class KitchenDrawer:
    def _check_tool(self, tool):
        return tool in ['knife', 'spoon', 'fork']

for tool in ['knife', 'spoon', 'fork']:
    setattr(KitchenDrawer, f'is_{tool}_available', lambda self, t=tool: self._check_tool(t))



# Usage
drawer = KitchenDrawer()
print(drawer.is_knife_available())   # True

Also you can check that methods is_fork_available, is_knife_available, is_spoon_available are available in the class:

dir(KitchenDrawer) 
# [... 'is_fork_available', 'is_knife_available', 'is_spoon_available'] 

Here is a related question that can be helpful with some better approach.

Sign up to request clarification or add additional context in comments.

Comments

0
class KintchenDrawer:
    def __getattr__(self, attr: str):
        if res := re.findall("is_(\w*?)_available", attr):
            return self._check_if_tool_available(res[0])

Then, you can use self.is_spoon_available without any paranthesis

Do you think it answers your problem? If yes, I can explain it

3 Comments

Definetely a good example!
@DmitryBrazhenko this answer is worse than yours. The methods won't show up in dir(KintchenDrawer) or help(KintchenDrawer) here.
Yes, this will not be show up, but on the other hand, it provides more flexibility.

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.