I am designing an API which deals with different type of vehicles for example cars, buses and vans. There is an endpoint POST /vehicle which will take a defined body.
{
'registration': 'str',
'date_of_purchase': 'datetime str',
'vehicle_type': 'car'
...
}
The first thing that we do is load an object based on the vehicle_type.
if body[vehicle_type] == 'car':
passed_in_vehicle = Car(body)
elif body['vehicle_type'] == 'bus':
passed_in_vehicle = Bus(body)
...
Within the python program there are multiple classes including:
vehicles.py
cars.py
vans.py
buses.py
The API entry point goes to vehicles.py which does some logic and then depending on the input will route it to one of the other classes to do more specific logic.
Each class has the same set of base methods.
update_vehicle_specs
register_vehicle
At the moment in the bottom of vehicles.py I have
if is_instance(passed_in_vehicle, Car):
carService = Cars()
carService.register_vehicle(passed_in_vehicle)
elif is_instance(passed_in_vehicle, Van):
vanService = Vans()
vanService.register_vehicle(passed_in_vehicle)
...
However, this cannot be scalable. What is the correct solution to route to specific classes based on a condition?
The way it looks to me, you can improve design a bit. Since each vehicle 'knows' where it is serviced, you should probably do in each something like
def __init__(self, ..., service):
super().__init__(self, ...)
...
...
service.register_vehicle(self)
this is coming from the perspective that "the car drives to the garage to register" rather than the "garage looks for new cars".
When you initialize a vehicle, pass it its servicing class, as in
new_car = Car(..., my_car_service)
where
my_car_service = Cars()
somewhere before. This is since we assume each new car needs to register, and we do not make a new service for each new car. Another approach, is for the class to contain (composition) its service object from the get go:
class Car:
service = Cars()
def __init__(...)
...
Car.service.register_vehicle(self)
so the class contains the servicing object always, and all initialized objects share the same one through a class variable. I actually prefer this.
First initialization:
With regard to your initial initialization of the vehicle, while using locals might be a nifty solution for that, it might be a bit more type safe to have something like what you have. In Python I like to use the "Python switch dictionary" (TM) for stuff like that:
{'car': Car,
'bus': Bus,
...
'jet': Jet
}[body[vehicle_type]](body)
I don't know if using locals would be ideal, but at least I believe it would scale better than your current solution:
use string name to instantiate classes from built-in locals() which will store imports as a dictionary
class Car(object):
def print(self):
print("I'm a car")
class Bus(object):
def print(self):
print("I'm a bus")
vehicle_type = "Car"
currV_class = locals()[vehicle_type]
currV_instance = currV_class()
#currV_instance.register_vehicle
currV_instance.print()
vehicle_type = "Bus"
currV_class = locals()[vehicle_type]
currV_instance = currV_class()
#currV_instance.register_vehicle
currV_instance.print()
OUTPUT:
I'm a car
I'm a bus
I'm making a game where I can gather resources or build when I send Workers, but I can't think of a way to receive those resources or finish building depending on the turn and the time(turns) it takes to finish those actions.
I've already made a Worker class, and it has a method to gather and it gives a random value that I save in a Player class. Also, my Game class keeps track of the turn I and the computers are.
class Game:
def __init__(self, player = None):
self.player = player
self.turn = 1
class Player:
def __init__(self):
self.workers = [Worker(), Worker(), Worker()]
self.resourcers = 0
class Worker:
def __init__(self):
self.hp = 100
def gather(self):
return randint(MIN_CANTIDAD_RECURSO, MAX_CANTIDAD_RECURSO)
player = Player()
game = Game()
game.player = player
for worker in player.workers:
player.resources += worker.gather
game.turn +=1
Gathering should give the result the next turn and build should give it depending on the building.
In a general sense, you store the values you need in the relevant object and pass them as parameters to whatever method requires those values. For example, you would need to store the turn duration of an action in the return value of that action, e.g in class Worker
def gather(self):
# Some code that determines gather_value and duration...
return [gather_value, duration]
and then the resource usage would look something like
def use_gather(gather, turn): # Pass in (return value from gather, game.turn)
# Use parameters...
With such a vague question, it's hard to say anything more.
For context, I'm working on an inventory system in an RPG, and I'm prototyping it with python code.
What I don't understand is how to make separate variables for each instance of an item without declaring them manually. For a short example:
class Player(object):
def __init__(self):
self.Items = {}
class Item(object):
def __init__(self):
self.Equipped = 0
class Leather_Pants(Item):
def __init__(self):
#What do i place here?
def Pick_Up(self, owner):
owner.Items[self.???] = self #What do i then put at "???"
def Equip(self):
self.Equipped = 1
PC = Player()
#Below this line is what i want to be able to do
Leather_Pants(NPC) #<-Create a unique instance in an NPC's inventory
Leather_Pants(Treasure_Chest5) #Spawn a unique instance of pants in a treasure chest
Leather_Pants1.Pick_Up(PC) #Place a specific instance of pants into player's inventory
PC.Items[Leather_Pants1].Equip() #Make the PC equip his new leather pants.
If I did something silly in the above code, please point it out.
What I want to do if the code doesn't make it clear is that I want to be able to dynamically create variables for all items as I spawn them, so no two items will share the same variable name which will serve as an identifier for me.
I don't mind if I have to use another class or function for it like "Create_Item(Leather_Pants(), Treasure_Chest3)"
What's the best way to go about this, or if you think I'm doing it all wrong, which way would be more right?
As a general rule, you don't want to create dynamic variables, and you want to keep data out of your variable names.
Instead of trying to create variables named pants0, pants1, etc., why not just create, say, a single list of all leather pants? Then you just do pants[0], pants[1], etc. And none of the other parts of your code have to know anything about how the pants are being stored. So all of your problems vanish.
And meanwhile, you probably don't want creating a Leather_Pants to automatically add itself to the global environment. Just assign it normally.
So:
pants = []
pants.append(Leather_Pants(NPC))
pants.append(Leather_Pants(chests[5]))
pants[1].pickup(PC)
The pants don't have to know that they're #1. Whenever you call a method on them, they've got a self argument that they can use. And the player's items don't need to map some arbitrary name to each item; just store the items directly in a list or set. Like this:
class Player(object):
def __init__(self):
self.Items = set()
class Item(object):
def __init__(self):
self.Equipped = 0
class Leather_Pants(Item):
def __init__(self):
pass # there is nothing to do here
def Pick_Up(self, owner):
self.owner.Items.add(self)
def Equip(self):
self.Equipped = 1
Abernat has tackled a few issues, but I thought I weigh in with a few more.
You appear to be using OOP, but are mixing a few issues with your objects. For example, my pants don't care if they are worn or not, I care though for a whole host of reasons. In python terms the Pants class shouldn't track whether it is equipped (only that it is equippable), the Player class should:
class CarryableItem:
isEquipable = False
class Pants(CarryableItem):
isEquipable = True
class Player:
def __init__(self):
self.pants = None # Its chilly in here
self.shirt = None # Better take a jumper
self.inventory = [] # Find some loot
def equip(self,item):
if is.isEquipable:
pass # Find the right slot and equip it,
# put the previously equipped item in inventory, etc...
Also, its very rare that an item will need to know who its owner is, or that its been grabbed, so verbs like that again should go onto the Player:
class Player:
maxCarry = 10
def take(Item):
if len(inventory) < maxCarry:
inventory.append(item)
Lastly, although we've tried to move most verbs on to actors which actually do things, sometimes this isn't always the case. For example, when instantiating a chest:
import random
class StorageItem:
pass
class Chest(StorageItem):
__init__(self):
self.storage = random.randint(5)
self.loot = self.spawnLoot()
def spawnLoot(self):
for i in range(self.storge):
# Lets make some loot
item = MakeAnItem # Scaled according to type level of dungeon, etc.
loot.append(item)
def remove(item):
self.loot[self.loot.index(item)]=None
Now the question about what to do when a Player wants to plunder a chest?
class Player:
def plunder(storage):
for item in storage.loot:
# do some Ui to ask if player wants it.
if item is not None and self.wantsItem(item) or \
(self.name="Jane" and self.wantsItem(item) and self.doesntWantToPay):
self.take(item)
storage.remove(item)
edit: Answering the comment:
If you are curious about calculating armor class, or the like, that again is a factor of the user, not the item. For example:
class Player:
#property
def clothing(self):
return [self.pants,self.top]
#property
def armorClass(self):
ac = self.defence
for item in self.clothing:
def = item.armorClass
if self.race="orc":
if item.material in ["leather","dragonhide"]:
def *= 1.5 # Orcs get a bonus for wearing gruesome dead things
elif item.material in ["wool","silk"]:
def *= 0.5 # Orcs hate the fineries of humans
ac += def
return ac
pants = Pants(material="leather")
grum = Player(race="orc")
grum.equip(pants)
print grum.armorClass
>>> 17 # For example?
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.