Python state-machine design - python

Related to this Stack Overflow question (C state-machine design), could you Stack Overflow folks share your Python state-machine design techniques with me (and the community)?
At the moment, I am going for an engine based on the following:
class TrackInfoHandler(object):
def __init__(self):
self._state="begin"
self._acc=""
## ================================== Event callbacks
def startElement(self, name, attrs):
self._dispatch(("startElement", name, attrs))
def characters(self, ch):
self._acc+=ch
def endElement(self, name):
self._dispatch(("endElement", self._acc))
self._acc=""
## ===================================
def _missingState(self, _event):
raise HandlerException("missing state(%s)" % self._state)
def _dispatch(self, event):
methodName="st_"+self._state
getattr(self, methodName, self._missingState)(event)
## =================================== State related callbacks
But I am sure there are tons of ways of going at it while leveraging Python's dynamic nature (e.g. dynamic dispatching).
I am after design techniques for the "engine" that receives the "events" and "dispatches" against those based on the "state" of the machine.

I don't really get the question. The State Design pattern is pretty clear. See the Design Patterns book.
class SuperState( object ):
def someStatefulMethod( self ):
raise NotImplementedError()
def transitionRule( self, input ):
raise NotImplementedError()
class SomeState( SuperState ):
def someStatefulMethod( self ):
actually do something()
def transitionRule( self, input ):
return NextState()
That's pretty common boilerplate, used in Java, C++, Python (and I'm sure other languages, also).
If your state transition rules happen to be trivial, there are some optimizations to push the transition rule itself into the superclass.
Note that we need to have forward references, so we refer to classes by name, and use eval to translate a class name to an actual class. The alternative is to make the transition rules instance variables instead of class variables and then create the instances after all the classes are defined.
class State( object ):
def transitionRule( self, input ):
return eval(self.map[input])()
class S1( State ):
map = { "input": "S2", "other": "S3" }
pass # Overrides to state-specific methods
class S2( State ):
map = { "foo": "S1", "bar": "S2" }
class S3( State ):
map = { "quux": "S1" }
In some cases, your event isn't as simple as testing objects for equality, so a more general transition rule is to use a proper list of function-object pairs.
class State( object ):
def transitionRule( self, input ):
next_states = [ s for f,s in self.map if f(input) ]
assert len(next_states) >= 1, "faulty transition rule"
return eval(next_states[0])()
class S1( State ):
map = [ (lambda x: x == "input", "S2"), (lambda x: x == "other", "S3" ) ]
class S2( State ):
map = [ (lambda x: "bar" <= x <= "foo", "S3"), (lambda x: True, "S1") ]
Since the rules are evaluated sequentially, this allows a "default" rule.

In the April, 2009 issue of Python Magazine, I wrote an article on embedding a State DSL within Python, using pyparsing and imputil. This code would allow you to write the module trafficLight.pystate:
# trafficLight.pystate
# define state machine
statemachine TrafficLight:
Red -> Green
Green -> Yellow
Yellow -> Red
# define some class level constants
Red.carsCanGo = False
Yellow.carsCanGo = True
Green.carsCanGo = True
Red.delay = wait(20)
Yellow.delay = wait(3)
Green.delay = wait(15)
and the DSL compiler would create all the necessary TrafficLight, Red, Yellow, and Green classes, and the proper state transition methods. Code could call these classes using something like this:
import statemachine
import trafficLight
tl = trafficLight.Red()
for i in range(6):
print tl, "GO" if tl.carsCanGo else "STOP"
tl.delay()
tl = tl.next_state()
(Unfortunately, imputil has been dropped in Python 3.)

There is this design pattern for using decorators to implement state machines. From the description on the page:
Decorators are used to specify which methods are the event handlers for the class.
There is example code on the page as well (it is quite long so I won't paste it here).

I also was not happy with the current options for state_machines so I wrote the state_machine library.
You can install it by pip install state_machine and use it like so:
#acts_as_state_machine
class Person():
name = 'Billy'
sleeping = State(initial=True)
running = State()
cleaning = State()
run = Event(from_states=sleeping, to_state=running)
cleanup = Event(from_states=running, to_state=cleaning)
sleep = Event(from_states=(running, cleaning), to_state=sleeping)
#before('sleep')
def do_one_thing(self):
print "{} is sleepy".format(self.name)
#before('sleep')
def do_another_thing(self):
print "{} is REALLY sleepy".format(self.name)
#after('sleep')
def snore(self):
print "Zzzzzzzzzzzz"
#after('sleep')
def big_snore(self):
print "Zzzzzzzzzzzzzzzzzzzzzz"
person = Person()
print person.current_state == person.sleeping # True
print person.is_sleeping # True
print person.is_running # False
person.run()
print person.is_running # True
person.sleep()
# Billy is sleepy
# Billy is REALLY sleepy
# Zzzzzzzzzzzz
# Zzzzzzzzzzzzzzzzzzzzzz
print person.is_sleeping # True

I think S. Lott's answer is a much better way to implement a state machine, but if you still want to continue with your approach, using (state,event) as the key for your dict is better. Modifying your code:
class HandlerFsm(object):
_fsm = {
("state_a","event"): "next_state",
#...
}

It probably depends on how complex your state machine is. For simple state machines, a dict of dicts (of event-keys to state-keys for DFAs, or event-keys to lists/sets/tuples of state-keys for NFAs) will probably be the simplest thing to write and understand.
For more complex state machines, I've heard good things about SMC, which can compile declarative state machine descriptions to code in a wide variety of languages, including Python.

The following code is a really simple solution. The only interesting part is:
def next_state(self,cls):
self.__class__ = cls
All the logic for each state is contained in a separate class. The 'state' is changed by replacing the '__class__' of the running instance.
#!/usr/bin/env python
class State(object):
call = 0 # shared state variable
def next_state(self,cls):
print '-> %s' % (cls.__name__,),
self.__class__ = cls
def show_state(self,i):
print '%2d:%2d:%s' % (self.call,i,self.__class__.__name__),
class State1(State):
__call = 0 # state variable
def __call__(self,ok):
self.show_state(self.__call)
self.call += 1
self.__call += 1
# transition
if ok: self.next_state(State2)
print '' # force new line
class State2(State):
__call = 0
def __call__(self,ok):
self.show_state(self.__call)
self.call += 1
self.__call += 1
# transition
if ok: self.next_state(State3)
else: self.next_state(State1)
print '' # force new line
class State3(State):
__call = 0
def __call__(self,ok):
self.show_state(self.__call)
self.call += 1
self.__call += 1
# transition
if not ok: self.next_state(State2)
print '' # force new line
if __name__ == '__main__':
sm = State1()
for v in [1,1,1,0,0,0,1,1,0,1,1,0,0,1,0,0,1,0,0]:
sm(v)
print '---------'
print vars(sm
Result:
0: 0:State1 -> State2
1: 0:State2 -> State3
2: 0:State3
3: 1:State3 -> State2
4: 1:State2 -> State1
5: 1:State1
6: 2:State1 -> State2
7: 2:State2 -> State3
8: 2:State3 -> State2
9: 3:State2 -> State3
10: 3:State3
11: 4:State3 -> State2
12: 4:State2 -> State1
13: 3:State1 -> State2
14: 5:State2 -> State1
15: 4:State1
16: 5:State1 -> State2
17: 6:State2 -> State1
18: 6:State1
---------
{'_State1__call': 7, 'call': 19, '_State3__call': 5, '_State2__call': 7}

I think that the tool PySCXML needs a closer look too.
This project uses the W3C definition: State Chart XML (SCXML): State Machine Notation for Control Abstraction
SCXML provides a generic state-machine based execution environment based on CCXML and Harel State Tables
Currently, SCXML is a working draft; but chances are quite high that it is getting a W3C recommendation soon (it is the 9th draft).
Another interesting point to highlight is that there is an Apache Commons project aimed at creating and maintaining a Java SCXML engine capable of executing a state machine defined using a SCXML document, while abstracting out the environment interfaces...
And for certain other tools, supporting this technology will emerge in the future when SCXML is leaving its draft-status...

I wouldn't think to reach for a finite state machine for handling XML. The usual way to do this, I think, is to use a stack:
class TrackInfoHandler(object):
def __init__(self):
self._stack=[]
## ================================== Event callbacks
def startElement(self, name, attrs):
cls = self.elementClasses[name]
self._stack.append(cls(**attrs))
def characters(self, ch):
self._stack[-1].addCharacters(ch)
def endElement(self, name):
e = self._stack.pop()
e.close()
if self._stack:
self._stack[-1].addElement(e)
For each kind of element, you just need a class that supports the addCharacters, addElement, and close methods.
EDIT: To clarify, yes I do mean to argue that finite state machines are usually the wrong answer, that as a general-purpose programming technique they're rubbish and you should stay away.
There are a few really well-understood, cleanly-delineated problems for which FSMs are a nice solution. lex, for example, is good stuff.
That said, FSMs typically don't cope well with change. Suppose someday you want to add a bit of state, perhaps a "have we seen element X yet?" flag. In the code above, you add a boolean attribute to the appropriate element class and you're done. In a finite state machine, you double the number of states and transitions.
Problems that require finite state at first very often evolve to require even more state, like maybe a number, at which point either your FSM scheme is toast, or worse, you evolve it into some kind of generalized state machine, and at that point you're really in trouble. The further you go, the more your rules start to act like codeā€”but code in a slow interpreted language you invented that nobody else knows, for which there's no debugger and no tools.

I would definitely not recommend implementing such a well known pattern yourself. Just go for an open source implementation like transitions and wrap another class around it if you need custom features. In this post I explain why I prefer this particular implementation and its features.

Other related projects:
http://fsme.sourceforge.net/
https://code.google.com/p/visio2python/
You can paint state-machine and then use it in your code.

Here is a solution for "statefull objects" I've come up with, but it is rather inefficient for your intended purpose because state changes are relatively expensive. However, it may work well for objects which change state infrequently or undergo only a bounded number of state changes. The advantage is that once the state is changed, there is no redundant indirection.
class T:
"""
Descendant of `object` that rectifies `__new__` overriding.
This class is intended to be listed as the last base class (just
before the implicit `object`). It is a part of a workaround for
* https://bugs.python.org/issue36827
"""
#staticmethod
def __new__(cls, *_args, **_kwargs):
return object.__new__(cls)
class Stateful:
"""
Abstract base class (or mixin) for "stateful" classes.
Subclasses must implement `InitState` mixin.
"""
#staticmethod
def __new__(cls, *args, **kwargs):
# XXX: see https://stackoverflow.com/a/9639512
class CurrentStateProxy(cls.InitState):
#staticmethod
def _set_state(state_cls=cls.InitState):
__class__.__bases__ = (state_cls,)
class Eigenclass(CurrentStateProxy, cls):
__new__ = None # just in case
return super(__class__, cls).__new__(Eigenclass, *args, **kwargs)
# XXX: see https://bugs.python.org/issue36827 for the reason for `T`.
class StatefulThing(Stateful, T):
class StateA:
"""First state mixin."""
def say_hello(self):
self._say("Hello!")
self.hello_count += 1
self._set_state(self.StateB)
return True
def say_goodbye(self):
self._say("Another goodbye?")
return False
class StateB:
"""Second state mixin."""
def say_hello(self):
self._say("Another hello?")
return False
def say_goodbye(self):
self._say("Goodbye!")
self.goodbye_count += 1
self._set_state(self.StateA)
return True
# This one is required by `Stateful`.
class InitState(StateA):
"""Third state mixin -- the initial state."""
def say_goodbye(self):
self._say("Why?")
return False
def __init__(self, name):
self.name = name
self.hello_count = self.goodbye_count = 0
def _say(self, message):
print("{}: {}".format(self.name, message))
def say_hello_followed_by_goodbye(self):
self.say_hello() and self.say_goodbye()
# ----------
# ## Demo ##
# ----------
if __name__ == "__main__":
t1 = StatefulThing("t1")
t2 = StatefulThing("t2")
print("> t1, say hello.")
t1.say_hello()
print("> t2, say goodbye.")
t2.say_goodbye()
print("> t2, say hello.")
t2.say_hello()
print("> t1, say hello.")
t1.say_hello()
print("> t1, say hello followed by goodbye.")
t1.say_hello_followed_by_goodbye()
print("> t2, say goodbye.")
t2.say_goodbye()
print("> t2, say hello followed by goodbye.")
t2.say_hello_followed_by_goodbye()
print("> t1, say goodbye.")
t1.say_goodbye()
print("> t2, say hello.")
t2.say_hello()
print("---")
print( "t1 said {} hellos and {} goodbyes."
.format(t1.hello_count, t1.goodbye_count) )
print( "t2 said {} hellos and {} goodbyes."
.format(t2.hello_count, t2.goodbye_count) )
# Expected output:
#
# > t1, say hello.
# t1: Hello!
# > t2, say goodbye.
# t2: Why?
# > t2, say hello.
# t2: Hello!
# > t1, say hello.
# t1: Another hello?
# > t1, say hello followed by goodbye.
# t1: Another hello?
# > t2, say goodbye.
# t2: Goodbye!
# > t2, say hello followed by goodbye.
# t2: Hello!
# t2: Goodbye!
# > t1, say goodbye.
# t1: Goodbye!
# > t2, say hello.
# t2: Hello!
# ---
# t1 said 1 hellos and 1 goodbyes.
# t2 said 3 hellos and 2 goodbyes.
I've posted a "request for remarks" here.

Related

Ensure a variable is only at one state at any given time

Let's say we have a simulation of taxi movements. Each car at any given time, can be only in one of idle, rebalancing, serving states (just as an example, there are many more in my simulation). At any time, I have to check the state of each of the vehicles and act accordingly. For example, if a vehicle was idle and then picked up a passenger, its state should change from idle to serving. Importantly, at any given time the vehicle can only be in one of those states and its action set is also dependent on that state.
Currently, I am doing this with a long list of if-else checks, but feels very naive and it's very difficult to debug.
For example, the main logic checks the state of a car first:
if self.should_move():
_ = _make_a_decision(t)
self.update_rebalancing(WARMUP_PHASE)
if self.is_busy():
self.keep_serving()
elif self.is_waiting_to_be_matched():
# it's sitting somewhere
self.keep_waiting()
elif self.rebalancing: # and not self.busy:
self.update_rebalancing(WARMUP_PHASE)
Then any of those functions update its state accordingly, all including statements like this
self.idle = False
self.rebalancing = False
self.serving = True
self.time_idled = 0
There is a lot of repetition and easy to make mistakes.
I am wondering if
there is a programming pattern for this situation
If Python specifically has functionalities to handle this case
This is a really broad question and there's not any correct answer to it..
But to try to help, why not use a class?
class Taxi:
# One variable to hold an enum of the states.
self.state = 'idle'
# function to update the state
def setState(self, state):
self.state = state
# Functions to check the state (could have one to get the state and check later
def isIdle(self):
return self.state == 'idle'
Then any functionality the taxi needs to do can be put in the class like:
def pickupPassengers():
if self.state != 'idle':
return
self.passengers += 1
Then you create your taxis and manage them through the class
taxi1 = Taxi()
taxi1.getPassengers()
There are a few ways to accomplish what you want. Since it can get confusing if you have to manually change multiple variables every time you have a state change... just have one variable in charge of the state! If you want to still be able to refer to Taxi.idle, Taxi.rebalancing, etc, then you can create #property methods. They look like functions when you define them but are called like properties.
See the example below for a Taxi class which has only one state variable, self._state and uses #property methods to return the status.
class Taxi:
def __init__(self, initial_state = "idle"):
self._state = initial_state
#property
def idle(self):
return self._state == "idle"
#property
def rebalancing(self):
return self._state == "rebalancing"
#property
def serving(self):
return self._state == "serving"
def serve(self):
print("\nChanging state to serving\n")
self._state = "serving"
T = Taxi() # Initialize taxi
print(f"Taxi is idle: {T.idle}")
print(f"Taxi is rebalancing: {T.rebalancing}")
print(f"Taxi is serving: {T.serving}")
T.serve()
print(f"Taxi is idle: {T.idle}")
print(f"Taxi is rebalancing: {T.rebalancing}")
print(f"Taxi is serving: {T.serving}")```
Output:
Taxi is idle: True
Taxi is rebalancing: False
Taxi is serving: False
Changing state to serving
Taxi is idle: False
Taxi is rebalancing: False
Taxi is serving: True
Your design problem is that you're trying to use a series of Booleans to embody one-hot encoding of a discrete variable (state). If you want only one value at a time, the natural way to do this is with a single variable. Enumeration types are what most advanced languages use for this. For instance, you can encode "idle" as 0, "rebalancing" as 1, etc.
Python code would look something like this:
from enum import Enum, unique, auto
#unique
class TaxiState(Enum):
IDLE = auto()
REBAL = auto()
SERVE = auto()
class Taxi():
def __init__(self):
self.state = TaxiState.IDLE
def is_busy(self):
return self.state != TaxiState.IDLE
You don't worry about the coding; auto handles that. All you do is use the enumeration name as a value. You get to code just as you designed that aspect of the model.

How to print actual name of variable class type in function?

I'm trying to return variable name, but i keep getting this:
<classes.man.man object at (some numbers (as example:0x03BDCA50))>
Below is my code:
from classes.man import man
def competition(guy1, guy2, counter1=0, counter2=0):
.......................
some *ok* manipulations
.......................
if counter1>counter2:
return guy1
bob = man(172, 'green')
bib = man(190, 'brown')
print(competition(bob , bib ))
Epilogue
If anyone want to, explain please what I can write instead of __class__ in example below to get variable name.
def __repr__(self):
return self.__class__.__name__
Anyway, thank you for all of your support
There are different ways to approach your problem.
The simplest I can fathom is if you can change the class man, make it accept an optional name in its __init__ and store it in the instance. This should look like this:
class man:
def __init__(number, color, name="John Doe"):
self.name = name
# rest of your code here
That way in your function you could just do with:
return guy1.name
Additionnally, if you want to go an extra step, you could define a __str__ method in your class man so that when you pass it to str() or print(), it shows the name instead:
# Inside class man
def __str__(self):
return self.name
That way your function could just do:
return guy1
And when you print the return value of your function it actually prints the name.
If you cannot alter class man, here is an extremely convoluted and costly suggestion, that could probably break depending on context:
import inspect
def competition(guy1, guy2, counter1=0, counter2=0):
guy1_name = ""
guy2_name = ""
for name, value in inspect.stack()[-1].frame.f_locals.items():
if value is guy1:
guy1_name = name
elif value is guy2:
guy2_name = name
if counter1 > counter2:
return guy1_name
elif counter2 > counter2:
return guy1_name
else:
return "Noone"
Valentin's answer - the first part of it at least (adding a name attribute to man) - is of course the proper, obvious solution.
Now wrt/ the second part (the inspect.stack hack), it's brittle at best - the "variables names" we're interested in might not necessarily be defined in the first parent frame, and FWIW they could as well just come from a dict etc...
Also, it's definitly not the competition() function's responsability to care about this (don't mix domain layer with presentation layer, thanks), and it's totally useless since the caller code can easily solve this part by itself:
def competition(guy1, guy2, counter1=0, counter2=0):
.......................
some *ok* manipulations
.......................
if counter1>counter2:
return guy1
def main():
bob = man(172, 'green')
bib = man(190, 'brown')
winner = competition(bob, bib)
if winner is bob:
print("bob wins")
elif winner is bib:
print("bib wins")
else:
print("tie!")
Python prints the location of class objects in memory if they are passed to the print() function as default. If you want a prettier output for a class you need to define the __repr__(self) function for that class which should return a string that is printed if an object is passed to print(). Then you can just return guy1
__repr__ is the method that defines the name in your case.
By default it gives you the object type information. If you want to print more apt name then you should override the __repr__ method
Check below code for instance
class class_with_overrided_repr:
def __repr__(self):
return "class_with_overrided_repr"
class class_without_overrided_repr:
pass
x = class_with_overrided_repr()
print x # class_with_overrided_repr
x = class_without_overrided_repr()
print x # <__main__.class_without_overrided_repr instance at 0x7f06002aa368>
Let me know if this what you want?

How can I use an 'update' function to 'open' and update if the object is not yet open?

My example is a progress bar
In its simplest form a progress bar is
bar = ProgressBar.Open()
for item in list:
bar.Update(count, len(list))
I would instead like my calling code to be
for item in list:
bar.Update(count, len(list))
I want my Update() function to Open() a bar for the caller if one is not open. The caller doesn't need any other access to the bar than to update it so there's no value in having the meter` handle.
How can I retain state to tell if the Update had been previously called?
I could create a global variable and keep track that way, but I have a gut sense there's a Pythonista way of doing it.
Trying again, but in a way that has no application to stumble on.
The base question is:
I have a function that will be called multiple times.
I want to do something different the first time it is called.
How can a function in Python do that?
In C, that of course would be a...
static variable
I'm just now kinda figuring it out as I type, sorry.
========================
I'm sure all these edits are not how stackoverflow is supposed to work. I'm sorry for not getting it right yet, but am very appreciative of the replies.
Despite it sounding like I'm breaking all the rules of good practices, it's when looked at from the CALLER'S point of view that I had hoped to make an impact.
What if the only thing you needed to do to add a progress meter, even for debugging, to your program was make a call to a progress meter update in the location you want to show progress?
That's the underlying motivation. Slide in 1-line, get something cool for the trouble.
This progress meter was added to my otherwise boring file de-duplicator by adding just the single call:
msg = f'Deduplicating {idx} of {total_files} files\n' f'{dup_count} Dupes found\n' f'{small_count} Too small'
not_cancelled = sGUI.ProgressBar('De-dupe', msg, idx, total_files)
To avoid using global variables, you can use decorator. Here's a simple example:
def open():
print 'open'
def update():
print 'update'
def call_once(func1, *args1, **kwargs1):
def decorator(func2):
called = [False]
def wrapper(*args2 ,**kwargs2):
if not called[0]:
func1(*args1, **kwargs1)
called[0] = True
return func2(*args2, **kwargs2)
return wrapper
return decorator
#call_once(open)
def my_update():
update()
for i in xrange(5):
my_update()
which give the result:
open
update
update
update
update
update
For more information about decorator, please visit: https://wiki.python.org/moin/PythonDecorators
For what you want, you can use a class:
class ProgressBar:
def __init__(self):
self._opened = False
def Open(self):
print("Open")
def Update(self):
if self._opened:
print("Update!")
else:
self.Open()
print("set flag")
self._opened = True
print("Update")
In action:
In [32]: bar = ProgressBar()
In [33]: bar.Update()
Open
set flag
Update
In [34]: bar.Update()
Update!
Note: I copied your casing so as to make it more clear to you, however, the official Python style would be like this:
class ProgressBar:
def __init__(self):
self._opened = False
def open(self):
pass # open stuff
def update(self):
if self._opened:
pass # update stuff
else:
self.open()
self._opened = True
Using snake_case for everything except the ClassName.
OK, I found a solution using 'globals'. I thought that a nested function was the way to do it... then I mixed the two.
By 'globals' I meant variables declared outside the scope of a function. I want to be able to import my module without the import creating anything.
Here's the code that shows how to do this with globals
def my_update(amount):
global flag
if 'flag' in globals():
print('I have been here')
else:
print('I have not been here')
flag = True
return
for i in range(10):
print(f'Calling number {i}')
result = my_update(1)
It does the job for the goals I had set out, but I'm SURE there are better, safer ways that are more elegant as well.
I posted this question on a Python forum and got back the best answer so far using a function attribute. It's brilliant and it works.
Here is code that demonstrates this construct... it should go in everyone's 'Favorite Python Constructs' notebook in my opinion.
def func():
if not hasattr(func, 'static_variable'):
func.static_variable = 0
func.static_variable += 1
return func.static_variable
def main():
for i in range(10):
print('func = {}'.format(func()))
if __name__ == '__main__':
main()
The output is
func = 1
func = 2
func = 3
func = 4
func = 5
func = 6
func = 7
func = 8
func = 9
func = 10

Python class inheritance/Logic gate & circuit example

I'm currently self-learning Python, and I'm reading 'Problem Solving with Algorithms and Data Structures' (Brad Miller, David Ranum). I've stumbled upon the basic example of inheritance. Although I can see what it does, I need an explanation, how it works actually. The Code is as follows:
class LogicGate:
def __init__(self,n):
self.name = n
self.output = None
def getName(self):
return self.name
def getOutput(self):
self.output = self.performGateLogic()
return self.output
class BinaryGate(LogicGate):
def __init__(self,n):
LogicGate.__init__(self,n)
self.pinA = None
self.pinB = None
def getPinA(self):
if self.pinA == None:
return int(input("Enter Pin A input for gate "+self.getName()+"-->"))
else:
return self.pinA.getFrom().getOutput()
def getPinB(self):
if self.pinB == None:
return int(input("Enter Pin B input for gate "+self.getName()+"-->"))
else:
return self.pinB.getFrom().getOutput()
def setNextPin(self,source):
if self.pinA == None:
self.pinA = source
else:
if self.pinB == None:
self.pinB = source
else:
print("Cannot Connect: NO EMPTY PINS on this gate")
class AndGate(BinaryGate):
def __init__(self,n):
BinaryGate.__init__(self,n)
def performGateLogic(self):
a = self.getPinA()
b = self.getPinB()
if a==1 and b==1:
return 1
else:
return 0
class OrGate(BinaryGate):
def __init__(self,n):
BinaryGate.__init__(self,n)
def performGateLogic(self):
a = self.getPinA()
b = self.getPinB()
if a ==1 or b==1:
return 1
else:
return 0
class UnaryGate(LogicGate):
def __init__(self,n):
LogicGate.__init__(self,n)
self.pin = None
def getPin(self):
if self.pin == None:
return int(input("Enter Pin input for gate "+self.getName()+"-->"))
else:
return self.pin.getFrom().getOutput()
def setNextPin(self,source):
if self.pin == None:
self.pin = source
else:
print("Cannot Connect: NO EMPTY PINS on this gate")
class NotGate(UnaryGate):
def __init__(self,n):
UnaryGate.__init__(self,n)
def performGateLogic(self):
if self.getPin():
return 0
else:
return 1
class Connector:
def __init__(self, fgate, tgate):
self.fromgate = fgate
self.togate = tgate
tgate.setNextPin(self)
def getFrom(self):
return self.fromgate
def getTo(self):
return self.togate
def main():
g1 = AndGate("G1")
g2 = AndGate("G2")
g3 = OrGate("G3")
g4 = NotGate("G4")
c1 = Connector(g1,g3)
c2 = Connector(g2,g3)
c3 = Connector(g3,g4)
print(g4.getOutput())
main()
I'm mostly doubted by the tgate.setNextPin(self) statement in Connector class __init__. Is it a method call? If it is, why is it called with just one parameter, when there are two actually required by the setNexPin function in UnaryGate and BinaryGate classes (self, source)? How does the fromgate variable ends up as the source arrgument? Does this statement 'initiliaze' anything actually, and what?
Next thing which troubles me is, for example, when I print(type(g4)) before declaring g4.getOutput(), I get <class '__main__.OrGate'>, but when the g4.getOutput() starts, and functions start calling each other, to the point of calling getPin function, if I put print (self.pinA) before return self.pinA.getFrom().getOutput(), I get the <__main__.Connector object at 0x2b387e2f74d0>, although self.Pin is a variable from g4 OrGate instance. How can one variable from one class instance can become object of another class, which isn't inheriting it? Does this have something with a work of setNextPin() function?
Can someone explain this to me as I am new to OOP and thorougly confused by this piece of code. Thank you.
Regarding your first question, tgate.setNextPin(self) is a method call. tgate is an object, presumably an instance of one of the gate types. When you access instance.method, Python gives you a "bound method" object, which works pretty much like a function, but which puts the instance in as the first argument when it is actually called. So, tgate.setNextPin(self) is really calling type(tgate).setNextPin(tgate, self)
Your second question seems to reflect a misunderstanding of what attributes are. There's no requirement that an object's attributes be of its own type. In the various LogicGate sub-classes, the pin/pinA/pinB attributes are either going to be None (signaling that the user should be prompted for an input value) or an instance of a Connector (or something else with a getFrom method). Neither of those values is a LogicGate instance.
As for where the Connector instance you saw came from, its going to be one of the c1 through c3 values you created. Connector instances install themselves onto a pin of their tgate argument, with the setNextPin call you were asking about in your first question. I can't really speak to the g4 gate you are looking at, as it seems to be different than the g4 variable created in your example code's main() function (it is a different type), but I suspect that it is working as designed, and it's just a bit confusing. Try accessing the pinX attributes via g4.pinA rather than inspecting them inside of the methods and you may have a bit less confusion.
Here's a bit of code with outputs that should help you understand things a bit better:
# create a few gates
g1 = AndGate("G1")
g2 = OrGate("G2")
# at this point, no connectors have been hooked up, so all pinX attrs are None:
print("G1 pins:", g1.pinA, g1.pinB) # "None, None"
print("G2 pins:", g2.pinA, g2.pinB) # "None, None"
# test that the gates work independently of each other:
print("G1 output:", g1.getOutput()) # will prompt for two inputs, then print their AND
print("G2 output:", g2.getOutput()) # will prompt for two inputs, then print their OR
# create a connection between the gates
c1 = Connector(g1, g2) # connects output of g1 to first available pin (pinA) of g2
# we can see that g2.pinA has changed
print("G2 pins after connection:", g2.pinA, g2.pinB)
# "<__main__.Connector object at SomeHexAddress>, None"
# now, if we get g2's output, it will automatically request g1's output via the Connector
print("G2 output:", g2.getOutput())
# will prompt for 2 G1 inputs, and one G2 input and print (G1_A AND G1_B) OR G2_B
If you want to play around with these classes more, you might want to add a __str__ (and/or __repr__) method to some or all of the classes. __str__ is used by Python to convert an instance of the class into a string whenever necessary (such as when you pass it as an argument to print or str.format). Here's a quick __str__ implementation for Connector:
def __str__(self):
return "Connector between {} and {}".format(self.fgate.name, self.tgate.name)

how to make a lot of parameters available to the entire system?

I have objects from various classes that work together to perform a certain task. The task requires a lot of parameters, provided by the user (through a configuration file). The parameters are used deep inside the system.
I have a choice of having the controller object read the configuration file, and then allocate the parameters as appropriate to the next layer of objects, and so on in each layer. But the only objects themselves know which parameters they need, so the controller object would need to learn a lot of detail about every other object.
The other choice is to bundle all the parameters into a collection, and pass the whole collection into every function call (equivalently, create a global object that stores them, and is accessible to everyone). This looks and feels ugly, and would cause a variety of minor technical issues (e.g., I can't allow two objects to use parameters with the same name; etc.)
What to do?
I have used the "global collection" alternative in the past.
If you are concerned with naming: how would you handle this in your config file? The way I see it, your global collection is a datastructure representing the same information you have in your config file, so if you have a way of resolving or avoiding name clashes in your cfg-file, you can do the same in your global collection.
I hope you don't feel like I'm thread-jacking you - what you're asking about is similar to what I was thinking about in terms of property aggregation to avoid the models you want to avoid.
I also nicked a bit of the declarative vibe that Elixir has turned me onto.
I'd be curious what the Python gurus of stack overflow think of it and what better alternatives there might be. I don't like big kwargs and if I can avoid big constructors I prefer to.
#!/usr/bin/python
import inspect
from itertools import chain, ifilter
from pprint import pprint
from abc import ABCMeta
class Property(object):
def __init__(self, value=None):
self._x = value
def __repr__(self):
return str(self._x)
def getx(self):
return self._x
def setx(self, value):
self._x = value
def delx(self):
del self._x
value = property(getx, setx, delx, "I'm the property.")
class BaseClass(object):
unique_baseclass_thing = Property()
def get_prop_tree(self):
mro = self.__class__.__mro__
r = []
for i in xrange( 0, len(mro) - 1 ):
child_prop_names = set(dir(mro[i]))
parent_prop_names = set(dir(mro[i+1]))
l_k = list( chain( child_prop_names - parent_prop_names ) )
l_n = [ (x, getattr(mro[i],x,None)) for x in l_k ]
l_p = list( ifilter(lambda y: y[1].__class__ == Property, l_n))
r.append(
(mro[i],
(dict
( l_p )
)
)
)
return r
def get_prop_list(self):
return list( chain(* [ x[1].items() for x in reversed( self.get_prop_tree() ) ] ) )
class SubClass(BaseClass):
unique_subclass_thing = Property(1)
class SubSubClass(SubClass):
unique_subsubclass_thing_one = Property("blah")
unique_subsubclass_thing_two = Property("foo")
if __name__ == '__main__':
a = SubSubClass()
for b in a.get_prop_tree():
print '---------------'
print b[0].__name__
for prop in b[1].keys():
print "\t", prop, "=", b[1][prop].value
print
for prop in a.get_prop_list():
When you run it..
SubSubClass
unique_subsubclass_thing_one = blah
unique_subsubclass_thing_two = foo
---------------
SubClass
unique_subclass_thing = 1
---------------
BaseClass
unique_baseclass_thing = None
unique_baseclass_thing None
unique_subclass_thing 1
unique_subsubclass_thing_one blah
unique_subsubclass_thing_two foo

Categories