Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
if else statements
#1
class Store:
    Day = 1
    Money = 5
    StoreName = "Lemonade Stand"
    StoreCount = 1
    StoreCost = 3
    StoreProfit = 1.5
    StoreList = []

    def __init__(self, StoreName, StoreCount, StoreCost, StoreProfit):
        self.StoreName = StoreName
        self.StoreCount = StoreCount
        self.StoreCost = StoreCost
        self.StoreProfit = StoreProfit

    @staticmethod
    def DisplayGameInfo(self):
        print("-----------------------------------")
        print("Day #" + str(self.Day))
        print("Money = ${:0,.2f}".format(self.Money))

    @staticmethod
    def DisplayStoreInfo(self):

        print("Store Name : %s, StoreCount = #%d " % (self.StoreName, self.StoreCount))
        print("-----------------------------------")

    def BuyStore(self):
        if self.StoreCost <= Store.Money:
            self.StoreCount += 1
            Store.Money -= self.StoreCost
        else:
            print("You don't have enough money")

    def NextDay(self):
        self.Day += 1
        DailyProfit = self.StoreProfit * self.StoreCount
        Store.Money += DailyProfit


Store.StoreList.append(Store)

while True:
    Store.DisplayGameInfo(Store)
    Store.DisplayStoreInfo(Store)

    print("Available Options (N)ext Day, (B)uy Store, (E)xit")
    Choice = input('Please select an option')

    if Choice is 'B' or 'b':
        Store.StoreList[0].BuyStore(Store)

    elif Choice is 'N' or 'n':
        Store.StoreList[0].NextDay(Store)

    elif Choice is 'E' or 'e':
        break
    else:
        print("Bad Input")

print("Thanks for playing Idle Tycoon")
This shows there is no error, but when in run it and choose the first if statement, it only executes that statement and if i choose to execute the second if statement, it will just keep ignoring my command and continue to run the first if statement.
#NB the ide that i'm using is intellij and i'm also just a beginner
So anyone can help me? will appreciate it a lot. 've been stuck here for days and almost want to give up
Reply
#2
This line if Choice is 'B' or 'b': is never False.

Please read the following post:
https://python-forum.io/Thread-Multiple-...or-keyword
Reply
#3
Thanks very much for this detailed explanation. Its very helpful and i definitely will be needing your assistance in the future again as i continue on the path to be a self taught programmer. Huge thank you
Reply
#4
[EDITED]
(Sep-14-2018, 10:05 AM)remy Wrote:
class Store:
    Day = 1
    Money = 5
    StoreName = "Lemonade Stand"
    StoreCount = 1
    StoreCost = 3
    StoreProfit = 1.5
    StoreList = []
This code is absolutely redundant - it creates class attributes with the same names as object attributes. It may cause a confusion and is a definite anti-pattern (not class attributes themselves, your usage). See the example below

(Sep-14-2018, 10:05 AM)remy Wrote:
class Store:
    @staticmethod
    def DisplayGameInfo(self):
        print("-----------------------------------")
        print("Day #" + str(self.Day))
        print("Money = ${:0,.2f}".format(self.Money))

    @staticmethod
    def DisplayStoreInfo(self):

        print("Store Name : %s, StoreCount = #%d " % (self.StoreName, self.StoreCount))
        print("-----------------------------------")
Those are wrong cases for staticmethod decorator - those should be regular methods. Staticmethods in Python should not contain self as a parameter - and should not address object/class attributes. The are just independent functions in the class namespace (and are seldom useful).

Take a look at this small experiment that explains my points
Output:
In [15]: class AntiPattern: ...: attr = 1 ...: def __init__(self, attr): ...: self.attr = attr ...: @staticmethod ...: def show_attr(self): ...: return self.attr ...: In [16]: a = AntiPattern(10) In [17]: a.attr Out[17]: 10 In [18]: AntiPattern.attr Out[18]: 1 In [19]: a.show_attr() --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-19-0d2c01c460f9> in <module>() ----> 1 a.show_attr() TypeError: show_attr() missing 1 required positional argument: 'self'
The last - but not the least - your names are un-Pythonic, see PEP-8 for guidance

PS I was wondering why your code worked - here's why, you don't instantiate the class, you use it as is! Your __init__ method is never called. This is an absolutely wrong approach for OOP.
Test everything in a Python shell (iPython, Azure Notebook, etc.)
  • Someone gave you an advice you liked? Test it - maybe the advice was actually bad.
  • Someone gave you an advice you think is bad? Test it before arguing - maybe it was good.
  • You posted a claim that something you did not test works? Be prepared to eat your hat.
Reply
#5
volcano63 pointed out why your use of class attributes is a problem. If you want to set it up that a store where the name is specified is called a lemonade stand by default, use defaults in the paramters to the __init__ method:

def __init__(self, StoreName = 'Lemonade Stand', StoreCost = 3, StoreProfit = 1.5):
If left out StoreCount, because that sounds like something that should be a class attribute, one that is incremented every time __init__ is called.
Craig "Ichabod" O'Brien - xenomind.com
I wish you happiness.
Recommended Tutorials: BBCode, functions, classes, text adventures
Reply
#6
The problem is that the code in OP - besides everything - is used to both to store list of stores (pun unintended) and actual stores. Class attributes mask the design flaw, creating an illusion of a working code.

In a properly designed implementation, Store class must contain a record of an individual store; container for stores may be another class, a dictionary or a list - but not the same class that contains the individual store record.
Test everything in a Python shell (iPython, Azure Notebook, etc.)
  • Someone gave you an advice you liked? Test it - maybe the advice was actually bad.
  • Someone gave you an advice you think is bad? Test it before arguing - maybe it was good.
  • You posted a claim that something you did not test works? Be prepared to eat your hat.
Reply
#7
I've taken the liberty of hacking around your code somewhat to produce a working version. This is not a particularly elegant approach, but it addresses many of the points @volcano63 raised.

The class attributes are used as either default values for instances OR as actual attributes for the class to represent the overall position of all stores.

Note the debt value, used to hold the total cost of stores bought so far (otherwise it is not clear which store is paying); thus, the money in each store instance is the total income w/o purchase costs.

The money attribute in class is updated to be the total of all of the stores less the debt.

The stores are held as a list of store instances.

class Store:
    day = 1
    money = 0
    count = 0
    debt = 0
 
    def __init__(self, store_name, store_count, store_cost, store_profit):
        self.name = store_name
        self.count = store_count
        self.cost = store_cost
        self.profit = store_profit
        self.money = 0
    
    @classmethod
    def update(cls, store_list):
        cls.count = 0
        cls.money = 0
        for store in store_list:
            cls.count += store.count
            cls.money += store.money
        cls.money += cls.debt
        
    @classmethod
    def display_game_info(cls):
        print("=" * 20)
        print("Total Stores #" + str(cls.count))
        print("Total Money = ${:0,.2f}".format(cls.money))
        print("=" * 20)
         
    def display_store_info(self):
        print("-----------------------------------")
        print(f"Store Name : {self.name}, StoreCount = #{self.count}")
        print(f"Day #{self.day:<3} Money = ${self.money:0,.2f}")
        print("-----------------------------------")
 
    
    @staticmethod
    def get_details():
        'get details from user - this needs validation/defaults adding'
        print('Details of new store (or group of stores)\n')
        name = input('Name of new store(s)? ')
        store_count = int(input('Number of stores in group? '))
        store_cost = float(input('Total cost of new store(s)? '))
        store_profit = float(input('Daily profit per store? '))
        return name, store_count, store_cost, store_profit
                          
    @classmethod
    def buy_store(cls, store_list, store_name='store', store_count=1, store_cost=store_cost, store_profit=100 ):
        if store_cost <= cls.money:
            store_list.append(cls(store_name, store_count, store_cost, store_profit))
            cls.debt -= store_cost
        else:
            print("You don't have enough money")
 
    def next_day(self):
        self.day += 1
        daily_profit = self.profit * self.count
        self.money += daily_profit
 
store_list = []
store_cost = 500
Store.buy_store(store_list,"Lemonade", store_count=1, store_cost=0, store_profit=200)
 
while True:
    Store.update(store_list)
    Store.display_game_info()
    for store in store_list:
        store.display_store_info()
    print("\nAvailable Options (N)ext Day, (B)uy Store, (E)xit")
    choice = input('Please select an option').lower()
    if choice == 'b':
        Store.buy_store(store_list, *Store.get_details())
    elif choice == 'n':
        for store in store_list:
            store.next_day()
    elif choice in 'ex':
        break
    else:
        print("Bad Input")
 
print("Thanks for playing Idle Tycoon")
I am trying to help you, really, even if it doesn't always seem that way
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020