1

I've been trying to wrap my head around this as I'm new to python. I have files A.py and B.py. I am currently trying to write a function in A.py that will iterate though all the function names in B.py and call that function if a condition is met. I have also imported the files. Any ideas?

Pseudo code for A.py

For function name in B.py
   If functionname == functionOne
       Call that function()

Example for B.py

def functionOne():
    Print("this is one")

def functionTwo():
  Print("this is two") 
  • by making a container of functions? – Azat Ibrakov Apr 14 '20 at 06:08
  • Why do you want to *iterate* through the other module? If you already know the function name, you can just *get* it. Do you need to support other comparisons than exact function name match? Do you need to support other criteria than function name, e.g. type? Most importantly, what have you tried so far? – MisterMiyagi Apr 14 '20 at 07:49
  • Can you clarify what you are trying to achieve? Instead of directly operating on a module, your underlying problem may be better addressed by a dedicated data structure. For example, a ``dict`` or ``list`` that contains all valid functions regardless where they are defined. Such data structures could also be optimised to be keyed by the attributes your condition is looking for. – MisterMiyagi Apr 14 '20 at 07:54
  • I assume that your example is a very simplified version of the actual goal. The test for whether you want to execute the function is more complicated than just comparing its name to a fixed string. – Todd Apr 14 '20 at 08:04
  • @MisterMiyagi Thank for answering, Yes, I need to add support for other comparisons than just explicitly referencing functionOne() . I see what you are trying to say. I tried addressing this issue by creating by a dictionary d = {"functionOne" : "1", "functionTwo" : "2"}. I have a section that takes user input and returns a string of that number picked (i.e "1"). so now I'm trying to work out the logic: loosely `for name, value in vars(B) .items(): for key in d.keys(): if name == key: value().` i need this to only call the function in B.py if name matches with the dictionary key. – mondragonfx Apr 14 '20 at 23:12

4 Answers4

0

result = getattr(b, 'functionOne')()

result()

Look at: Calling a function of a module by using its name (a string)

fernand0
  • 310
  • 1
  • 10
0

One way to do is, to use the dir() built in function which returns all properties and methods of the specified object, without the values. The you can iterate over dir() and filter the function name that is needed to be called. To call the function we can use the getattr() function which returns the value of the specified attribute from the specified object.

Use:

"""
File: B.py
"""

def functionOne():
    print("this is one")

def functionTwo():
    print("this is two") 

"""
File: A.py
"""
import B

for attr_name in dir(B):
    if attr_name == "functionOne":
        getattr(B, attr_name)() #--> call the function
    elif attr_name == "functionTwo":
        getattr(B, attr_name)() #--> call the function

Output:

>>> python A.py

this is one
this is two
Shubham Sharma
  • 68,127
  • 6
  • 24
  • 53
  • this does work for my case however, it would require me to if elif each function name for attr_name. In hindsight, it will probably the same lines of code bc i implemented each function name as a string into a dictionary key. – mondragonfx Apr 14 '20 at 23:38
0

I assume that the actual problem is more complex than a simple string comparison to find the function, but for the sake of clarity my first example uses the simplified case.

If you treat B as a module that you can import, using the built-in, vars(), you could iterate over the names of functions and the functions themselves in parallel and test for the condition and execute.

import B 

for name, value in vars(B).items():
    if name == 'functionOne':
        value()

vars() is a built-in similar to dir() except that it returns a dictionary of the names and values. If you used dir(), you'd have to then use getattr() or B.__dict__[name] or some other extra step to get the value.

A more general implementation could look like:

for name, value in vars(B).items():
    if callable(value) and check_conditions_met(name, value):
        value()

You would need to declare and implement check_conditions_met(). value() invokes the function without parameters.

The for loop iterates over the name of each member of the module, and its value. callable() will be true if the value can be called as a function.

If you already know the names of the functions you want to execute in a module and they don't vary, but may not be implemented:

try:
    B.functionOne()

except AttributeError as ae:
    print(f"module 'B' may be missing an implementation: {ae}")

You can always get an attribute of any object by name using getattr():

getattr(B, 'functionOne')()

Kind of a roundabout way of going about it though. But could be useful for the case where user input (as suggested in another answer) is used to select the function to run:

for _ in range(n_attempts):
    try:
        request = input("What do you want me to do? ")
        cmd, *params = request.split()
        getattr(B, cmd)(*params)

    except AttributeError:
        print("Please try again...")
Todd
  • 4,669
  • 1
  • 22
  • 30
0

Ok, everybody already posted solutions based on dir() + getattr() or vars(), which technically answer the question indeed. I'd just want to mention that if the name of the function to execute comes from user inputs, it's much safer and clearer to use an explicit dict of allowed functions, ie:

# b.py
def functionOne():
    print("this is one")

def functionTwo():
    print("this is two") 

def no_you_dont():
    raise Exception("you should not call me")

and then

# a.py
import b

funcs = {"name1" : b.functionOne, "name2": b.functionTwo}


name = input("which func ?")
try:
    f = funcs[name]
except KeyError:
    print("sorry, {} is not allowed".format(name)
else:
    f()

The point is that 1/ which functions are expected to be used that way is as explicit as it can be and 2/ you wont inadvertently expose anything that shouldn't be.

bruno desthuilliers
  • 75,974
  • 6
  • 88
  • 118
  • It's `dir() + getattr() or vars()` ;-) – Todd Apr 14 '20 at 07:29
  • @brunodesthuilliers Can you elaborate more on what you mean by an explicit dict?. I added a comment above mentioning that i created a dictionary that holds the names of the functions as the key and the value would be the user input. [hard coded bc these will never change] if user input is the value of the key, call the function that corresponds to the same name in B.py. Hopefully that makes sense... – mondragonfx Apr 14 '20 at 23:31
  • @mondragonfx actually it's even simpler: you use the functions themselves as values. Python functions are objects (everything in python is an object actually), so you can use them like just anything else - cf my edited answer. – bruno desthuilliers Apr 15 '20 at 07:19
  • @mondragonfx, please take a look at my last example. A module already implements a dictionary with the member names that can be leveraged via getattr(). If user input fails to match a member name, then an AttributeError is generated and handled in a loop. You could name the module functions after commands that you expect the user to input. – Todd Apr 16 '20 at 01:37