Python dispatcher and scenario-specific functions and sub-functions - python

I am trying to write several functions in Python (dispatcher + scenario-specific functions and sub-functions) as follows:
def dispatcher(event):
if event['name'] == 'func_a':
return func_a(event['data'])
# several elif statements here
elif event['name'] == 'func_n':
return func_n(event['data'])
def func_a(data):
""" multi-scenario function returning dict"""
# Scenario A
if data['certain_param'] == 'certain value':
# do something
# that takes several lines of code
return {'result': 'scenario A'}
# Scenario B
elif data['certain_param'] == 'another value':
# do something else
# that takes several lines of code
return {'result': 'scenario B'}
# some other elif scenarios go here
return {'result': 'Fail'}
# func_b(), func_c(), .... go here (similar to func_a())
def func_n(data):
""" similar logic to funcs a, b, ...."""
pass
I want to break a very long func_a() into several sub-functions (one for each scenario). Here are 2 options:
# makes 2 calls to each scenario sub-function (not ideal)
def func_a(data):
""" same func_a() above"""
# Scenario A
if func_a_scenario_a(data):
return func_a_scenario_a(data)
# other elifs
# Scenario N
elif func_a_scenario_n(data):
return func_a_scenario_n(data)
Yet another way to write func_a() is:
# Not very Pythonic
def func_a(data):
result = func_a_scenario_a(data)
if result:
return result
result = func_a_scenario_b(data)
if result:
return result
# repeat for every scenario
What is (are) better ways to do the above? maybe using eval('some_func()')? or something else? Thanks.

You can create a decorator which can then determine what to pass to its wrapped function. The decorator can store a dictionary with the function name as the key, and an associated value to be passed to the function with the same name as the key:
def dispatcher(f):
registry = {'func_a':"arbitrary_data", 'func_n':"arbitrary_data_1"}
def wrapper(data):
return f(registry[f.__name__])
return wrapper
#dispatcher
def func_a(data):
#do something with data
return
#dispatcher
def func_n(data):
#do something with data
return
func_a("somedata")
func_n("someotherdata") #functions called be called normally

Related

How to save a list of functions as an object in Python3

I'm working on a filter. For each case, I have a list of functions to process the input data, which differs from case to case.
I want to serialize and save such list of function, so that I can load and use functions for each case. I tried to use pickle to dump the list as a pkl file, but it cannot be load if I delete the definition of functions.
To deliver it more explicitly, it runs like this
def a1(obj):
pass
def a2(obj):
pass
def b1(obj):
pass
def b2(obj):
pass
a_func = [a1, a2]
b_func = [b1, b2]
if obj.flag == 1:
for fun in a_func:
fun(obj)
elif obj.flag == 2:
for fun in b_func:
fun(obj)
and I want to save such a_func and b_func as pkl file or so.
I don't know how to save them as py. I need to deal with more than 100 cases, and each case may need about 10 functions, most of which are in common. I don't want type them manually.
Here you can try like this, using exec() and store string names of the functions in lists:
class obj:
def __init__(self):
self.flag = 1
def a1(obj):
pass
def a2(obj):
pass
def b1(obj):
pass
def b2(obj):
pass
a_func = ['a1', 'a2']
b_func = ['b1', 'b2']
objg = obj()
if objg.flag == 1:
for fun in a_func:
exec('{x}(objg)'.format(x=fun))
elif objg.flag == 2:
for fun in b_func:
exec('{x}(objg)'.format(x=fun))
You can define functions that use functions such as:
def a1(obj):
result = obj+1
return result
def a2(obj):
result = obj*3
return result
def a1_a2(obj):
result1 = a1(obj)
result2 = a2(result1)
return result2
then calling a1_a2 will do a1 first and apply a2 to the result of a1.
If you save the code to say filters.py you can do in any other programm in the same directory:
from filters import a1_a2

How do I approach this python test?

I have a function inside a class, that calls other functions and does some stuff until it obtains two variables, A and B:
Class NumberLogic:
def compare():
#do stuff_
A=#do stuff__
B=#do stuff___
if A<B:
return 1
else:
return 2
I would like to test this function compare() but give values directly from A and B so only the if condition is tested, I am not sure if this is possible and the rest of the code can be mocked so when I call someting like
assert 1 == NumberLogic.compare()
You could rewrite your code like this:
Class NumberLogic:
def compare(self):
A = self._get_A()
B = self._get_B()
return self._compare(A, B)
def _get_A(self):
# do stuff
return A
def _get_B(self):
# do stuff
return B
def _compare(self, A, B):
if A<B:
return 1
else:
return 2
This way you can write your code to check only the _compare
Note: Starting a function with an underscore signifies it's an internal method only used by the function itself.
You could also write:
def _compare(self, A, B):
if A<B:
return 1
return 2
Which is the same thing

Way to call method depending on variable?

I already have a working, but in my oppinion not beautiful solution for a part of a long script.
My script uses several similar methods, that differ too much to combine. However I came to a point where I want to call one of those methods depending on a given variable.
The names of the methods are build up like this:
def read_A():
#doing sth
def read_B():
#doing sth else
def read_C():
etc.
Now I would like to call those methods in a pythonic way, when the letter ('A', 'B', 'C', ...) is given as a variable.
A non-pythonic solution would be:
if var == "A":
read_A()
if var == "B":
read_B() .....
And I hope to find a more pythonic solution that allows me to call those methods simply like this:
var = "A"
read_var() #This would call the method 'read_A()'
Please mind that the code above is only an image of what I hope to do, it is not a working example!
I dont see an issue with just using
if var == 'A':
read_a()
but if you'd like to make it more 'pythonic' you could map your variables to the methods using a dictionary and execute it based on the result of what's stored in your dictionary:
def read_a():
print('Running method read_a')
def read_b():
print('Running method read_b')
switch = {'A': read_a, 'B': read_b}
case = 'A'
switch.get(case)()
>> 'Running method read_a'
case = 'B'
switch.get(case)()
>> 'Running method read_b'
Stick the functions in a dictionary, and use the dictionary to dispatch to the chosen one:
read = {'A': read_a, 'B': read_b, 'C': read_c}
choice = 'A'
read[choice]()
On that last line, you lookup the function that matches your choice in the dictionary, then you immediately call it.
you may use next construction:
def execute_func(x):
return {
'0':read_A(),
'1':read_B()
}[x]
Set your variables instead '0' and '1' or more and pass your params to execute_func().
You can do it in this way if you have many functions named read_a, read_b...etc, instead of writing huge dictionary.
def read_a():
print('Running method read_a')
def read_b():
print('Running method read_b')
def read_c():
print("running method read_c")
def read_d():
print("running method read_d")
............
............
def read_z():
print("running method read_z")
def _read_var(var):
method = "read_{}".format(var.lower())
try:
eval(method)()
except NameError:
raise NotImplementedError
var = "A"
_read_var(var)# will invoke read_a method
"""
modified from
https://stackoverflow.com/questions/65163600/how-to-call-a-class-method-given-its-name
"""
class MyClass(object):
def __init__(self):
pass
def call_method_by_string(self, method_name):
getattr(self, method_name)() # call local method based on string
def get_year(self):
print("here")
if __name__ == "__main__":
mc = MyClass()
mc.call_method_by_string(method_name="get_year")

Workaround for equality of nested functions

I have a nested function that I'm using as a callback in pyglet:
def get_stop_function(stop_key):
def stop_on_key(symbol, _):
if symbol == getattr(pyglet.window.key, stop_key):
pyglet.app.exit()
return stop_on_key
pyglet.window.set_handler('on_key_press', get_stop_function('ENTER'))
But then I run into problems later when I need to reference the nested function again:
pyglet.window.remove_handler('on_key_press', get_stop_function('ENTER'))
This doesn't work because of the way python treats functions:
my_stop_function = get_stop_function('ENTER')
my_stop_function is get_stop_function('ENTER') # False
my_stop_function == get_stop_function('ENTER') # False
Thanks to two similar questions I understand what is going on but I'm not sure what the workaround is for my case. I'm looking through the pyglet source code and it looks like pyglet uses equality to find the handler to remove.
So my final question is: how can I override the inner function's __eq__ method (or some other dunder) so that identical nested functions will be equal?
(Another workaround would be to store a reference to the function myself, but that is duplicating pyglet's job, will get messy with many callbacks, and anyways I'm curious about this question!)
Edit: actually, in the questions I linked above, it's explained that methods have value equality but not reference equality. With nested functions, you don't even get value equality, which is all I need.
Edit2: I will probably accept Bi Rico's answer, but does anyone know why the following doesn't work:
def get_stop_function(stop_key):
def stop_on_key(symbol, _):
if symbol == getattr(pyglet.window.key, stop_key):
pyglet.app.exit()
stop_on_key.__name__ = '__stop_on_' + stop_key + '__'
stop_on_key.__eq__ = lambda x: x.__name__ == '__stop_on_' + stop_key + '__'
return stop_on_key
get_stop_function('ENTER') == get_stop_function('ENTER') # False
get_stop_function('ENTER').__eq__(get_stop_function('ENTER')) # True
You could create a class for your stop functions and define your own comparison method.
class StopFunction(object):
def __init__(self, stop_key):
self.stop_key = stop_key
def __call__(self, symbol, _):
if symbol == getattr(pyglet.window.key, self.stop_key):
pyglet.app.exit()
def __eq__(self, other):
try:
return self.stop_key == other.stop_key
except AttributeError:
return False
StopFunciton('ENTER') == StopFunciton('ENTER')
# True
StopFunciton('ENTER') == StopFunciton('FOO')
# False
the solution is to keep a dictionary containing the generated functions around,
so that when you make the second call, you get the same object as in the first call.
That is, simply build some memoization logic, or use one of the libraries
existing with memoizing decorators:
ALL_FUNCTIONS = {}
def get_stop_function(stop_key):
if not stop_key in ALL_FUNCTIONS:
def stop_on_key(symbol, _):
if symbol == getattr(pyglet.window.key, stop_key):
pyglet.app.exit()
ALL_FUNCTIONS[stop_key] = stop_on_key
else:
stop_on_key = ALL_FUNCTIONS[stop_key]
return stop_on_key
You can generalize Bi Rico's solution to allow wrapping any functions up with some particular equality function pretty easily.
The first problem is defining what the equality function should check. I'm guessing for this case, you want the code to be identical (meaning functions created from the same def statement will be equal, but two functions created from character-for-character copies of the def statement will not), and the closures to be equal (meaning that if you call get_stop_function with two equal but non-identical stop_keys the functions will be equal), and nothing else to be relevant. But that's just a guess, and there are many other possibilities.
Then you just wrap a function the same way you'd wrap any other kind of object; just make sure __call__ is one of the things you delegate:
class EqualFunction(object):
def __init__(self, f):
self.f = f
def __eq__(self, other):
return (self.__code__ == other.__code__ and
all(x.cell_contents == y.cell_contents
for x, y in zip(self.__closure__, other.__closure__)))
def __getattr__(self, attr):
return getattr(self.f, attr)
def __call__(self, *args, **kwargs):
return self.f(*args, **kwargs)
If you want to support other dunder methods that aren't required to go through getattr (I don't think any of them are critical for functions, but I could be wrong…), either do it explicitly (as with __call__) or loop over them and add a generic wrapper to the type for each one.
To use the wrapper:
def make_f(i):
def f():
return i
return EqualFunction(f)
f1 = f(0)
f2 = f(0.0)
assert f1 == f2
Or, notice that EqualFunction actually works as a decorator, which may be more readable.
So, for your code:
def get_stop_function(stop_key):
#EqualFunction
def stop_on_key(symbol, _):
if symbol == getattr(pyglet.window.key, stop_key):
pyglet.app.exit()
return stop_on_key

How can I refer to a function not by name in its definition in python?

I am maintaining a little library of useful functions for interacting with my company's APIs and I have come across (what I think is) a neat question that I can't find the answer to.
I frequently have to request large amounts of data from an API, so I do something like:
class Client(object):
def __init__(self):
self.data = []
def get_data(self, offset = 0):
done = False
while not done:
data = get_more_starting_at(offset)
self.data.extend(data)
offset += 1
if not data:
done = True
This works fine and allows me to restart the retrieval where I left off if something goes horribly wrong. However, since python functions are just regular objects, we can do stuff like:
def yo():
yo.hi = "yo!"
return None
and then we can interrogate yo about its properties later, like:
yo.hi => "yo!"
my question is: Can I rewrite my class-based example to pin the data to the function itself, without referring to the function by name. I know I can do this by:
def get_data(offset=0):
done = False
get_data.data = []
while not done:
data = get_more_starting_from(offset)
get_data.data.extend(data)
offset += 1
if not data:
done = True
return get_data.data
but I would like to do something like:
def get_data(offset=0):
done = False
self.data = [] # <===== this is the bit I can't figure out
while not done:
data = get_more_starting_from(offset)
self.data.extend(data) # <====== also this!
offset += 1
if not data:
done = True
return self.data # <======== want to refer to the "current" object
Is it possible to refer to the "current" object by anything other than its name?
Something like "this", "self", or "memememe!" is what I'm looking for.
I don't understand why you want to do this, but it's what a fixed point combinator allows you to do:
import functools
def Y(f):
#functools.wraps(f)
def Yf(*args):
return inner(*args)
inner = f(Yf)
return Yf
#Y
def get_data(f):
def inner_get_data(*args):
# This is your real get data function
# define it as normal
# but just refer to it as 'f' inside itself
print 'setting get_data.foo to', args
f.foo = args
return inner_get_data
get_data(1, 2, 3)
print get_data.foo
So you call get_data as normal, and it "magically" knows that f means itself.
You could do this, but (a) the data is not per-function-invocation, but per function (b) it's much easier to achieve this sort of thing with a class.
If you had to do it, you might do something like this:
def ybother(a,b,c,yrselflambda = lambda: ybother):
yrself = yrselflambda()
#other stuff
The lambda is necessary, because you need to delay evaluation of the term ybother until something has been bound to it.
Alternatively, and increasingly pointlessly:
from functools import partial
def ybother(a,b,c,yrself=None):
#whatever
yrself.data = [] # this will blow up if the default argument is used
#more stuff
bothered = partial(ybother, yrself=ybother)
Or:
def unbothered(a,b,c):
def inbothered(yrself):
#whatever
yrself.data = []
return inbothered, inbothered(inbothered)
This last version gives you a different function object each time, which you might like.
There are almost certainly introspective tricks to do this, but they are even less worthwhile.
Not sure what doing it like this gains you, but what about using a decorator.
import functools
def add_self(f):
#functools.wraps(f)
def wrapper(*args,**kwargs):
if not getattr(f, 'content', None):
f.content = []
return f(f, *args, **kwargs)
return wrapper
#add_self
def example(self, arg1):
self.content.append(arg1)
print self.content
example(1)
example(2)
example(3)
OUTPUT
[1]
[1, 2]
[1, 2, 3]

Categories

Resources