Say I have a file functions.py containing
def some_function():
return "something"
def some_other_function():
return "something else"
I'm trying to create a dictionary in another file, load_functions.py, with keys being the function-names from functions.py and the items being the actual function e.g:
import functions
useable_functions = [f for f in dir(functions) if "__" not in f] #Get all functions to be used
function_dict = TO_BE_IMPLEMENTED
print(function_dict)
#{"some_function":some_function,
#"some_other_function":some_other_function}
func = function_dict["some_function"]
func()
# "something"
Is it by all means doable?
Take a look at the inspect module.
Say you have your functions.py module.
To get all functions from it, use this:
import inspect
import functions # your module
elements = inspect.getmembers(functions, inspect.isfunction)
element_dict = dict(elements)
The call will return all the function members of the functions.py module as a list of (name, value) pairs sorted by name. Note it will also include lambdas.
Then, I use dict() to convert the (name, value) pairs to a dict.
https://docs.python.org/3/library/inspect.html
Related
I'm writing a method that takes in a list and returns a dictionary. This method is to be saved in a separate Python file and imported into Main.py
The method that takes in a list calls another method that's meant to update the global dictionary.
global myDict
def addKeyValuePair(listItem):
try:
key = listItem.split(': ')[0].replace('\\','')
value = listItem.split(': ')[1].replace('\\r\\n','').replace('\\','')
myDict.update({key:value})
except:
pass
def makeDict(dataList):
myDict = {}
for listItem in dataList:
addKeyValuePair(listItem)
return(myDict)
From the main method I'm importing the makeDict module and passing it the dataList, but it returns an empty dictionary.
from Toolkit import makeDict
finalDict = makeDict(dataList)
Any idea how this can be done?
For example I have a function like below:
def func(val):
dict = {}
# some logic to fill in dict
dict['a'] = val
Then how can I pytest the the contents of dict? Is it possible?
You can actually replace the dict constructor, for the tested module, if you can change your code slightly. Suppose that your module name is my_module.py and you can make the following changes:
Initialize the dictionary using dict() instead of {}
Rename dict into my_dict (or any other name so it doesn't shadows the builtin dict())
my_module.py would look like so:
def func(val):
my_dict = dict() # instead of dict = {}
# some logic to fill in dict
my_dict['a'] = val
Then, in your test, override the dict constructor which creates new dictionaries and return your dictionary that you can assert later on:
from my_module import func
def test_func(mocker):
my_replaced_dict = {}
mocker.patch("my_module.dict", return_value=my_replaced_dict)
func(20)
assert my_replaced_dict['a'] == 20 # the assert works since func uses our variable
I have 4 python files, the first two is the function itself, the second is functions dictionary, and the third is kind of a 'definition' parser
function_1
def increment(obj):
return obj+1
#another function
function_2
def decrement(obj):
return obj-1
#another function
function_dictionary
import fucntion1
import function2
FUNC_DICT = {
'increment': function1.increment,
'decrement': function2.decrement,
#another function
}
definition_parser
from function_dictionary import FUNC_DICT
def get_definition():
result = {}
for key, value in FUNC_DICT.items():
#check if value is from function_1 or function_2
#result[key] = 'function_1' or 'function_2', depends on its origin
return result
is it possible to compare function import? I tried it with is_in_function_1 = value is in function_1, doesn't work.
if it is not, what are the way around without much repetition?
You can get the module of functions via the __module__ property.
from function_dictionary import FUNC_DICT
def get_definition():
result = {}
for key, value in FUNC_DICT.items():
result[key] = value.__module__
return result
The output would look like the following:
{
'increment': 'function_1',
'decrement': 'function_2'
}
You could use the inspect module like so:
import inspect
print(inspect.getmodule(SequenceMatcher))
for example, if I inspect SequenceMatcher, the output is:
<module 'difflib' from 'C:\ProgramData\Anaconda2\lib\difflib.py'>
So to compare the origin of two functions, you could simply do this:
if inspect.getmodule(increment) == inspect.getmodule(decrement):
do stuff
The globals function returns a dictionary that contains the functions in a module, and the dir function returns a list that contains the names of the functions in a module, but they are in alphabetical order or are in a dictionary.
Is there a way to get the names of all the functions in a module in the order they appear in a file?
Here is my solution. Read in the source file as a string, filter out lines that begin with def, strip leading whitespace and extract the substring between the first space and first left paren.
def extract_fns(filename):
with open(filename) as f:
lines = f.readlines()
return [line.split(' ', 1)[1].split('(')[0] for line in lines
if line.strip().startswith('def')]
When I had a need like this, I used a decorator.
def remember_order(func, counter=[0]):
func._order = counter[0]
counter[0] += 1
return func
#remember_order
def foo():
print "foo"
#remember_order
def bar():
print "bar"
#remember_order
def baz():
print "baz"
Yes, you have to decorate each function individually. Explicit is better than implicit, as they say, and because you are doing something unnatural it's good to call it out as plainly as possible.
Now you want to get all the decorated functions in the order they were defined?
import sys
module = sys.modules[__name__] # get reference to current module
# you could also use a reference to some other module where the functions are
# get the functions in the order defined
funcs = sorted((func for func in
(getattr(module, name) for name in dir(module))
if callable(func) and hasattr(func, "_order")),
key = lambda func: func._order)
# call them in that order
for func in funcs:
func()
But it'd be easier to just give them names in alphabetical order...
My solution was to parse the ast. As it turns out elements in the ast tree are in the order they are parsed. Hence functions are in the order they appear in the file.
import inspect
import ast
def get_function_names_in_order_of_appearence(module_name):
this_source = inspect.getsource(module_name)
tree = ast.parse(this_source)
functions = []
for elem in tree.body:
if type(elem) is ast.FunctionDef:
this_func_name = elem.name
functions.append(this_func_name)
return functions
Assuming the module that is to be analyzed is:
# fancy_module
def z_func(x):
return x+1
def a_func(a, b):
pass
def b_func(mystr, **kw):
pass
Will give:
func_list = get_function_names_in_order_of_appearence(fancy_module)
for func in func_list:
print(func)
# -------
# output:
z_func
a_func
b_func
The advantage is you can add other stuff from the ast tree, like the signatures of the functions.
I have an unknown number of functions in my python script (well, it is known, but not constant) that start with site_...
I was wondering if there's a way to go through all of these functions in some main function that calls for them.
something like:
foreach function_that_has_site_ as coolfunc
if coolfunc(blabla,yada) == true:
return coolfunc(blabla,yada)
so it would go through them all until it gets something that's true.
thanks!
The inspect module, already mentioned in other answers, is especially handy because you get to easily filter the names and values of objects you care about. inspect.getmembers takes two arguments: the object whose members you're exploring, and a predicate (a function returning bool) which will accept (return True for) only the objects you care about.
To get "the object that is this module" you need the following well-known idiom:
import sys
this_module = sys.modules[__name__]
In your predicate, you want to select only objects which are functions and have names that start with site_:
import inspect
def function_that_has_site(f):
return inspect.isfunction(f) and f.__name__.startswith('site_')
With these two items in hand, your loop becomes:
for n, coolfunc in inspect.getmembers(this_module, function_that_has_site):
result = coolfunc(blabla, yada)
if result: return result
I have also split the loop body so that each function is called only once (which both saves time and is a safer approach, avoiding possible side effects)... as well as rewording it in Python;-)
Have you tried using the inspect module?
http://docs.python.org/library/inspect.html
The following will return the methods:
inspect.getmembers
Then you could invoke with:
methodobjToInvoke = getattr(classObj, methodName)
methodobj("arguments")
This method goes through all properties of the current module and executes all functions it finds with a name starting with site_:
import sys
import types
for elm in dir():
f = getattr(sys.modules[__name__], elm)
if isinstance(f, types.FunctionType) and f.__name__[:5] == "site_":
f()
The function-type check is unnecessary if only functions are have names starting with site_.
def run():
for f_name, f in globals().iteritems():
if not f_name.startswith('site_'):
continue
x = f()
if x:
return x
It's best to use a decorator to enumerate the functions you care about:
_funcs = []
def enumfunc(func):
_funcs.append(func)
return func
#enumfunc
def a():
print 'foo'
#enumfunc
def b():
print 'bar'
#enumfunc
def c():
print 'baz'
if __name__ == '__main__':
for f in _funcs:
f()
Try dir(), globals() or locals(). Or inspect module (as mentioned above).
def site_foo():
pass
def site_bar():
pass
for name, f in globals().items():
if name.startswith("site_"):
print name, f()