Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ocelots - Xuan Hien Pham #5

Open
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

HienXuanPham
Copy link

No description provided.

Copy link

@kelsey-steven-ada kelsey-steven-ada left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉 Congrats on completing your first project at Ada! 🎉 I’ve added some suggestions & questions, let me know if there's anything I can clarify.

@@ -119,12 +119,12 @@ def test_moves_movie_from_watchlist_to_empty_watched():
assert len(updated_data["watchlist"]) == 0
assert len(updated_data["watched"]) == 1

raise Exception("Test needs to be completed.")
#raise Exception("Test needs to be completed.")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assertion above assert len(updated_data["watched"]) == 1 tells us that there is only one element in the watched list, but it does not guarantee that the element holds the movie data we expect. Whenever we see one of these raise Exception statements in a test file, we need to add our own assertions to complete the test.

What assertions could you add that would confirm the title, genre, and rating of the item in the watched list are what we expect?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't want to flood you with duplicate comments so I want to say here, it looks like all the tests with raise Exception("Test needs to be completed.") are missing new assertions. I recommend for your own practice to go through and try out adding assertions to complete these tests to practice syntax for tests and thinking about what data is necessary to check in order to confirm a scenario.

Comment on lines 5 to 6
if title == None or genre == None or rating == None:
return None

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice handling to return None for missing data! In Python, when we test if a variable is pointing to None the PEP8 style guide recommends using is or is not for comparison rather than operators like ==.

None is a special object in Python, it’s a singleton, meaning there is only ever one instance of None in memory. All variables holding None are actually pointing to the same instance. By using is to compare against None, we avoid issues that could be caused by a class’s custom implementation of the comparison operators, and we gain some speed over a check using == since we are checking against identity rather than looking up if the variable's held type has a comparison function that should be used.

if title is None or genre is None or rating is None :
    return None

If you’d like more info on is vs == for None, here’s a couple resources to get started =]
https://peps.python.org/pep-0008/#programming-recommendations
http://jaredgrubb.blogspot.com/2009/04/python-is-none-vs-none.html

Something else to consider: here we're explicitly checking if the values are None, but what if we got an empty string for title? If we wanted to check for empty strings at the same time as we check for None, we could rely on the truthy/falsy values of the parameters and write something like:

if not title or not genre or not rating:
    return None

@@ -1,23 +1,148 @@
# ------------- WAVE 1 --------------------

def create_movie(title, genre, rating):
pass
movie = dict()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest moving the movie declaration under the invalid data check so that we don't allocate space for movie unless we know it will be used.

Comment on lines 7 to 11
else:
movie["title"] = title
movie["genre"] = genre
movie["rating"] = rating
return movie

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it doesn't change the result of our function, I recommend removing the else so we can outdent the main flow of the function.

If an else clause doesn't change the flow of our code, then we have a statement that needs to be compiled and evaluated, but that has no benefit. Additionally, they might cause the main flow of our code to be indented, when we generally want that to be prominent to readers. I generally recommend always questioning if we need an else clause, and only adding one if it's required.

Comment on lines 13 to 16
def add_to_watched(user_data, movie):
user_data["watched"] = []
user_data["watched"].append(movie)
return user_data

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something we need to be really careful about is avoiding overwriting data that we want to preserve. In the description for the add_to_watched function, the README says:

the value of user_data will be a dictionary with a key "watched", and a value which is a list of dictionaries representing the movies the user has watched

This means that the function parameter user_data is already a dictionary that contains a watched list, and which might have values inside. Line 14 overwrites the user_data's watched list by assigning it to an empty list, losing any data that was in the argument.

How could we re-write this to preserve the data we get in the input user_data?

Comment on lines +88 to +90
user_set = user_watched(user_data)
friend_set = friends_watched(user_data)
unique_title = get_difference(user_set, friend_set)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love the use of helper functions to help organize the code!

Comment on lines 93 to 96
for title in unique_title:
for movie in user_data["watched"]:
if title == movie["title"]:
unique_watched.append(movie)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could simplify our loops a little bit by looping over user_data["watched"] and inside the loop checking if the current movie's title is in non_watch_set:

for movie in user_data["watched"]:
    if movie["title"] in unique_title:
        unique_watched.append(movie)

Comment on lines 108 to 112
for title in unique_title:
for movie in user_data["friends"]:
for watched in movie["watched"]:
if title == watched["title"] and watched not in user_has_not_watched:
user_has_not_watched.append(watched)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to the function above, we could remove one of the loops here to simplify our syntax and reduce how much we are looping over the data. What could the code for that change look like?

# -----------------------------------------
# ------------- WAVE 4 --------------------
# -----------------------------------------

def get_available_recs(user_data):
user_has_not_watched = get_friends_unique_watched(user_data)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice code reuse!

Comment on lines 121 to 125
recommended_movies = list()

for movie in user_has_not_watched:
if movie["host"] in user_data["subscriptions"]:
recommended_movies.append(movie)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice algorithm! Another way we could approach filtering the unique_watched list is with a list comprehension:

# list comprehension
result = [movie for movie in user_has_not_watched if movie["host"] in user_data["subscriptions"]]

This line is a bit long, in practice we would split a statement like this across lines, use some extra variables, or shorten some naming to keep under the PEP8 guide of 79 characters max per line:

# list comprehension
result = [movie for movie in user_has_not_watched 
         if movie["host"] in user_data["subscriptions"]]

@HienXuanPham
Copy link
Author

HienXuanPham commented Nov 12, 2022 via email

@kelsey-steven-ada
Copy link

The updates look good, nice work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants