Lists not resetting after loop has been executed - python

I am trying create a loop that resets all the data inside of it every iteration but somewhere the data is not resetting even though I am initializing values inside of the loop.
Here is my code:
import time , sys , string
import serial
ser = serial.Serial("/dev/ttyUSB0", baudrate=9600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS
)
print (ser.name)
ser.write(b'U')
#print ('test1')
time.sleep(2)
b=0
while (b <= 2):
time.sleep(0.25)
ser.write(b'R')
#print ('test2')
d = [] # establishes an empty list to iterate through all the incoming data
i=0 # beginning of the buffer
time.sleep(0.5)
while (i<=11):
d.append(str(ord(ser.read()))) #adding each incoming bit to the list
#print (d[i])
#print ('^ is the ' + str(i) + 'th term') // these two lines help establish where the useful information begins for the lidar.
i+=1
#establishing a better way to write the data out / gd = good distance
gd = []
a = 0
for a in range(8):
gd.append(str(chr(int(d[a+4]))))
print (gd)
print (gd[0] + gd[1] + gd[2] + gd[3] + gd[4] + gd[5] + gd[6] + gd[7] + ' mm')
ser.flush()
b+=1
The reason i do d[a+4] is because the first few bits of information are nonsense so I need it to start from that bit every time.
The program works in the first loop and correctly prints it out, however, in subsequent loops it begins to start from different points when I try to print out the values again. I am unsure if I am missing something and would love a second opinion.
My outputs are:
D = 0609 mm
\r:\rD = 0 mm
mm \r:\rD mm
so it's looping around the lists I'm creating somewhere and since it's taking in the string from the print statement I wonder if that has something to do with the issue.

I cannot add a comment, so here is a little suggestion. At the end of your main loop, after
b+=1
add the following line
d, gd = [], []
if they are no longer useful after the loop has ended (which I suspect is the case). It'll reset any value the both variables hold in them and you'll be able to start from empty lists again.

Related

Stuck in loop help - Python

The second 'if' statement midway through this code is using an 'or' between two conditions. This is causing the issue I just don't know how to get around it. The code is going through a data file and turning on the given relay number at a specific time, I need it to only do this once per given relay. If I use an 'and' between the conditions, it will only turn on the first relay that matches the current time and wait for the next hour and turn on the next given relay.
Could someone suggest something to fix this issue, thank you!
def schedule():
metadata, sched = dbx.files_download(path=RELAYSCHEDULE)
if not sched.content:
pass # If file is empty then exit routine
else:
relaySchedule = str(sched.content)
commaNum = relaySchedule.count(',')
data1 = relaySchedule.split(',')
for i in range(commaNum):
data2 = data1[i].split('-')
Time1 = data2[1]
currentRN = data2[0]
currentDT = datetime.datetime.now()
currentHR = currentDT.hour
global RN
global T
if str(currentHR) == str(Time1):
if T != currentHR or RN != currentRN:
relaynum = int(data2[0])
relaytime = int(data2[2])
T = currentHR
RN = currentRN
k = threading.Thread(target=SendToRelay(relaynum, relaytime)).start()
else:
print("Pass")
Desired Inputs:
sched.content = '1-19-10,3-9-20,4-9-10,'
T = ' '
RN = ' '
T and RN are global variables because the loop is running indefinitely, they're there to let the loop know whether the specific Time(T) and Relay Number(RN) have already been used.
Desired Outputs:
If the time is 9 AM then,
T = 9
RN should be whatever the given relay number is so RN = 3, but not sure this is the right thing to use.
Sorry if this is confusing. I basically need the program to read a set of scheduled times for specific relays to turn on, I need it to read the current time and if it matches the time in the schedule it will then check which relay is within that time and turn it on for however long. Once it has completed that, I need it to go over that same set of data in case there is another relay within the same time that also needs to turn on, the issue is that if I don't use T and RN variables to check whether a previous relay has been set, it will read the file and turn on the same relay over and over.
Try printing all used variables, check if everything is, what you think it is. On top of that, sometimes whietespaces characters causes problem with comparison.
I fixed it. For anyone wondering this is the new working code:
def schedule():
metadata, sched = dbx.files_download(path=RELAYSCHEDULE)
if not sched.content:
pass # If file is empty then exit routine
else:
relaySchedule = str(sched.content)
commaNum = relaySchedule.count(',')
data1 = relaySchedule.split(',')
for i in range(commaNum):
data2 = data1[i].split('-')
TimeSched = data2[1]
relaySched = data2[0]
currentDT = datetime.datetime.now()
currentHR = currentDT.hour
global RN
global T
if str(currentHR) == str(TimeSched):
if str(T) != str(currentHR):
RN = ''
T = currentHR
if str(relaySched) not in str(RN):
relaynum = int(data2[0])
relaytime = int(data2[2])
k = threading.Thread(target=SendToRelay(relaynum, relaytime)).start()
RN = str(RN) + str(relaySched)

While loop works for small to medium sized data but not larger amounts of data. (Python)

Ok so for a problem I must parse in two files of information and then compare those files. I need to report any inconsistent data and any data that is in one file but not the other file. To do this I have sorted both lists of data which allows me to compare the first element in each list, if they are equal I remove them if they are inconsistent I report and remove them, if one or the other is different I report which one is missing data and then PUT BACK the later date so it can be compared next time.
As you can see in my code (at least I think, and have tested extensively) that this method works well for data sets with 100-200 lines per file. When I get larger, like 1,000-1,000,000 it takes to long to report.
I am stumped at how my while loop would be causing this. See below.
The split represents the date(split[0]) and then a piece of information(split[1]).
Any help would be appreciated and this is actually my first python program.
tldr; For some reason my program works fine in small data sets but larger data sets do not run properly. It isn't the sort()'s either (i.e. something in my first while loop is causing the run time to be shit).
ws1.sort()
ws2.sort()
while ws1 and ws2:
currItem1 = ws1.pop(0)
currItem2 = ws2.pop(0)
if currItem1 == currItem2:
continue
splitWS1 = currItem1.split()
splitWS2 = currItem2.split()
if splitWS1[0] == splitWS2[0] and splitWS1[1] != splitWS2[1]:
print("Inconsistent Data (" + splitWS1[0] + "): A: " + splitWS1[1] + " B: " + splitWS2[1])
continue
elif splitWS1[0] < splitWS2[0]:
print("Missing Data (" + splitWS1[0] + ") in data set A but not in B")
ws2.insert(0, currItem2)
continue
elif splitWS1[0] > splitWS2[0]:
print("Missing Data (" + splitWS2[0] + ") in data set B but not in A")
ws1.insert(0, currItem1)
continue
while ws2:
currItem2 = ws2.pop(0)
splitWS2 = currItem2.split()
print("Missing data (" + splitWS2[0] + ") in data set B but not in A")
while ws1:
currItem1 = ws1.pop(0)
splitWS1 = currItem1.split()
print("Missing data (" + splitWS1[0] + ") in data set A but not in B")
It's likely these two lines:
currItem1 = ws1.pop(0)
currItem2 = ws2.pop(0)
As you are removing the first item in the lists, you have to rebuild the entire list. If you try to use (outside the loop):
listA = list(reversed(ws1.sorted()))
And then process in the loop with
currItem1 = listA.pop()
For each of the two lists, you may save much processing time.
Basically, removing the first item in a list is O(n), while removing the last item in the list is O(1). Doing this within the loop means it is O(n^2), but if you reverse the list once beforehand, and then remove the last item in the list, it's O(n).

If-statement seemingly ignored by Write operation

What I am trying to do here is write the latitude and longitude of the sighting of a pokemon to a text file if it doesn't already exist. Since I am using an infinite loop, I added an if-state that prevents an already existent pair of coordinates to be added.
Note that I also have a list Coordinates that stores the same information. The list works as no repeats are added.(By checking) However, the text file has the same coordinates appended over and over again even though it theoretically shouldn't as it is contained within the same if-block as the list.
import requests
pokemon_url = 'https://pogo.appx.hk/top'
while True:
response = requests.get(pokemon_url)
response.raise_for_status()
pokemon = response.json()[0:]
Sighting = 0
Coordinates = [None] * 100
for num in range(len(pokemon)):
if pokemon[num]['pokemon_name'] == 'Aerodactyl':
Lat = pokemon[num]['latitude']
Long = pokemon[num]['longitude']
if (Lat, Long) not in Coordinates:
Coordinates[Sighting] = (Lat, Long)
file = open("aerodactyl.txt", "a")
file.write(str(Lat) + "," + str(Long) + "\n")
file.close()
Sighting += 1
For clarity purposes, this is the output
You need to put your Sighting and Coordinates variables outside of the while loop if you do not want them to reset on every iteration.
However, there are a lot more things wrong with the code. Without trying it, here's what I spot:
You have no exit condition for the while loop. Please don't do this to the poor website. You'll essentially be spamming requests.
file.close should be file.close(), but overall you should only need to open the file once, not on every single iteration of the loop. Open it once, and close once you're done (assuming you will add an exit condition).
Slicing from 0 (response.json()[0:]) is unnecessary. By default the list starts at index 0. This may be a convoluted way to get a new list, but that seems unnecessary here.
Coordinates should not be a hard-coded list of 100 Nones. Just use a set to track existing coordinates.
Get rid of Sighting altogether. It doesn't make sense if you're re-issuing the request over and over again. If you want to iterate through the pokémon from one response, use enumerate if you need the index.
It's generally good practice to use snake case for Python variables.
Try this:
#!/usr/bin/env python
import urllib2
import json
pokemon_url = 'https://pogo.appx.hk/top'
pokemon = urllib2.urlopen(pokemon_url)
pokeset = json.load(pokemon)
Coordinates = [None] * 100
for num in range(len(pokeset)):
if pokeset[num]['pokemon_name'] == 'Aerodactyl':
Lat = pokeset[num]['latitude']
Long = pokeset[num]['longitude']
if (Lat, Long) not in Coordinates:
Coordinates.append((Lat, Long))
file = open("aerodactyl.txt", "a")
file.write(str(Lat) + "," + str(Long) + "\n")
file.close

Python: how to interrupt, then return to while loop, without goto?

I'm running a simple PID control program in python. Basically an infinite while loop, which reads from sensors then calculates the appropriate control signal, as well as outputs diagnostic info to the terminal.
However, sometimes while watching the diagnostic info, I'd like to change the PID coefficients - which are essentially some constants used by the loop - by breaking from the loop, accepting user input, then returning to the very same loop. I'd like to do this an arbitrary number of times.
With 'goto' this would be simple and easy and just what I want. Can someone give me some python pseudo-code to do this? I can't really think of how to do it. I can interrupt the loop with a CTRL+C exception handler, but then I can't get back to the main loop.
There must be some very simple way to do this but I can't think of it. Thoughts?
Snippets from my code:
while True:
t0 = get_temp_deg_c(thermocouple1)
print "Hose Temperature = " + str(t0) + " deg C"
t1 = get_temp_deg_c(thermocouple2)
print "Valve Temperature = " + str(t1) + " deg C"
# write temps to file
fi.write(str(t0))
fi.write(" " + str(t1) + "\n")
error = setpoint - t0
print "Setpoint = " + str(setpoint) + " deg C"
print "Error = " + str(error) + " deg C"
percent_error = error/setpoint*100
print "Percent error = " + str(percent_error) + " %"
duty_out = p.GenOut(percent_error)
print "PID controller duty output: " + str(duty_out) + " %"
# clamp the output
if(duty_out) > 100:
duty_out = 100
if(duty_out < 0):
duty_out = 0
PWM.set_duty_cycle(PWM_pin, duty_out)
# do we need to increment the setpoint?
if( (setpoint - setpoint_precision) ... # omitted logic here
# Here we return to the top
As long as you're okay with restarting "from the top" after each interrupt (as opposed to returning to the exact point in the loop when the signal was raised, which is a much harder problem):
while True:
try:
controller.main_loop()
except KeyboardInterrupt:
controller.set_coefficients()
In case you don't want a separate thread for IO, generators may be used to preserve the state of your loop across KeyboardInterrupts.
some_parameter = 1
def do_pid_stuff():
while True:
sensor_data1 = 'data'
sensor_data2 = 'data'
sensor_data3 = 'data'
yield 'based on sensor_data1 ' * some_parameter
yield 'based on sensor_data2 ' * some_parameter
yield 'based on sensor_data3 ' * some_parameter
stuff = do_pid_stuff()
while True:
try:
for control_signal in stuff:
print(control_signal)
except KeyboardInterrupt:
some_parameter = int(input())
So the main loop will continue with new parameters from the last executed yield. This however would require to rewrite your loop. Probably, it should be splitted into a generator that will give you sensor data and into a function that will actually do stuff based on the sensor values.
You already have a few ways to interact with your loop, I'd like to point out another one: select(). Using select(), you can wait for either user input. If you add a timeout, you can then break into the normal loop if no user input is available and interact with your hardware there.
Notes:
Here's the documentation for select , but consider the warning on top and look at the selectors module instead.
This solution, like the one using a keyboard interrupt, will stop interacting with the hardware while parameters are being changed. If that isn't acceptable, using a background thread is necessary.
Using select() is more generally applicable, you could also wait for network traffic.
Your hardware will not be serviced as often as possible but with a fixed pause in between. On the upside, you also don't use a full CPU then.

What's wrong with my python multiprocessing code?

I am an almost new programmer learning python for a few months. For the last 2 weeks, I had been coding to make a script to search permutations of numbers that make magic squares.
Finally I succeeded in searching the whole 880 4x4 magic square numbers sets within 30 seconds. After that I made some different Perimeter Magic Square program. It finds out more than 10,000,000 permutations so that I want to store them part by part to files. The problem is that my program doesn't use all my processes that while it is working to store some partial data to a file, it stops searching new number sets. I hope I could make one process of my CPU keep searching on and the others store the searched data to files.
The following is of the similar structure to my magic square program.
while True:
print('How many digits do you want? (more than 20): ', end='')
ansr = input()
if ansr.isdigit() and int(ansr) > 20:
ansr = int(ansr)
break
else:
continue
fileNum = 0
itemCount = 0
def fileMaker():
global fileNum, itemCount
tempStr = ''
for i in permutationList:
itemCount += 1
tempStr += str(sum(i[:3])) + ' : ' + str(i) + ' : ' + str(itemCount) + '\n'
fileNum += 1
file = open('{0} Permutations {1:03}.txt'.format(ansr, fileNum), 'w')
file.write(tempStr)
file.close()
numList = [i for i in range(1, ansr+1)]
permutationList = []
itemCount = 0
def makePermutList(numList, ansr):
global permutationList
for i in numList:
numList1 = numList[:]
numList1.remove(i)
for ii in numList1:
numList2 = numList1[:]
numList2.remove(ii)
for iii in numList2:
numList3 = numList2[:]
numList3.remove(iii)
for iiii in numList3:
numList4 = numList3[:]
numList4.remove(iiii)
for v in numList4:
permutationList.append([i, ii, iii, iiii, v])
if len(permutationList) == 200000:
print(permutationList[-1])
fileMaker()
permutationList = []
fileMaker()
makePermutList(numList, ansr)
I added from multiprocessing import Pool at the top. And I replaced two 'fileMaker()' parts at the end with the following.
if __name__ == '__main__':
workers = Pool(processes=2)
workers.map(fileMaker, ())
The result? Oh no. It just works awkwardly. For now, multiprocessing looks too difficult for me.
Anybody, please, teach me something. How should my code be modified?
Well, addressing some things that are bugging me before getting to your asked question.
numList = [i for i in range(1, ansr+1)]
I know list comprehensions are cool, but please just do list(range(1, ansr+1)) if you need the iterable to be a list (which you probably don't need, but I digress).
def makePermutList(numList, ansr):
...
This is quite the hack. Is there a reason you can't use itertools.permutations(numList,n)? It's certainly going to be faster, and friendlier on memory.
Lastly, answering your question: if you are looking to improve i/o performance, the last thing you should do is make it multithreaded. I don't mean you shouldn't do it, I mean that it should literally be the last thing you do. Refactor/improve other things first.
You need to take all of that top-level code that uses globals, apply the backspace key to it, and rewrite functions that pass data around properly. Then you can think about using threads. I would personally use from threading import Thread and manually spawn Threads to do each unit of I/O rather than using multiprocessing.

Categories