Python Forum
return next item each time a function is executed
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
return next item each time a function is executed
#11
I have already posted all my code in in the initial post.

I think the solution to my problem is this bit here posted by @Yoriz, makes sense:

"To alter the state of which item is selected you would need to store that state to be recalled each time the code is run."

I just need an example of how to do it.
Reply
#12
The code you posted works correctly.
for applicant_name in new_applicants():
    print(f'Here we have applicant {applicant_name}.')
I want to see an example of your code where the generator is not yielding the results you want.

Yoriz is asking if you want your program to remove applicants as they are used by your program. You run your program and it asks for two applicants. The applicants are Mathew and Michael. You run your program again and ask for an applicant. The applicant is Natalie. You run your program again, ask for an applicant and are told there are no remaining applicants.

Is that what you want? If so, you will need an external applicant reference that is modified each time you ask for an applicant. This could be as simple as a file, where you read and remove the first applicant each time your function is called.

That is not what you asked for in your first post. You asked for a function that acts like an iterator. Each time the function is called it returns the next value from the list. You could write such a thing, but why? You can already get this behavior using an iterator, as I demonstrated in my reply. You could bundle this up with some syntactic sugar to make it look like a function call.
job_applicants = {'applicants': {'names': [
{'name': 'Matthew', 'key2': '...', 'key3': 'value1'}, 
{'name': 'Michael', 'key2': '...', 'key3': 'value2'}, 
{'name': 'Natalie', 'key2': '...', 'key3': 'value3'}]}}
 
def applicant_generator():
    for each_applicant in job_applicants['applicants']['names']:
        applicant_name = each_applicant['name']
        yield applicant_name

applicant_iterator = applicant_generator()

def new_applicant():
    return next(applicant_iterator)

print(new_applicant())
print(new_applicant())
print(new_applicant())
This does what you asked, but I think it is a bad idea. Why hide that you are using an iterator?
Reply
#13
I don't need to remove the applicant. In fact, I don't want to remove it. I want to cycle through the applicants. Each time a different name should appear. The order of the applicant matters.

So far I go to IDLE Python 3.8 and load up my .py file and hit the "Run" button and every time I hit "Run" I get the same name. Matthew. Michael and Natalie don't show up.
Reply
#14
You want your program to act differently each time it is run? To do that you need to change the applicant list each time you run. That will require having an external resource that is modified each time you ask for an applicant.
import json

def get_applicant():
    # Load applicants from file
    with open("applicants.json", "r") as file:
        applicants = json.load(file)

    # Get first applicant.  Move to end of applicant list
    names = applicants['applicants']['names']
    applicant = names.pop(0)
    names.append(applicant)

    # Save modified applicant list
    with open("applicants.json", "w") as file:
        json.dump(applicants, file, indent=4)

    return applicant["name"]


print(get_applicant())
The program uses a file to hold the names. This program creates the json format file use by the program above.
import json

job_applicants = {'applicants': {'names': [
{'name': 'Matthew', 'key2': '...', 'key3': 'value1'}, 
{'name': 'Michael', 'key2': '...', 'key3': 'value2'}, 
{'name': 'Natalie', 'key2': '...', 'key3': 'value3'}]}}

with open("applicants.json", "w") as file:
    json.dump(job_applicants, file, indent=4)
Here it is as 1 program.
mport json

def get_applicant():
    # Load applicants from file
    try:
       with open("applicants.json", "r") as file:
            applicants = json.load(file)
    except FileNotFoundError:
        applicants = {'applicants': {'names': [
            {'name': 'Matthew', 'key2': '...', 'key3': 'value1'}, 
            {'name': 'Michael', 'key2': '...', 'key3': 'value2'}, 
            {'name': 'Natalie', 'key2': '...', 'key3': 'value3'}]
        }}        

    # Get first applicant.  Move to end of applicant list
    names = applicants['applicants']['names']
    applicant = names.pop(0)
    names.append(applicant)

    # Save modified applicant list
    with open("applicants.json", "w") as file:
        json.dump(applicants, file, indent=4)

    return applicant["name"]


print(get_applicant())
User3000 likes this post
Reply
#15
Would itertools.cycle not work in my case?
Reply
#16
Would itertools.cycle not work in my case?
No. Cycle will restart the sequence when you reach the end. It will not remember what you were doing the last time you ran the program. For that. For that, you need something to remember where you were. See my previous post for example.

Another approach is save the index of the next applicant in a file.
applicants = {'applicants': {'names': [
    {'name': 'Matthew', 'key2': '...', 'key3': 'value1'}, 
    {'name': 'Michael', 'key2': '...', 'key3': 'value2'}, 
    {'name': 'Natalie', 'key2': '...', 'key3': 'value3'}]
}}


def get_applicant():
    # Load index from file
    try:
        with open("applicants.index", "r") as file:
            index = int(file.read())
    except (FileNotFoundError, ValueError):
        index = 0

    applicant = applicants['applicants']['names'][index]

    # Update the index file
    index = (index + 1) % len(applicants['applicants']['names'])
    with open("applicants.index", "w") as file:
        file.write(str(index))

    return applicant["name"]


print(get_applicant())
User3000 likes this post
Reply
#17
Eureka, it works!

Yes, finally Big Grin

Thank you so much.

edit: indeed, the version with an index file works just as fine. Awesome!

(Aug-06-2023, 01:07 PM)deanhystad Wrote: Would itertools.cycle not work in my case?
No. Cycle will restart the sequence when you reach the end. It will not remember what you were doing the last time you ran the program. For that. For that, you need something to remember where you were. See my previous post for example.

I think this is rather interesting. I have actually a similar scenario where it doesn't need to remember the last position. So it can restart at the beginning. Import thing is to cycle through the different names.
So then itertools.cycle would work right?

If it's not too much to ask for, what would that look like code wise? With itertools.cycle.

Impressed Dance
Reply
#18
Next time post an example of your code that shows it not working. Lucky for you that Yoriz guessed the issue or we would still be trying to get to the root of the problem.

itertools.cycle works if you want to cycle through a sequence forever. Cycling through 'ABC' results in ABCABCABCABC... If you don't use cycle, the sequence is played out once and a StopIteration exception is raised with you run out of values.
from itertools import cycle

a = cycle('ABC')
b = iter('ABC')

while True:
    print("a", next(a))
    print("b", next(b))
Output:
a A b A a B b B a C b C a A Traceback (most recent call last): File "c:\Users\djhys\Documents\python\musings\junk.py", line 8, in <module> print("b", next(b)) ^^^^^^^ StopIteration
Reply
#19
Absolutely! let's jus say describing the problem is always the hardest part.

About itertools.cycle:

this is again like before. Not what I want.

So whenever I run the script it should start from the beginning and cycle through each name. Not printing everything at once.

I am considering this because it doesn't involve another file like the index file or a json.

Appreciated!
Reply
#20
If anything is "printing everything at once", that is your code, not anything to do with iterators. If you want to use an iterator outside a for loop, use next() as I showed in my first response to your post.

Again, please post an example showing what your are trying to do and describe how it doesn't work.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  nested function return MHGhonaim 2 620 Oct-02-2023, 09:21 AM
Last Post: deanhystad
  How to not open the context menu if a mouse gesture is executed? MicheliBarcello 2 673 Aug-22-2023, 02:47 PM
Last Post: deanhystad
  code not working when executed from flask app ThomasDC 1 900 Jul-18-2023, 07:16 AM
Last Post: ThomasDC
  function return boolean based on GPIO pin reading caslor 2 1,192 Feb-04-2023, 12:30 PM
Last Post: caslor
  return vs. print in nested function example Mark17 4 1,757 Jan-04-2022, 06:02 PM
Last Post: jefsummers
  Remove an item from a list contained in another item in python CompleteNewb 19 5,776 Nov-11-2021, 06:43 AM
Last Post: Gribouillis
  time function does not work tester_V 4 3,052 Oct-17-2021, 05:48 PM
Last Post: tester_V
  How to invoke a function with return statement in list comprehension? maiya 4 2,865 Jul-17-2021, 04:30 PM
Last Post: maiya
  Function - Return multiple values tester_V 10 4,468 Jun-02-2021, 05:34 AM
Last Post: tester_V
  Why recursive function consumes more of processing time than loops? M83Linux 9 4,276 May-20-2021, 01:52 PM
Last Post: DeaD_EyE

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020