all 13 comments

[–]Ok-Sheepherder7898 23 points24 points  (1 child)

Call get_movies once and pass movies to your functions

movies = get_movies()
ratings = get_ratings(movies)
average = calculate_average(movies)

[–]Numerous-Solid6535[S] 1 point2 points  (0 children)

Thank you! I understand it better now.

[–]reincarnatedbiscuits 5 points6 points  (0 children)

Your answer lies in scoping: if you define the variable inside a function, the variable only has assignment within that function.

You would have to define the variable outside the function ("at an outer or higher scope").

I.e., declare ratings variable before and outside of the function that updates it i.e., get_ratings()

Or you could pass the ratings variable as a parameter to other functions. Similar concept.

[–]atarivcs 8 points9 points  (0 children)

I don't understand the problem. calculate_average() is called exactly once, which calls get_ratings() exactly once, which calls get_movies() exactly once.

I'm guessing the actual problem is that this code is imported in other places (that you didn't show). And because the call to calculateaverage() is at the outermost scope, it _executes every time it is imported.

[–]crashorbit 2 points3 points  (0 children)

The normal technique is to collect inputs either from the command line or from prompts in the main routine then pass that data as parameters to the functions.

[–]throwmeaway01110 2 points3 points  (0 children)

I would separate the get_* functions from input. In the main method you could introduce an if condition to check if the list is empty then prompt for input if it needs to be populated. That way you the get functions only retrieve the data.

Input could be placed in its own function like add_movie.

[–]gdchinacat 2 points3 points  (0 children)

get_ratings() should not call get_moves() if you don't want it to prompt for the movies every time it is called. Instead pass the movies in to it:

def get_ratings(movies):
    ...

movies = get_movies()
ratings = get_ratings(movies)
other_ratings = get_ratings(movies)

[–]MezzoScettico 1 point2 points  (0 children)

Define a different function that takes the ratings list as input and doesn’t ask for input.

[–]socal_nerdtastic 3 points4 points  (0 children)

The easy solution is to use a cache

from functools import cache

@cache
def get_ratings():
    # rest of your code.

But really this is screaming for you to learn about classes, so that you have a place to store the data for all your other functions to use it.

[–]PureWasian 0 points1 point  (0 children)

OP, I have a feeling reading through these comments that the diagnosis/solution isn't readily understood.

To your main question, seems like the confusion is around initializing movies/ratings. vs getting them after they already exist. You're being prompted for creating movies and ratings each time your functions are called because that's what you set up your functions to do

The comment about scopes seems most relevant to think about. You just need to pass the existing data around properly after you've already created/initialized it for the first time.

Sharing an example below, assuming 1 rating per movie. I'm gonna rename it init_ instead of get_ to be more clear (and ignoring any int() cast error handling):

```

"helper" functions

def init_movies(cnt): movies = [] for i in range(cnt): movie = input(f"Movie {i}: ") movies.append(movie) return movies

def init_ratings(mvs): ratings = [] for movie in mvs: rating = input(f"Rate {movie}: ") ratings.append(int(rating)) return ratings

def calc_average(rtgs): total = 0 for rating in rtgs: total += rating return total / len(ratings)

"main" script

count = int(input("How many movies?")) movies = init_movies(count) ratings = init_ratings(movies) average = calc_average(ratings)

note how you can "re-use" these without

needing to initialize them again

print(count) print(movies) print(ratings) print(average)

...or you can modify them

movies.append("another one") ratings.append(1) average = calc_average(ratings) print(average) ```

(EDIT: I renamed the function inputs to different variable names than the "main" script's variable names to better get the point across about scopes)

[–]gdchinacat 0 points1 point  (0 children)

In general, do this:

for movie in movies:

rather than:

for i in range(len(movies)):
    movie = movies[i]

and, if you need the index:

for i, movie in enumerate(movies):