> On Apr 26, 2019, at 4:18 AM, Arup Rakshit wrote:
>
> I have modelled which starts running once drivers and stations are assigned
> to it. Otherwise, it doesn’t run, really don’t care if passengers are boarded
> or not at this moment. :) I think this program can help me to introduce to
> the Python async programming domain.
>
> Here is my program:
>
> # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
> # train.py
> # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
>
> import time
> import random
>
> from user import User
>
> class NotReadyToDeparture(Exception):
>pass
>
> class Train:
>def __init__(self, name, category):
>self.name = name
>self.category = category
>self.__drivers = []
>self.__stations = []
>
>@property
>def drivers(self):
>return self.__drivers
>
>@drivers.setter
>def drivers(self, coachmen):
>self.__drivers = coachmen
>
>@property
>def stations(self):
>return self.__stations
>
>@stations.setter
>def stations(self, places):
>self.__stations = places
>
>def next_stoppage(self):
>return self.stations[0]
>
>def run(self):
>total_run_time = 0
>if len(self.drivers) == 0:
>raise NotReadyToDeparture('Drivers are not yet boarded')
>
>if len(self.stations) == 0:
>raise NotReadyToDeparture('Stoppage stations are not yet
> scheduled')
>
>for station in range(len(self.stations[:])):
>run_time_to_next_stoppage = random.randint(2, 6)
>time.sleep(run_time_to_next_stoppage)
>total_run_time += run_time_to_next_stoppage
>print("Train Reached at {0} in {1}
> seconds".format(self.stations.pop(0), run_time_to_next_stoppage))
>
>print(f"Train {self.name} is reached the destination in
> {total_run_time} seconds.")
>
The underlying problem with your current "run" method is that it only returns
when the train has visited all the stations. This happens because of your for
loop and the call to time.sleep inside your loop.
Instead, I would suggest that you split the functionality of your current run
method into two methods. The "run" method would start the train going. Then
you need a separate method, maybe "update" that would be called continuously.
(Code below is completely untested)
The run method would consist of your current checks to ensure that the drivers
and stations are set. Then, it should set:
self.total_run_time = 0 # making this an instance variable that will
be used in the update method
You also need a way of getting the current (real) time so you can know when you
have reached the next station (I'll leave the implementation of that up to you):
self.stations.insert(0, 'start') # add something at the beginning of
your list that will get popped off immediate at the first call to update
self.time_at_next_station =
The update method will be called continuously. It should check the current
time and see if it has reached the time to move on to the next station,
something like:
def update():
currentTime =
if currentTime < self.time_at_next_station: # in transit to the next
station, nothing to do
return
# Train has arrived at a station, set up for next station
self.stations.pop(0) # eliminate the station at the front of the
list
if len(self.stations) == 0:
return # reached the end of the line
run_time_to_next_stoppage = random.randint(2, 6) # whatever time this
happened plus some random seconds
self.time_at_nextStation = currentTime + run_time_to_next_stoppage
# time in the future when train gets to next station
self.total_run_time = self.total_run_time + run_time_to_next_stoppage
# add to total time
print('Next stoppage is at', stations[0])
The first time "update" is called, it will move from the 'start' to the first
station, and calculate when the train should reach the first station. Because
update is called continuously, it only needs to check if the time for getting
to the next station has been reached. If so, then set up for the next station.
That way, your main loop becomes:
train.run()
while len(train.stations) is not 0:
train.update()
Then you could have another property to get the total time (and print).
Personally, I would prefer that train.update would return True or False to say
if it was done with the whole route. that is, it would normally return False
to say it is not done yet. But when it gets to the end, it would return True.
Then your main code could be written as:
train.run()
while True:
done = train.update()
if done:
break
Like I