Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trial
Valerio Versace
11,319 PointsShopping List extra credit
Hi, I'm trying to do the Python Basics shopping list extra credit. I'm having a problem with what I assume is Python variable scope.
If I do the program this way, it works:
def show_help():
print("What do you want to buy?")
print("""
Enter 'DONE' to stop adding items
Enter 'HELP' for this help.
Enter 'SHOW' to see your current list.
Enter 'SAVE' to save the list to a file (list.txt in the current folder).
""")
def print_list():
print("Here's your list:")
for item in shopping_list:
print(item)
def add_to_list(new_item):
shopping_list.append(new_item)
print("Added {}. Shopping list now has {} items.".format(new_item, len(shopping_list)))
def save_list():
with open("shopping_list", "w") as textfile:
for item in shopping_list:
textfile.write(item + "\n")
print("List saved!")
#BEGIN
shopping_list = open("shopping_list").read().splitlines()
load_list()
show_help()
while True:
new_item = input("> ")
if new_item == "DONE":
break
elif new_item == "HELP":
show_help()
elif new_item == "SHOW":
print_list()
elif new_item == "SAVE":
save_list()
else:
add_to_list(new_item)
if len(shopping_list) > 0:
print_list()
However, if I refactor the code and declare shopping_list as an empty list in the global scope and then assign it a value via a function that I make, it does not work. shopping_list is not assigned any value.
Here's the refactored code which does not work:
def show_help():
print("What do you want to buy?")
print("""
Enter 'DONE' to stop adding items
Enter 'HELP' for this help.
Enter 'SHOW' to see your current list.
Enter 'SAVE' to save the list to a file (list.txt in the current folder).
""")
def print_list():
print("Here's your list:")
for item in shopping_list:
print(item)
def add_to_list(new_item):
shopping_list.append(new_item)
print("Added {}. Shopping list now has {} items.".format(new_item, len(shopping_list)))
def load_list():
with open("shopping_list") as textfile:
shopping_list = textfile.read().splitlines()
def save_list():
with open("shopping_list", "w") as textfile:
for item in shopping_list:
textfile.write(item + "\n")
print("List saved!")
#BEGIN
shopping_list = []
load_list()
show_help()
while True:
new_item = input("> ")
if new_item == "DONE":
break
elif new_item == "HELP":
show_help()
elif new_item == "SHOW":
print_list()
elif new_item == "SAVE":
save_list()
else:
add_to_list(new_item)
if len(shopping_list) > 0:
print_list()
Any idea why, and how I could fix it (or possibly make it more elegant)? Thank you!
1 Answer
Chris Freeman
Treehouse Moderator 68,468 PointsThe difference is in referencing vs. assigning a global variable.
While you can access global variables without the global keyword, if you want to assign to them you have to use the global keyword. For example:
foo = 1
def test_creates_local():
foo = 2 # new local foo
def test_modifies_global():
global foo
foo = 3 # changes the value of the global foo
So you have two choices:
- add the
global shopping_listdeclaration inside of your functions, or - pass
shopping_listas an argument
To pass as an argument, use a mutable type:
>>> shopping_list = []
>>> def test_modifies_global(shopping_list, new_item):
... shopping_list.append(new_item) # changes the value of the global shopping_list
... print("shopping_list", shopping_list)
...
>>> test_modifies_global(shopping_list, 'apples')
shopping_list ['apples']
>>> test_modifies_global(shopping_list, 'apples')
shopping_list ['apples', 'apples']
>>> shopping_list
['apples', 'apples']
Kevin Faust
15,353 PointsKevin Faust
15,353 PointsI've read that the use of global variables is bad practice. Is this true?
Chris Freeman
Treehouse Moderator 68,468 PointsChris Freeman
Treehouse Moderator 68,468 PointsYes. Passing an argument should take precedent over using a
globalvariable, because "explicit is always better than implicit". In this case, it helps in debugging by keeping the scopes of the variables clear.For more checkout this StackOverflow: why are global variables evil
EDIT: modified answer above to provide better examples.
Valerio Versace
11,319 PointsValerio Versace
11,319 PointsThanks, it works perfectly now! So even inside functions I can always reference global variables, but never assign them unless I pass them to the function inside a parameter or reference them inside the function as "global".
Is this the case for most programming languages? I feel like this is often implied but not stressed enough.
Chris Freeman
Treehouse Moderator 68,468 PointsChris Freeman
Treehouse Moderator 68,468 PointsThe topic is called variable scope and the exact rules vary slightly for each language but the global vs local concepts are generally true.