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

Python Python Basics All Together Now Cleaner Code Through Refactoring

Can I make my code more concise?

Wherever possible, I'd like to:

  • Reduce the number of parameters of some functions
  • Break the functions up into smaller logical units

Questions:

  • Does create_order() do too much?
  • confirm_purchase() and purchase_tickets() both have the same parameters. Is it possible to avoid this?

Something unique I did was create bitcoin.py in order to get the current exchange rate of bitcoin in real time.

(I didn't follow along with the tutorial at all). If you want to run the code (without the line numbers,) I also have a Github repo here

main.py

1   import sys
2   import bitcoin
3   
4   tickets_stock = 200
5   USD_TICKET_PRICE = 14
6   event = 'Monty Python Q&A Session'
7   bitcoin_exchange_rate = bitcoin.bitcoin_price()
8   name = input('What is your name?: ').title()
9   
10  
11  def print_welcome():
12      if tickets_stock == 0:
13          sys.exit('Sorry we\'re all out of tickets!')
14  
15      print(f'\nHello {name}!')
16      print('\n----------------------\n')
17      print('Welcome to the CLI Ticketing System')
18      print('----------------------\n')
19  
20      print(f'We are currently selling tickets for the {event}')
21      print(f'Each ticket costs: ${USD_TICKET_PRICE}\n')
22  
23  
24  def show_ticket_stock():
25      if tickets_stock == 1:
26          print('We\'re down to our last ticket!')
27      elif 1 < tickets_stock < 100:
28          print(f'Buy now! We only have {tickets_stock} tickets remaining!\n')
29      elif tickets_stock > 100:
30          print(f'There are currently {tickets_stock} tickets remaining.')
31  
32  
33  def ticket_quantity_request():
34      while True:
35          try:
36              tickets_request = int(input('How many tickets would you like to purchase?: '))
37              while tickets_request > tickets_stock:
38                  print(f'Sorry, we only have {tickets_stock} tickets in stock! Try again...\n')
39                  tickets_request = int(input('How many tickets would you like to purchase?: '))
40              return tickets_request
41          except ValueError:
42              print('\nOops! That was an invalid number. Try again...')
43  
44  
45  def calculate_purchase_cost(tickets):
46      return tickets * USD_TICKET_PRICE
47  
48  
49  def usd_to_bitcoin(cost):
50      return cost / bitcoin_exchange_rate
51  
52  
53  def ask_for_payment_method():
54      while True:
55          try:
56              payment_method = input('Will you be paying using a Credit Card or by Bitcoin? (c/b): ')
57              if payment_method == 'c':
58                  print('\nSelected payment method: Credit Card\n')
59                  return 'usd'
60              elif payment_method == 'b':
61                  print('\nSelected payment method: Bitcoin\n')
62                  return 'bitcoin'
63              else:
64                  print(f'Hmm... I didn\'t understand {payment_method}')
65          except BaseException as e:
66              print('\nHmm, there was an error: ' + str(e))
67  
68  
69  def payment_method_symbol(payment_method):
70      if payment_method == 'bitcoin':
71          return '฿'
72      elif payment_method == 'usd':
73          return '$'
74  
75  
76  def cost_string(symbol, cost):
77      return f'{symbol}{cost}'
78  
79  
80  def cost_string_after_considering_payment_method(tickets, payment_method):
81      usd_cost = calculate_purchase_cost(tickets)
82      currency_symbol = payment_method_symbol(payment_method)
83      if payment_method == 'usd':
84          return cost_string(currency_symbol, usd_cost)
85      elif payment_method == 'bitcoin':
86          cost_in_bitcoin = usd_to_bitcoin(usd_cost)
87          return cost_string(currency_symbol, cost_in_bitcoin)
88  
89  
90  def confirm_purchase(tickets, string):
91      while True:
92          response = input(f'You are purchasing {tickets} tickets for {string}. '
93                           f'\nIs this order correct? (y/n): ')
94          if response == 'y':
95              purchase_tickets(tickets, string)
96              return tickets
97          elif response == 'n':
98              print(f'Cancelling order...')
99              break
100         elif response == ('exit' or 'e' or 'c' or 'cancel'):
101             print('Your order was canceled')
102             sys.exit()
103         else:
104             print(f'\nHmm, I don\'t recognize the option "{response}"...\n')
105 
106 
107 def purchase_tickets(tickets, string):
108     response = input('Purchase tickets (p): ')
109     if response == 'p':
110         print('\nPurchase complete...')
111 
112         print(f'\n\nPurchase Confirmation for {name}:')
113         print('---------------')
114         print(f'Thank you {name}! Your payment of {string} was received.')
115         print('\n***')
116         print(f'Congratulations! You now have {tickets} tickets to the "{event}"')
117         print('***')
118         sys.exit()
119     else:
120         print('goodbye...')
121         sys.exit()
122 
123 
124 def create_order():
125     ticket_quantity = tick et_quantity_request()
126     payment_method = ask_for_payment_method()
127     show_cost = cost_string_after_considering_payment_method(ticket_quantity, payment_method)
128     confirm_purchase(ticket_quantity, show_cost)
129     purchase_tickets(ticket_quantity, show_cost)
130     return
131 
132 
133 def main():
134     print_welcome()
135     show_ticket_stock()
136     create_order()
137 
138 
139 if __name__ == '__main__':
140     main()
141 

bitcoin.py

1   import json
2   
3   
4   def bitcoin_price():
5       try:
6           import urllib.request as urllib2
7       except ImportError:
8           raise ImportError('There was a problem importing urllib2')
9   
10      url = "http://api.coindesk.com/v1/bpi/currentprice/EUR.json"
11  
12      json_url = urllib2.urlopen(url)
13      json_object = json.load(json_url)
14  
15      exchange_rate = json_object['bpi']['USD']['rate']
16  
17      return float(exchange_rate.replace(',', ''))
18  

I would be grateful for any improvements you are able to provide.

1 Answer

Jeff Muday
MOD
Jeff Muday
Treehouse Moderator 28,722 Points

Nice work! Your program was written in a very clear manner and easy to follow.

Your create_order() doesn't need to be broken down any further. I would not worry about duplicated parameter passing in this scenario since you are adhering to the best practices of the functional programming paradigm.

I don't think I would change anything.

But the stubborn old project manager I had when I was first starting out was insistent on best practices. Two of the software engineering principles he insisted upon were to "minimize exit points" and to "have meaningful return values from functions and programs."

In that spirit, you could possibly create a single exit point from main(). Currently, your program can sys.exit() in two different ways confirm_purchase() and purchase_tickets().

Another thing would be to add an argument to your sys.exit() indicating successful completion of the program like a sys.exit(0) if tickets were sold, and sys.exit(1) if the user canceled the sale.

(By convention, zero is used when termination is normal and 1 is canceled or abnormal termination)

https://stackoverflow.com/questions/9426045/difference-between-exit0-and-exit1-in-python

Keep up the good work!