Call a function dynamically from a variable - Python - python-3.x

Ok so I have two files, filename1.py and filename2.py and they both have a function with same name funB. The third file process.py has function that calls function from either files. I seem to be struggling in calling the correct function.
In process.py:
from directoryA.filename1 import funB
from directoryA.filename2 import funB
def funA:
#do stuff to determine which filename and save it in variable named 'd'
d = 'filename2'
# here i want to call funB with *args based on what 'd' is
So i have tried eval() like so:
call_right_funB = eval(d.funB(*args))
but it seems not to work.
Any help is appreciated.

The problem is, you can't use eval() with a combination of a string and a method like that. What you have written is:
call_right_funB = eval('filename'.funB(*args))
What you can do is:
call_right_funB = eval(d + '.funB(*args)')
But this is not very pythonic approach.
I would recommend creating a dictionary switch. Even though you have to import entire module:
import directoryA.filename1
import directoryA.filename2
dic_switch = {1: directoryA.filename1, 2: directoryA.filename2}
switch_variable = 1
call_right_funB = dic_switch[switch_variable].funB(*args)
Hope it helps.

Related

Is there a way to convert a conditional (if/for) statements to a variable?

I've written some code
for i in range(0, b):
for g in range(1, b+1):
if i+1==g:
a = f'''r{g} = {list(df.iloc[i])}<br>'''
I want to be able to store this exact code in a variable and be able to print it out/write it to a file (and hopefully be able to convert it into regular code again)
Just to clarify, I want to be able to print that exact piece of code/write that piece of code to a file
Is it possible?
Thanks in advance
You can store these lines of code in a function and then can get back its source code with the help of inspect library as follows:
import inspect
def foo(arg1, arg2):
# do something with args
a = arg1 + arg2
return a
lines = inspect.getsource(foo)
print(lines)
So if you wanna run these lines of code, just call the function, and if you wanna print these lines of code, just use inspect library.
And if you also want these lines of code to get written in another python file, just do as follows
file=open("Program.py","w")
file.write(lines)
#lines is the output of the above program
file.close()
And you would also be able to execute this python file!!
Hope I made myself clear
You can add it in a function, like this
def my_function(df, b):
for i in range(0, b):
for g in range(1, b+1):
if i+1==g:
a = f'''r{g} = {list(df.iloc[i])}<br>'''
And later if you want to call the function, just call my_function(df, b)

Parameterize function name in Python

I have a generic function for which I would like the name to change based on the value of predefined variable. Not sure this is possible in Python:
n = 'abc'
def f{n}(x):
print(x)
f{n}(3)
In the above, the function name will end up becoming "fabc"?
It is possible using a code-generation + exec pattern. It is also possible by instantiating a types.FunctionType instance directly. But a much simpler solution would be to leave the generic name, and then inject an alias (another reference to the same function object) for the dynamic name into whichever namespace you want.
>>> def generic_function(x):
... print(x ** 2)
...
>>> dynamic_name = "func_abc"
>>> globals()[dynamic_name] = generic_function
>>> func_abc(3)
9
To inject in some other module namespace that would be a setattr call:
setattr(other_mod, dynamic_name, generic_function)
You could also rewrite the function's __name__ attribute if you wanted to, but there's probably not much point.
You could do it with something like the below:
def f(n):
exec(f"def f{n}(x): print(x)")
return eval(f"f{n}")

Where are user defined functions stored?

I want to make a sort of help() function for my module. My idea is to have something like module.help() that just prints out the __doc__ of my functions. My first approach was just to hardcode them and then iterate over them, but I feel there has to be a better way to do so. I looked through the docs for a reference as to where they are stored but couldn't find any. What I want is the python equivalent to this but for function names. I would appreciate if anyone could help me out. Thanks!
Edit: Ok so as of now the functions I have are:
BoyleGraph
Boyle_Resolve
Boyle_k
Boyle_k_solve
GayLussacGraph
GayLussac_Resolve
`
and what I have tried so far is:
funcs = list()
for f in dir():
funcs.append(f)
def helper():
for f in funcs[:-13]:
print(help(f))
and this returns something like (redacted):
No Python documentation found for 'GayLussac_Resolve'.
Use help() to get the interactive help utility.
Use help(str) for help on the str class.
Now using:
def helper():
for f in funcs[:-13]:
print(f)
will give me:
BoyleGraph
Boyle_Resolve
Boyle_k
Boyle_k_solve
GayLussacGraph
GayLussac_Resolve
but doing:
def helper():
for f in funcs[:-13]:
print(f, '\n', '#' * 50)
print(f.__doc__)
gives me (redacted):
GayLussac_Resolve
##################################################
str(object='') -> str
str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or
errors is specified, then the object must expose a data buffer
that will be decoded using the given encoding and error handler.
Otherwise, returns the result of object.__str__() (if defined)
or repr(object).
encoding defaults to sys.getdefaultencoding().
errors defaults to 'strict'.
which is the __doc__ of str() which is not even in the funcs list. I feel I'm so close yet so far.
PS: I know the funcs definition looks sloppy but when I try to assign directly or use list comprehensions I only get the first element of dir()'s output
dir() gets you a list of names, not objects. You could use the values of globals() instead, but you would need to filter out special names like __builtins__ and imports. Instead, just use help(module). It does everything you want, automatically.

import and rename functions from a folder - Python 3 [duplicate]

I would like to import all methods from a module with altered names.
For instance, instead of
from module import repetitive_methodA as methodA, \
repetitive_Class1 as Class1, \
repetitive_instance4 as instance4
I'd prefer something along the lines of
from module import * as *-without-"repetitive_"
this is a rephrasing of this clumsy unanswered question, I have not been able to find a solution or similar questions yet.
You can do it this way:
import module
import inspect
for (k,v) in inspect.getmembers(module):
if k.startswith('repetitive_'):
globals()[k.partition("_")[2]] = v
Edit in response to the comment "how is this answer intended to be used?"
Suppose module looks like this:
# module
def repetitive_A():
print ("This is repetitive_A")
def repetitive_B():
print ("This is repetitive_B")
Then after running the rename loop, this code:
A()
B()
produces this output:
This is repetitive_A
This is repetitive_B
What I would do, creating a work-around...
Including you have a file named some_file.py in the current directory, which is composed of...
# some_file.py
def rep_a():
return 1
def rep_b():
return 2
def rep_c():
return 3
When you import something, you create an object on which you call methods. These methods are the classes, variables, functions of your file.
In order to get what you want, I thought It'd be a great idea to just add a new object, containing the original functions you wanted to rename. The function redirect_function() takes an object as first parameter, and will iterate through the methods (in short, which are the functions of your file) of this object : it will, then, create another object which will contain the pointer of the function you wanted to rename at first.
tl;dr : this function will create another object which contains the original function, but the original name of the function will also remain.
See example below. :)
def redirect_function(file_import, suffixe = 'rep_'):
# Lists your functions and method of your file import.
objects = dir(file_import)
for index in range(len(objects)):
# If it begins with the suffixe, create another object that contains our original function.
if objects[index][0:len(suffixe)] == suffixe:
func = eval("file_import.{}".format(objects[index]))
setattr(file_import, objects[index][len(suffixe):], func)
if __name__ == '__main__':
import some_file
redirect_function(some_file)
print some_file.rep_a(), some_file.rep_b(), some_file.rep_c()
print some_file.a(), some_file.b(), some_file.c()
This outputs...
1 2 3
1 2 3

python import as a variable name

I wanted to use import with a variable name. For example I wanted to do something like this
from var import my_class
I went through pythons documentation, but seems thats a little confusing. Also I seen some other posting on stack overflow that give the example of something like this
import importlib
my_module = importlib.import_module("var, my_class)
This second example does work to a certain extent. The only issue I see here var is imported but I don't see the attributes of my_class in python's namespace. How would I equate this to my original example of
from var import my_class
Here's how to use importlib (there is no need for the second parameter):
var = importlib.import_module("var")
# Now, you can use the content of the module:
var.my_class()
There is no direct programmable equivalent for from var import my_class.
Note: As #DYZ points out in the comments, this way of solving this is not recommended in favor of importlib. Leaving it here for the sake of another working solution, but the Python docs advise "Direct use of import() is also discouraged in favor of importlib.import_module()."
Do you mean that you want to import a module whose name is defined by a variable? If so, you can use the __import__ method. For example:
>>> import os
>>> os.getcwd()
'/Users/christophershroba'
>>>
>>> name_to_import = "os"
>>> variable_module = __import__(name_to_import)
>>> variable_module.getcwd()
'/Users/christophershroba'
If you also want to call a variable method of that variable module you could use the __getattribute__ method on the module to get the function, and then call it with () as normal. The line below marked "See note" is not necessary, I just include it to show that the __getattribute__ method is returning a function.
>>> name_to_import = "os"
>>> method_to_call = "getcwd"
>>> variable_module = __import__(name_to_import)
>>> variable_module.__getattribute__(method_to_call) # See note
<built-in function getcwd>
>>> variable_module.__getattribute__(method_to_call)()
'/Users/christophershroba'
More documentation available for Python 3 here or Python2 here.

Resources