This kind of follows up on a question I asked prior, but I have a function, we'll call it get_temp(), that needs to be looped in order to gather the data it needs to call for another function, we'll call it notification(), to run if the if statement is satisfied. This all works great, but once it does satisfy the if statement, I need it to only send auxFunction once.
This section of the code works by getting temperature from a thermocouple, and then I'm using an if statement to call for a specific function when the temp == a specific value. The temperature data is looked at every 2 seconds in the loop, which is necessary to see the changes in the data to satisfy the if statement eventually, so I can't just run it outside of the loop.
This is the part of the code that grabs the thermocouple value:
def grab_temp(self):
temp = self.board.temp_sensor
print("Temperature is " + str(round(temp)) + " degrees")
temp=int(temp)
if temp == 200:
self.notification()
This is the concept of the code, but not the exact code. It's written a little differently, but performs as it's written above and the notification function does more than just print. just for the sake of example, I'm just having it print something
And then:
def notification(self):
print("Testing")
Again, this all works, but since the grab_temp function is inside of the loop of the rest of the code, it loops every two seconds, which in turn, prints every two seconds when the value is 200, where I need it to just perform the notification function once, when temp == 200. This is problematic because the code that will be in the notification function will be notifying me of the temperature, so I can't have it notifying me every two seconds while the temperature is 200 degrees.
What would be the best way to go about achieving this, in this instance? I've tried a few other things recommended on similar questions, but none of them worked. All that I tried returned some kind of error, which prevented the rest of the code from functioning properly.
I didn't write the entirety of this of this whole project, I'm just modifying it to do some things I want it to do, and I don't have a ton of experience in coding, but I'm learning more and more as I work through this project, and have enjoyed making these modifications, and am still learning some basics on the side.
Possible solution without explicitly using global.
Add a boolean parameter to grab_temp, we'll call it notify. Set an initial value for notify=True. At the end of grab_temp, return the appropriate boolean to turn on/off the notification. Assign grab_temp to notify within your loop.
This version will disable notifications for consecutive calls, but re-enable notifications when the condition is no longer met. You can modify what's returned from grab_temp if you only want a notification for the very first time the condition is met.
temp_values = [1,200,200,1,200,200,200,1,200]
def notification():
print('notification')
def grab_temp(i, notify=True):
temp = temp_values[i]
print("Temp is", temp)
check_temp = temp == 200
if notify and check_temp:
notification()
return not check_temp
notify = True
for i in range(len(temp_values)):
notify = grab_temp(i, notify)
Example result
Temp is 1
Temp is 200
notification
Temp is 200
Temp is 1
Temp is 200
notification
Temp is 200
Temp is 200
Temp is 1
Temp is 200
notification
Modified grab_temp to only notify for the very first time the condition is met.
def grab_temp(i, notify=True):
temp = temp_values[i]
print("Temp is", temp)
check_temp = temp == 200
if notify and check_temp:
notification()
return False
else:
return notify
Temp is 1
Temp is 200
notification
Temp is 200
Temp is 1
Temp is 200
Temp is 200
Temp is 200
Temp is 1
Temp is 200
I sadly do not have the ability to comment currently due to my lack of reputation on this website. However, I think a solution you could consider is adding a global boolean variable called 'uncalled' that defaults to true and adjust it once you've called the self.notification() portion of your code.
Beginning of Script:
uncalled = True
Printing Warning
global uncalled
if temp == 200 and uncalled:
self.notification()
uncalled = False
Using the keyword 'global' here should change it throughout your entire code and not just within the function. If this doesn't answer your question, would you mind clarifying for me in my comments? Thanks!
Extra Example:
uncalled = True
def function(x):
global uncalled
if x and uncalled:
print('hit')
uncalled = False
for i in range(5):
x = True
function(x)
Returns
hit
Related
I have no idea anymore. I've been struggling for hours now.
I got a pi2golite here with wheel sensors.
the wheelCount() isn't working anyway (or at least I dont know how)
so I've been trying to find another solution.
The 2 motors I've got seem to run on different speed's. I wanted to see that in numbers to change the speed of each motor so they run the same.
import pi2go, time
pi2go.init()
running = True
countL = 0
countR = 0
def counter1():
global countR
countR += 0
speed = 60
try:
pi2go.stepForward(50,10)
time.sleep(2)
print counter1()
print countL
finally:
pi2go.cleanup()
->
When I try to run it, the motor's run fine and turn off after the 10 steps (so it has to be counting)
it outputs this:
for countL -> 0
for counter1() ->None
Why none?
This is expected bahaviour.
If you run code in a Python shell, then when you write an expression, the shell will print the result of the expression.
For a function call, this is what the function returns. In Python every function returns something. In case you do not specify a return statement, then None is returned. Some shells do not print None, but anyway, the result is None of sucht call.
So the function updates countR, then performs return None (implicitly). This is the result of the function call, and so the shell prints this. If you run code without the shell, then nothing is printed (as in no content at all).
You can let the function return the updated value. Furthermore you probably want to increment the value, so += 1:
def counter1():
global countR
countR += 1
return countR
I have written an instance method which uses recursion to find a certain solution. It works perfectly fine except the time when I'm exiting the if-elif block. I call the function itself inside IF block. Also, I have only one return statement. The output from the method is weird for me to understand. Here is the code and the output:
def create_schedule(self):
"""
Creates the day scedule for the crew based on the crew_dict passed.
"""
sched_output = ScheduleOutput()
assigned_assignements = []
for i in self.crew_list:
assigned_assignements.extend(i.list_of_patients)
rest_of_items = []
for item in self.job.list_of_patients:
if item not in assigned_assignements:
rest_of_items.append(item)
print("Rest of the items are:", len(rest_of_items))
if len(rest_of_items) != 0:
assignment = sorted(rest_of_items, key=lambda x: x.window_open)[0]
# print("\nNext assignment to be taken ", assignment)
output = self.next_task_eligibility(assignment, self.crew_list)
if len(output) != 0:
output_sorted = sorted(output, key=itemgetter(2))
crew_to_assign = output_sorted[0][1]
assignment.eta = output_sorted[0][4]
assignment.etd = int(assignment.eta) + int(assignment.care_duration)
crew = next((x for x in self.crew_list if x.crew_number == crew_to_assign), None)
self.crew_list.remove(crew)
crew.list_of_patients.append(assignment)
crew.time_spent = assignment.etd
self.crew_list.append(crew)
self.create_schedule()
else:
print("*" * 80, "\n", "*" * 80, "\nWe were not able to assign a task so stopped.\n", "*" * 80, "\n", "*" * 80)
sched_output.crew_output = self.crew_list
sched_output.patients_left = len(rest_of_items)
elif not rest_of_items:
print("Fully solved.")
sched_output.crew_output = self.crew_list
sched_output.patients_left = 0
print("After completely solving coming here.")
return sched_output
This was the output:
Rest of the items are: 10
Rest of the items are: 9
Rest of the items are: 8
Rest of the items are: 7
Rest of the items are: 6
Rest of the items are: 5
Rest of the items are: 4
Rest of the items are: 3
Rest of the items are: 2
Rest of the items are: 1
Rest of the items are: 0
Fully solved.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
What I don't understand is that as soon as my list rest_of_items is empty, I assign data to sched_output and return it. However, print statement is being executed for the same number of time as recursion was done. How can I avoid this?
My output is perfectly fine. All I want to do is understand the cause of this behaviour and how to avoid it.
The reason it's printing out 11 times is that you always call print at the end of the function, and you're calling the function 11 times. (It's really the same reason you get Rest of the items are: … 11 times, which should be a lot more obvious.)
Often, the best solution is to redesign things so instead of doing "side effects" like print inside the function, you just return a value, and the caller can then do whatever side effects it wants with the result. In that case, it doesn't matter that you're calling print 11 times; the print will only happen once, in the caller.
If that isn't possible, you can change this so that you only print something when you're at the top of the stack. But in many recursive functions, there's no obvious way to figure that out without passing down more information:
def create_schedule(self, depth=0):
# etc.
self.create_schedule(depth+1)
# etc.
if not depth:
print('After completely solving come here.')
returns sched_output
The last resort is to just wrap the recursive function, like this:
def _create_schedule(self):
# etc.
self._create_schedule()
# etc.
# don't call print
return sched_output
def create_schedule(self):
result = self._create_schedule()
print('After completely solving come here.')
return result
That's usually only necessary when you need to do some one-time setup for the recursive process, but here you want to do some one-time post-processing instead, which is basically the same problem, so it can be solved the same way.
(Of course this is really just the first solution in disguise, but it's hidden inside the implementation of create_schedule, so you don't need to change the interface that the callers see.)
As you call your create_schedule function within itself before the function finishes, once it has gotten to the end and doesn't need to call itself again, each function ends, and hits the "After completely solving coming here.", at the end of the function.
This means that each function, after calling itself, is still running - just stuck at the line where it calls itself - until they have all completed, which is when the paused functions can finish their task, printing out your statement.
You have print("After completely solving coming here.") at the end of your recursive function. That line will be executed once for each recursion.
Consider this simple example, which recreates your issue:
def foo(x):
print("x = {x}".format(x=x))
if x > 1:
foo(x-1)
print("Done.")
Now call the function:
>>> foo(5)
x = 5
x = 4
x = 3
x = 2
x = 1
Done.
Done.
Done.
Done.
Done.
As you can see, on the final call to foo(x=0), it will print "Done.". At that point, the function will return to the previous call, which will also print "Done." and so on.
In my experiment I'm showing a random generated stimulus 'x', which I need to compare to a key that's been giving in by the user of the experiment.
Basically, I have two lists:
one with the stimuli
and one with the correct answers (the keys they should give)
The order is the same, by which I mean that stimulus 1 should get the key that's at 'place 1' in the list with answers.
I've searched several topics on how to compare these two lists but so far it hasn't been working.
These are the options I've tried:
Answerruning = True
while Answerrunning:
if event.getKeys(keyList):
ReactionTime.getTime()
Keys = event.waitKeys()
for givenKey in Keys:
if givenKey == keyList:
answer_stimulus = 2
Answerrunning = False
window.flip(clearBuffer = True)
else:
answer_stimulus = 0
And this option but I think the other one is better:
keyList = []
givenKey = event.getKeys(keyList)
Answerrunning = True
while Answerrunning:
for x in stimulus:
if givenKey in keyList:
ReactionTime.getTime()
answer_stimulus = 2
Answerrunning = False
window.flip(clearBuffer = True)
else:
answer_stimulus = 0
I hope one of you can give me a hint on the problem how to compare those two en from there on my window will clear en the experiment can go on.
You don't mention this, but you really need to be using a TrialHandler object http://www.psychopy.org/api/data.html which will handle the variables for you, stepping through your conditions file (.xlsx or .csv) a row at a time for each trial. i.e. don't put the stimulus and correct response values in lists: put them in an external file, and let PsychoPy do the housekeeping of managing them trial by trial.
If you have a column in that file called correctResponse, another called stimulusText, and a TrialHandler called trials, then some pseudo-code would look like this:
trialClock = core.Clock() # just create this once, & reset as needed
# trials is a TrialHandler object, constructed by linking to an
# external file giving the details for each trial:
for trial in trials:
# update the stimulus for this trial.
# the stimulusText variable is automatically populated
# from the corresponding column in your conditions file:
yourTextStimulus.setText(stimulusText)
# start the next trial:
trialClock.reset()
answerGiven = False
while not answerGiven:
# refresh the stimuli and flip the window
stimulus_1.draw() # and whatever other stimuli you have
win.flip() # code pauses here until the screen is drawn
# i.e. meaning we are checking for a keypress at say, 60 Hz
response = event.getKeys() # returns a list
if len(response) > 0: # if so, there was a response
reactionTime = trialClock.getTime()
# was it correct?
if correctResponse in response:
answer = True
else:
answer = False
# store some data
trials.addData('Keypress', response)
trials.addData('KeypressRT', reactionTime)
trials.addData('KeypressCorrect', answer)
# can now move on to next trial
answerGiven = True
PsychoPy code is generally constructed around a cycle of drawing to the screen on every refresh, so the code above shows how within each trial, the stimulus is updated once but redrawn to the screen on every refresh. In this cycle, the keyboard is also checked once every time the screen is redrawn.
In your code, you are mixing getKeys(), which checks the instantaneous state of the keyboard, and waitKeys(), which pauses until a response is given (and hence breaks the screen refresh cycle). So gerenally avoid the latter. Also, when you use getKeys(), you have to assign the result to a variable, as this function clears the buffer. Above, you use getKeys() and then follow up by checking the keyboard again. In that case, the initial response will have disappeared, as it wasn't stored.
Clear as mud?
Sorry about the title, this is a bit of a tough question to phrase. I'm using Python. Basically, I want the program to check a variable indefinitely. If the variable goes above 100 for example, I want code block A to run only once, and then I want the program to do nothing until the variable goes back below 100, then run code block B, and wait again until the variable goes back above 100, and then run block A again, and repeat.
The current setup I've written is as follows:
while on = True:
if value_ind >= 100:
open_time = time()
else:
close_time = time()
calculate_time_open(open_time, close_time)
The obvious problem here is that whichever if/else code block is true will run itself indefinitely, and create multiple entries in my lists for only one event. So, how would I make the code blocks run only once and then wait for a change instead of repeating constantly while waiting for a change? Thanks in advance.
You can use a state machine: your program is in one of two state: "waiting for a high/low value" and behaves appropriately:
THRESHOLD = 100
waiting_for_high_value = True # False means: waiting for low value
while True: # Infinite loop (or "while on", if "on" is a changing variable)
if waiting_for_high_value:
if value_ind >= THRESHOLD:
open_time = time()
waiting_for_high_value = False
else: # Waiting for a low value:
if value < THRESHOLD:
close_time = time()
calculate_time_open(open_time, close_time)
waiting_for_high_value = True
Now, you do need to update you test value value_ind somewhere during the loop. This is best done through a local variable (and not by changing a global variable as an invisible side effect).
PS: The answer above can be generalized to any number of states, and is convenient for adding some code that must be done continuously while waiting. In your particular case, though, you toggle between two states, and maybe there is not much to do while waiting for a change, so Stefan Pochmann's answer might be appropriate too (unless it forces you to duplicate code in the two "wait" loops).
How about this?
while True:
# wait until the variable goes over 100, then do block A once
while value_ind <= 100:
pass
<block A here>
# wait until the variable goes below 100, then do block B once
while value_ind => 100:
pass
<block B here>
This solves your repetition issue. You might better actually wait rather than constantly checking the variable, though, although it depends on what you're actually doing.
Added: Here it is with the actual blocks A and B from your code and using not, which maybe makes it nicer. One of them with parentheses which maybe highlights the condition better. (And with pass not on an extra line... I think that's ok here):
while True:
while not value_ind > 100: pass
open_time = time()
while not (value_ind < 100): pass
close_time = time()
calculate_time_open(open_time, close_time)
I am trying to use a while loop to create object to populate a list of a user defined type until a certain condition is met. I want to assign a value to each object based on the number of iterations the loop has completed. For example:
class WalkingPeeps:
def___init___(self):
self.location = 0
def leftAt(self,time):
self.tleft = time
def changePos(self):
self.location += random.choice([1, -1])
objectList =[]
location_reached = False
time = 0
while not location_reached
objectList.append(WalkingPeeps())
for x in objectList:
x.tleft = time
if x.location == 20:
location_reached = True
time+=1
print("Person left at: ",x.tleft)
print("Person arrived at: ", time)
However, when it runs, it just set the time the object was created to one less than when the person reached 20. Any pointers? Hints? Thanks in advance.
In python, loops do not define their own scope. When you write
for x in objectList: ...
There variable x is created. At each step in the loop, the variable is updated. When the loop ends, the variable is not destroyed. Therefore, when you print x.tleft, you're printing the time on the last x, which by definition is 20, since you break the loop only when x.tleft == 20.
Furthermore, since you loop over every single element at each phase and update its time, you're setting each elements time to the most reccent time. Therefore, all elements have time == 20, when you terminate. What you mean, I believe, is to only update the last element
What I think you want to print, to check that your loop is working is,
for obj in objectList:
print( obj.tleft )
You would then see the expected behaviour
You also have many errors, including some syntax errors and some that make the code enter an infinite loop. This is the version I worked with, in good faith (try and make sure that the the only bugs in your code are the one's you're asking about!)
class WalkingPeeps: pass # None of the methods were relevant
objectList =[]
location_reached = False
time =0
while not location_reached:
objectList.append(WalkingPeeps())
x = objectList[-1]
x.tleft = time
# you need to check tleft, not location; location is never set
if x.tleft == 20:
location_reached = True
time+=1
print("Person left at: ",x.tleft)
print("Person arrived at: ", time)
for person in objectList: print(person.tleft)
A far more readable and concise version of this code would be:
class WalkingPerson:
def __init__(self,time=0):
self.time=time
objectList = [WalkingPerson(t) for t in range(20)]