How to combine for_each and if_ - python

I am starting to learn liteflow and wonder if it is possible to somehow combine for_each and if_. I tried the following:
from liteflow.core import *
class Hello(StepBody):
def run(self, context: StepExecutionContext) -> ExecutionResult:
print("Hello")
return ExecutionResult.next()
class DoStuff(StepBody):
def run(self, context: StepExecutionContext) -> ExecutionResult:
print(f"doing stuff...{context.execution_pointer.context_item}")
return ExecutionResult.next()
class Goodbye(StepBody):
def run(self, context: StepExecutionContext) -> ExecutionResult:
print("Goodbye")
return ExecutionResult.next()
class MyWorkflow(Workflow):
def id(self):
return "MyWorkflow"
def version(self):
return 1
def build(self, builder: WorkflowBuilder):
builder\
.start_with(Hello)\
.for_each(lambda data, context: ["abc", "def", "xyz"])\
.if_(lambda d, c: not d.startswith("x"))\
.do(lambda x: x.start_with(DoStuff))\
.then(Goodbye)
host = configure_workflow_host()
host.register_workflow(MyWorkflow())
host.start()
wid = host.start_workflow("MyWorkflow", 1, None)
input()
host.stop()
This is not working ('NoneType' object has no attribute 'startswith'), if I replace the condition with something like 0 < 1 DoStuff is exceuted once instead of three times without the if_ and even prints the "wrong" output.
I know that I can eliminate the if_ by using a LC in for_each in this simple example ([x for x in ["abc", "def", "xyz"] if not x.startswith("x")]), but imagine a more complex workflow.
So how do I combine for_each and if_ in a way to get access to the loop variable from for_each in if_ and also pass the correct context to do? Or is this impossible and I have to check the condition in the run method of my steps?

Related

Python Typing: Make python func return value type based on input func arguments

I have a func, that form a list of certain class instances, lets say it output type will be list[SomeClass].
The output class type may differ depending on data (e.g. it may be list[ClassA], list[ClassB], list[ClassC], etc.).
I'm trying to pass that list and a lambda function as an arguments into another class . The purpose of the latter class is to divide it's list argument into two separate lists based on that lambda function.
So basically what I need is:
def func_A(cls_instance: some_cls) -> list[some_cls]:
.....
.....
return list[some_cls]
class DividerClass()
def __init__(list_of_classes: list[Object], func: Callable):
self.list_of_classes = list_of_classes
self.result_list_1 = []
self.result_list_2 = []
def divide():
for item in self.list_of_classes:
if func(item):
self.result_list_1.append(item)
else:
self.result_list_2.append(item)
return self.result_list_1, self.result_list_2
if __name__ == '__main__':
list_1 = func_A(SomeClass()) -> list[SomeClass]
list_2 = func_A(YetAnotherClass()) -> list[YetAnotherClass]
result_1_a, result_1_b = DividerClass(list_1, lambda_func).divide() -> tuple[list[SomeClass],list[SomeClass]]
resule_2_a, result_2_b = DividerClass(list_2, lambda_func).divide() -> tuple[list[YetAnotherClass],list[YetAnotherClass]]
But instead of getting output like:
-> tuple[list[SomeClass],list[SomeClass]]
-> tuple[list[YetAnotherClass],list[YetAnotherClass]]
I've got output like this:
-> tuple[list, list]
-> tuple[list, list]
So the question is how to make compiler/IDE be aware of type of class inside the list and output the classList type based on input argument?
Use typing.Generic to specify that an arbitrary, but fixed, type will be used in the various signatures.
Something like
from typing import TypeVar, Tuple, Generic
T = TypeVar('T')
def func_A(cls_instance: T) -> list[T]:
...
class DividerClass(Generic[T])
def __init__(self, list_of_classes: list[T], func: Callable[[T],list[T]]):
self.list_of_classes = list_of_classes
self.result_list_1 = []
self.result_list_2 = []
self.func = func
def divide(self) -> Tuple[list[T], list[T]]:
for item in self.list_of_classes:
if self.func(item):
self.result_list_1.append(item)
else:
self.result_list_2.append(item)
return self.result_list_1, self.result_list_2

How to print the for loop in a class object?

Hi I am learning about OOP and classes and have some confusion regarding the implementation of classes. Below, I have two sets of identical codes with slight differences in the way I am trying to run them after defining the methods in the class. I am just unsure as to why the first code runs and the second one doesnt as I feel like I am doing the same thing? Also, upon running the first code I get 'None' after the loop has finished, any ideas why that takes place? In addition to this, I know that there are iterators that you can use but just wondering if the method used below to loop through stuff is incorrect or problematic?
class i:
def __init__(self,number):
self.number=number
def fun(self):
for i in range(self.number):
print(i)
kj=i(9)
print(kj.fun())
class i:
def __init__(self,number):
self.number=number
def fun(self):
for i in range(self.number):
print(i)
kj=i()
print(kj.fun(9))
In python, class names are typically capitalized. This avoids the problem here where you define a class with the same name are your index variable.
Also, if you want to print a result of a method, then have the method return a value rather than having it print each value.
Putting these concepts together, I would change
class i:
def __init__(self, number):
self.number = number
def fun(self):
for i in range(self.number):
print(i)
kj=i(9)
print(kj.fun())
to
class I:
def __init__(self, number):
self.number = number
def fun(self, number=None):
if not number:
number = self.number
return list(range(number))
kj = I(9)
numbers = kj.fun()
# if you want to print the list
print(numbers)
# if you want to print individual values
print(*numbers)
# if you want to print one number per line
print('\n'.join(numbers))
The following code illustrates the syntax better with type hint:
class i:
def __init__(self,number: int) -> "i":
self.number=number
def fun(self) -> None:
for i in range(self.number):
print(f"fun - i")
kj=i(9)
print(kj.fun())
The output
-> fun - 0
-> fun - 1
-> fun - 2
-> fun - 3
-> fun - 4
-> fun - 5
-> fun - 6
-> fun - 7
-> fun - 8
-> None
We see that the output 1 - 8 is from within the function
And None is because the fun() method has None return by default.
The second code will have the following error
TypeError: __init__() missing 1 required positional argument: 'number'
because to initialise the class it expects the number input. The fact that you want to pass the parameter on the 'fun' method call, it means to expect the number on class initialisation is redundant;
One can do the following instead:
class i:
def __init__(self):
pass
def fun(self, number: int):
for i in range(number):
print(i)
kj = i()
print(kj.fun(9))

Is there a Python structure that combines `while` and `with`?

I have some code that looks like this.
condition = <expression>
while condition:
<some code>
I would like to be able to write that without having to write a separate statement to create the condition. E.g.,
while <create_condition(<expression>)>:
<some code>
Here are two possibilities that don't work, but that would scratch my itch.
with <expression> as condition:
<some code>
The problem with that is that it doesn't loop. If I embed a while inside the with I'm back where I started.
Define my own function to do this.
def looping_with(<expression>, <some code>):
<define looping_with>
The problem with this is that if <some code> is passed as a lambda expression it is limited to a single expression. None of the workarounds I've seen are attractive.
If <some code> is passed as an actual def one gets a syntax error. You can't pass a function definition as an argument to another function.
One could define the function elsewhere and then pass the function. But the point of with, while, and lambda is that the code itself, not a reference to the code, is embedded in context. (The original version of my code, which is not terrible, is better than that.)
Any suggestions would be appreciated.
UPDATE: (As Dave Beazley likes to say: You're going to hate this.)
I hesitate to offer this example, but this is something like what I'm trying to do.
class Container:
def __init__(self):
self.value = None
class Get_Next:
def __init__(self, gen):
self.gen = gen
def __call__(self, limit, container):
self.runnable_gen = self.gen(limit, container)
return self
def get_next(self):
try:
next(self.runnable_gen)
return True
except StopIteration:
return False
#Get_Next
def a_generator(limit, container):
i = 0
while i < limit:
container.value = i
yield
i += 1
container = Container()
gen = a_generator(5, container)
while gen.get_next():
print(container.value)
print('Done')
When run, the output is:
0
1
2
3
4
Done
P.S. Lest you think this is too far out, there is a very easy way to produce the same result. Remove the decorator from a_generator and then run:
for _ in a_generator(5, container):
print(container.value)
print('Done')
The result is the same.
The problem is that for _ in <something> is too ugly for me.
So, what I'm really looking for is a way to get the functionality of for _ in <something> with nicer syntax. The syntax should (a) indicate that we are establishing a context and (b) looping within that context. Hence the request for a combination of with and while.
You could a context manager class that would help in doing something like that:
class Condition:
def __init__(self, cond):
self.cond = cond
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
pass
def __call__(self, *args, **kwargs):
return self.cond(*args, **kwargs)
with Condition(lambda x: x != 3) as condition:
a = 0
while condition(a):
print('a:', a)
a += 1
Output:
a: 0
a: 1
a: 2

Using Python decorators to enable/disable certain parts of a program

I have a bunch of scripts that are essentially data preparation steps, to set up data for simulation models. I very often want to run only parts of it, say either 'phase1' or 'phase2', but most 'phases' are more than one line, so commenting out isn't very convenient. So I generally do:
# Phase 1
if True:
do_step_1('high')
do_step_2()
for i in range(1,10):
do_step_3()
#Phase 2
if True:
do_step_1('low')
do_something_else()
And then change True to False as needed.
Now, this is quite cumbersome. Sometimes, phases depend on each other (so when I run 3 I also need to run 1), they are nested, etc.
What I want to do, is have some way to pass an argument to my script that would run one or more 'phases', and I need some way to 'mark' certain functions, blocks of code or scopes as being part of that 'phase'. A certain chunk of code can be part of multiple phases, so that when there are chunks B and C that depend on chunk A, I could mark A as being part of 'phase1' and 'phase2' and then when I run phase1, it would run chunk A and chunkB, and for phase2, chunk A and chunk C. I hope this still makes sense.
So I was thinking that decorators would be perfect to do this, so that I could do (conceptually) something like
#partOfAPhase("phase1", "phase2")
def f1():
pass
and then somehow, I pass a list of 'phases' to run to my program (either from the command line, or by setting it as a configuration variable somewhere) and when my program is run, it only executes the functions that were decorated as being part of one of the phases specified to be run.
So, what I think I need is a generic decorator that can be applied to either functions or member functions which accept any number of arguments, and I need to be able to pass a list of 'tags' to the decorator itself. Then inside the decorator, I need to check (when the original function or member is called) whether the tags of that decorator exist in a global (maybe class static?) list of tags to run.
I looked at https://gist.github.com/Zearin/2f40b7b9cfc51132851a and it seems, at the very end, to do more or less what I want, yet I can't quite puzzle all pieces together to do what I want. More specifically I don't really understand the double nested decorator generator and whether I would need two functions or just one to implement this, and also how I'd get access to the argument that are passed to the decorator (i.e. the phases to run).
Not sure if this covers your needs but here is a quick and dirty proof of concept:
# This first part could go in its own module or a class or whatever
_program = []
def partOfPhase(*phases):
def decorator(fn):
_program.append((fn, tuple(phases)))
return fn
return decorator
def partOfProgram(fn):
_program.append((fn, None))
return fn
def runProgram(phase):
for fn, fn_phases in _program:
if fn_phases is None or any(p in fn_phases for p in phases):
fn()
# This is the actual script
import sys
#partOfPhase('phase1')
def step1():
print('step1')
#partOfPhase('phase1', 'phase2')
def step2():
print('step2')
#partOfProgram
def step3():
print('step3')
#partOfPhase('phase2')
def step4():
print('step4')
if __name__ == '__main__':
phases = sys.argv[1:]
runProgram(phases)
If you save it as phases.py, for example, you would get:
> python phases.py
step3
> python phases.py phase1
step1
step2
step3
> python phases.py phase2
step3
step4
> python phases.py phase1 phase2
step1
step2
step3
step4
EDIT
I think this is probably more like what you were thinking, functions that become disabled depending on the phase:
# This first part could go in its own module or a class or whatever
from functools import wraps
_enabledPhases = []
def enablePhase(*phases):
_enabledPhases.extend(phases)
def partOfPhase(*phases):
def decorator(fn):
#wraps(fn) # Just "cosmetic" wrapping
def decorated(*args, **kwargs):
if any(p in phases for p in _enabledPhases):
fn(*args, **kwargs)
return decorated
return decorator
# This is the actual script
import sys
#partOfPhase('phase1')
def step1():
print('step1')
#partOfPhase('phase1', 'phase2')
def step2():
print('step2')
def step3():
print('step3')
#partOfPhase('phase2')
def step4():
print('step4')
if __name__ == '__main__':
phases = sys.argv[1:]
enablePhase(*phases)
step1()
step2()
step3()
step4()
Here's what I ended up with, after finding out that the method as it is presented in the link is very convoluted and it's much easier to do this with a callable decorator object. This works on both free standing functions and methods, that take any number of arguments (with some simple tests that just print easily visually verified results):
import functools
import sys
class runConditional(object):
def __init__(self, datasets):
self.datasets = datasets
def __call__(self, func):
def wrapped_f(*args, **kwargs):
global to_run
for d in self.datasets:
if d in to_run:
sys.stdout.write(" 1")
func(*args, **kwargs)
return
sys.stdout.write(" 0")
return wrapped_f
#runConditional([1])
def fun1():
pass
#runConditional([2])
def fun2():
pass
#runConditional([1,2,3])
def fun3(arg1, arg2):
pass
def fun_always():
sys.stdout.write(" 1")
pass
#runConditional([])
def fun_never():
pass
class test():
#runConditional([1])
def m1(self):
pass
#runConditional([2])
def m2(self):
pass
#runConditional([1,2,3])
def m3(self, arg1):
pass
def m_always(self):
sys.stdout.write(" 1")
pass
#runConditional([])
def m_never(self):
pass
def run_test(funcs_to_run, expected):
global to_run
t = test()
funcs = [ fun1, fun2, functools.partial(fun3, "123", "meh"), fun_always, fun_never,
t.m1, t.m2, functools.partial(t.m3, "321"), t.m_always, t.m_never ]
to_run = funcs_to_run
print "Expected: " + " ".join(map(str, expected))
sys.stdout.write("Actual: ")
for f in funcs:
f()
print ""
print ""
run_test([2], [ 0, 1, 1, 1, 0, 0, 1, 1, 1, 0 ])
run_test([1], [ 1, 0, 1, 1, 0, 1, 0, 1, 1, 0 ])
run_test([], [ 0, 0, 0, 1, 0, 0, 0, 0, 1, 0 ])
run_test([1, 2], [ 1, 1, 1, 1, 0, 1, 1, 1, 1, 0 ])

Using a dictionary to select function to execute

I am trying to use functional programming to create a dictionary containing a key and a function to execute:
myDict={}
myItems=("P1","P2","P3",...."Pn")
def myMain(key):
def ExecP1():
pass
def ExecP2():
pass
def ExecP3():
pass
...
def ExecPn():
pass
Now, I have seen a code used to find the defined functions in a module, and I need to do something like this:
for myitem in myItems:
myDict[myitem] = ??? #to dynamically find the corresponding function
So my question is, How do I make a list of all the Exec functions and then assign them to the desired item using the a dictionary? so at the end I will have myDict["P1"]() #this will call ExecP1()
My real problem is that I have tons of those items and I making a library that will handle them so the final user only needs to call myMain("P1")
I think using the inspect module, but I am not so sure how to do it.
My reason to avoid:
def ExecPn():
pass
myDict["Pn"]=ExecPn
is that I have to protect code as I am using it to provide a scripting feature within my application.
Simplify, simplify, simplify:
def p1(args):
whatever
def p2(more args):
whatever
myDict = {
"P1": p1,
"P2": p2,
...
"Pn": pn
}
def myMain(name):
myDict[name]()
That's all you need.
You might consider the use of dict.get with a callable default if name refers to an invalid function—
def myMain(name):
myDict.get(name, lambda: 'Invalid')()
(Picked this neat trick up from Martijn Pieters)
Simplify, simplify, simplify + DRY:
tasks = {}
task = lambda f: tasks.setdefault(f.__name__, f)
#task
def p1():
whatever
#task
def p2():
whatever
def my_main(key):
tasks[key]()
Not proud of it, but:
def myMain(key):
def ExecP1():
pass
def ExecP2():
pass
def ExecP3():
pass
def ExecPn():
pass
locals()['Exec' + key]()
I do however recommend that you put those in a module/class whatever, this is truly horrible.
If you are willing to add a decorator for each function, you can define a decorator which adds each function to a dictionary:
def myMain(key):
tasks = {}
def task(task_fn):
tasks[task_fn.__name__] = task_fn
#task
def ExecP1():
print(1)
#task
def ExecP2():
print(2)
#task
def ExecP3():
print(3)
#task
def ExecPn():
print(4)
tasks['Exec' + key]()
Another option is to place all the functions under a class (or in a different module) and use getattr:
def myMain(key):
class Tasks:
def ExecP1():
print(1)
def ExecP2():
print(2)
def ExecP3():
print(3)
def ExecPn():
print(4)
task = getattr(Tasks, 'Exec' + key)
task()
# index dictionary by list of key names
def fn1():
print "One"
def fn2():
print "Two"
def fn3():
print "Three"
fndict = {"A": fn1, "B": fn2, "C": fn3}
keynames = ["A", "B", "C"]
fndict[keynames[1]]()
# keynames[1] = "B", so output of this code is
# Two
You can just use
myDict = {
"P1": (lambda x: function1()),
"P2": (lambda x: function2()),
...,
"Pn": (lambda x: functionn())}
myItems = ["P1", "P2", ..., "Pn"]
for item in myItems:
myDict[item]()
This will call methods from dictionary
This is python switch statement with function calling
Create few modules as per the your requirement.
If want to pass arguments then pass.
Create a dictionary, which will call these modules as per requirement.
def function_1(arg):
print("In function_1")
def function_2(arg):
print("In function_2")
def function_3(fileName):
print("In function_3")
f_title,f_course1,f_course2 = fileName.split('_')
return(f_title,f_course1,f_course2)
def createDictionary():
dict = {
1 : function_1,
2 : function_2,
3 : function_3,
}
return dict
dictionary = createDictionary()
dictionary[3](Argument)#pass any key value to call the method
#!/usr/bin/python
def thing_a(arg=None):
print 'thing_a', arg
def thing_b(arg=None):
print 'thing_b', arg
ghetto_switch_statement = {
'do_thing_a': thing_a,
'do_thing_b': thing_b
}
ghetto_switch_statement['do_thing_a']("It's lovely being an A")
ghetto_switch_statement['do_thing_b']("Being a B isn't too shabby either")
print "Available methods are: ", ghetto_switch_statement.keys()
Often classes are used to enclose methods and following is the extension for answers above with default method in case the method is not found.
class P:
def p1(self):
print('Start')
def p2(self):
print('Help')
def ps(self):
print('Settings')
def d(self):
print('Default function')
myDict = {
"start": p1,
"help": p2,
"settings": ps
}
def call_it(self):
name = 'start'
f = lambda self, x : self.myDict.get(x, lambda x : self.d())(self)
f(self, name)
p = P()
p.call_it()
class CallByName():
def method1(self):
pass
def method2(self):
pass
def method3(self):
pass
def get_method(self, method_name):
method = getattr(self, method_name)
return method()
callbyname = CallByName()
method1 = callbyname.get_method(method_name)
```
def p1( ):
print("in p1")
def p2():
print("in p2")
myDict={
"P1": p1,
"P2": p2
}
name=input("enter P1 or P2")
myDictname
You are wasting your time:
You are about to write a lot of useless code and introduce new bugs.
To execute the function, your user will need to know the P1 name anyway.
Etc., etc., etc.
Just put all your functions in the .py file:
# my_module.py
def f1():
pass
def f2():
pass
def f3():
pass
And use them like this:
import my_module
my_module.f1()
my_module.f2()
my_module.f3()
or:
from my_module import f1
from my_module import f2
from my_module import f3
f1()
f2()
f3()
This should be enough for starters.

Categories

Resources