Skip to content

Ocelots - Xuan Hien Pham#5

Open
HienXuanPham wants to merge 7 commits intoada-ac2:masterfrom
HienXuanPham:master
Open

Ocelots - Xuan Hien Pham#5
HienXuanPham wants to merge 7 commits intoada-ac2:masterfrom
HienXuanPham:master

Conversation

@HienXuanPham
Copy link
Copy Markdown

No description provided.

Copy link
Copy Markdown

@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.

Comment thread tests/test_wave_01.py
assert len(updated_data["watched"]) == 1

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

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?

Copy link
Copy Markdown

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 thread viewing_party/party.py Outdated
Comment on lines +5 to +6
if title == None or genre == None or rating == None:
return None
Copy link
Copy Markdown

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

Comment thread viewing_party/party.py Outdated

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

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 thread viewing_party/party.py Outdated
Comment on lines +7 to +11
else:
movie["title"] = title
movie["genre"] = genre
movie["rating"] = rating
return movie
Copy link
Copy Markdown

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 thread viewing_party/party.py
Comment on lines +13 to +16
def add_to_watched(user_data, movie):
user_data["watched"] = []
user_data["watched"].append(movie)
return user_data
Copy link
Copy Markdown

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 thread viewing_party/party.py
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)
Copy link
Copy Markdown

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 thread viewing_party/party.py Outdated
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)
Copy link
Copy Markdown

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 thread viewing_party/party.py Outdated
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)
Copy link
Copy Markdown

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?

Comment thread viewing_party/party.py
# -----------------------------------------

def get_available_recs(user_data):
user_has_not_watched = get_friends_unique_watched(user_data)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Nice code reuse!

Comment thread viewing_party/party.py Outdated
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)
Copy link
Copy Markdown

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
Copy Markdown
Author

HienXuanPham commented Nov 12, 2022 via email

@kelsey-steven-ada
Copy link
Copy Markdown

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