-
Notifications
You must be signed in to change notification settings - Fork 113
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
Sea Turtles - Esther Annorzie #106
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉 You completed Unit 1! 🎉 Great work on this project, I've left some suggestions for refactoring. Take a look, and let me know if anything needs clarification!
@pytest.mark.skip | ||
@pytest.mark.integration_test | ||
# @pytest.mark.skip | ||
# @pytest.mark.integration_test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We want to comment out the @pytest.mark.skip
decorator so the test will run, but we should leave the @pytest.mark.integration_test
decorator active for all the tests in the project that use it.
The integration_test decorator directs pytest to run these tests after all of our unit tests. We want to do this because unit tests are small and isolated, making them more helpful for debugging issues. Our integration tests are larger, checking if multiple pieces are working together, which can make it harder to tell where an error came from, if one arises.
assert len(vendor.inventory) == 3 | ||
assert item not in vendor.inventory | ||
assert result == False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice checks for all the relevant data!
swap_meet/clothing.py
Outdated
super().__init__("Clothing", condition) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For all of the subclasses of Item
, we could remove the category
parameter from the child's __init__
method since we don't want folks to change that value. We always want a Clothing
object to have the category "Clothing"
, so we can decide to not even let someone pass a different value.
def __init__(self, category="", condition=0): | |
super().__init__("Clothing", condition) | |
def __init__(self, condition=0): | |
super().__init__("Clothing", condition) |
swap_meet/item.py
Outdated
return "This item has been heavily used." | ||
elif self.condition == 1: | ||
return "This item has been moderately used." | ||
elif self.condition == 2: | ||
return "This item has been partially used." | ||
elif self.condition == 3: | ||
return "This item is in good condition." | ||
elif self.condition == 4: | ||
return "This item is in great condition." | ||
elif self.condition == 5: | ||
return "This item is brand new!" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice handling for condition! It looks like the code assumes that self.condition
will always be an integer, but what if we allowed decimals like a condition of 3.5
? How could we adapt our code to convert the decimal to an int we could use here, or alternately, change the if-statements to support decimals?
Another approach for finding the condition description could be to make a dictionary that maps conditions as keys to descriptions as values. There's a trade off of using more memory creating the map variable, but if memory isn't a concern, for me, it's a little easier to read.
if not self.condition: | |
return "This item has been heavily used." | |
elif self.condition == 1: | |
return "This item has been moderately used." | |
elif self.condition == 2: | |
return "This item has been partially used." | |
elif self.condition == 3: | |
return "This item is in good condition." | |
elif self.condition == 4: | |
return "This item is in great condition." | |
elif self.condition == 5: | |
return "This item is brand new!" | |
condition_map = { | |
0: "This item has been heavily used.", | |
1: "This item has been moderately used.", | |
2: "This item has been partially used.", | |
3: "This item is in good condition.", | |
4: "This item is in great condition.", | |
5: "This item is brand new!" | |
} | |
return condition_map[self.condition] |
swap_meet/vendor.py
Outdated
inventory = [] | ||
self.inventory = inventory |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice handling of the None
default value! Another way we could write this is with a ternary operator:
if not inventory: | |
inventory = [] | |
self.inventory = inventory | |
self.inventory = inventory if inventory else [] |
This can be read as "If the parameter inventory is truthy, assign self.inventory to inventory, else set self.inventory to an empty list". The general blueprint for a ternary operator looks like: variable_name = <value_if_condition_true> if <condition_statement> else <value_if_condition_false>
.
More info: https://book.pythontips.com/en/latest/ternary_operators.html
swap_meet/vendor.py
Outdated
return False | ||
|
||
swapped_items = self.swap_items(other, their_best_item, my_best_item) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
swapped_items
sounds like it might hold Item
objects. I'd consider variable names like are_items_swapped
or did_swap_items
to more clearly represent that this is a boolean value.
swap_meet/vendor.py
Outdated
return swapped_items |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we don't perform other actions with swapped_items
before we return it, we could remove the variable assignment and directly return the value from calling self.swap_items(...)
:
swapped_items = self.swap_items(other, their_best_item, my_best_item) | |
return swapped_items | |
return self.swap_items(other, their_best_item, my_best_item) |
swap_meet/vendor.py
Outdated
for item in self.inventory: | ||
if item.category == specific_category: | ||
category_matches.append(item) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Notice this pattern of:
result_list = []
for element in source_list:
if some_condition(element):
result_list.append(element)
can be rewritten using a list comprehension as:
result_list = [element for element in source_list if some_condition(element)]
Which here would look like:
category_matches = [item for item in self.inventory if item.category == category]
At first, this may seem more difficult to read, but comprehensions are a very common python style, so try getting used to working with them!
swap_meet/vendor.py
Outdated
self.inventory.remove(item) | ||
return item | ||
return False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like inverting the logic of the condition to be able to treat it like a guard clause, which allows us to outdent the main logic of the function something like the following:
if item not in self.inventory:
return False
self.inventory.remove(item)
return item
Another approach we could take is to try to remove the item directly, and handle the ValueError
that occurs if it's not there, and return False
to handle it.
# - That all the correct items are in tai and jesse's inventories, including the items which were swapped from one vendor to the other | ||
assert item_a in tai.inventory |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice use of in
since the specification doesn't stipulate where the swapped items will end up in the output!
No description provided.