How to add custom parameter parameter in python functions? - python

My name is Piyush and I have just started learning to code in python. Right now I am working on a project. And would really appreciate if anyone can help in adding customized parameters in functions.
I am mentioning my code and the problem I am facing down below:
class Chips ():
def __init__ (self, total):
while True:
try:
total = int(input("How many chips as total?: ?"))
except:
print("Please enter an integer")
else:
break
self.total = total
self.bet = 0
def win_bet (self):
self.total = self.total + self.bet
def loose_bet (self):
self.total = self.total - self.bet
However, I can set total = 100 and can run the game but I want the user to be able to enter the total chips he/she wants to add.
I want the input(total) in the while loop to be as the argument while running the game. But I keep on getting this error:
--
TypeError Traceback (most recent call last)
<ipython-input-9-b1b7b1c195f7> in <module>()
367
368 # Set up the Player's chips
--> 369 player_chips = Chips() # remember the default value is 100
370
371 # Prompt the Player for their bet:
TypeError: __init__() missing 1 required positional argument: 'total'
Please Help!
Thanks for your attention to my request.

Your class takes a parameter in its constructor, but you also read it from the input in your constructor.
I think you are confused in what you are trying to achieve here.
Option 1:
If the caller of your code (the code that constructs your class), can be modified and know the total at the instance creation time, just add the parameter in the constructor call.
total = 100
player_chips = Chips(total)
Option 2:
in case you can't modify the caller, (most likely from what I read), then that means you want to actually read the total from the input. Remove the argument from your constructor.
def __init__ (self):
instead of
def __init__(self, total):

You should add method get_total_from_user and set default param in constructor
class Chips ():
def __init__ (self, total=None):
self.total = self.get_total_from_user() if not total else total
self.bet = 0
def win_bet (self):
self.total = self.total + self.bet
def loose_bet (self):
self.total = self.total - self.bet
def get_total_from_user(self):
while True:
try:
return int(input("How many chips as total?: ?"))
except:
print("Please enter an integer")
else:
break
It allows you to get total from user
Chips()
Or you can set it via passing value
Chips(100)

c = Chips(100)
at the bottom of your code - no error. You override the value of total in the interactive constructor, but hey, you promised "init" you were sending it.
c = Chips()
works if you change your signature to:
def __init__ (self, total):
The interactive constructor seems like a very bad idea overall.

Related

4 Classes, 1 performs actions and asks for input, the others keep track of values

I'm working on a project for CS1410, where I need to simulate a Coffee Machine. I have quite a bit so far, but I'm a bit stuck, specifically with these questions:
In the class CashBox, under the function deposit, I'm trying to add the values together from any coins inserted in the oneAction function from the CoffeeMachine class. However I get the error "'CoffeeMachine' object has no attribute 'credit'" and I'm struggling with understanding why. I can tell it's an inheritance problem, but I'm unsure exactly how to fix it.
How should I format it so that when I get the input in oneAction(), I can take that input and mess with it in the cashBox? What am I doing wrong with self.something, and how can I recognize when to use self, and when to just use a normal variable
I wasn't sure how to upload the code so that the problem is reproducible without giving at least this file, it's all pretty tied together. Some advice on how I could have presented this better would be helpful as well.
Past the original question, any further advice would be seriously appreciated.
Seriously.
Thank you all, hopefully the code is pretty readable.
class CashBox(object):
def __init__(self):
self.credit = 0
self.totalReceived = 0.0
def deposit(self,amount):
self.credit = amount + self.credit
self.totalReceived = amount + self.totalReceived
print(self.totalReceived,self.credit)
def returnCoins(self):
print("Returning ", self.totalReceived, " cents.")
self.totalReceived = 0.0
def haveYou(self,amount):
return self.credit >= amount
def deduct(self,amount):
pass
def totalCoins(self):
return self.totalReceived
class CoffeeMachine(object):
def __init__(self):
self.cashBox = CashBox()
self.selector = self.cashBox
def oneAction(self):
while True:
command = input("""
______________________________________________________
PRODUCT LIST: all 35 cents, except bouillon (25 cents)
1=black, 2=white, 3=sweet, 4=sweet & white, 5=bouillon
Sample Commands: insert 25, select 1. Your command:
""")
words = command.lower().split()
if 'select' in words:
Selector.select(self,int(words[1]))
print("Great selection!")
elif 'insert' in words:
coinsAllowed = [5,10,25,50]
if int(words[1]) in coinsAllowed:
CashBox.deposit(self,int(words[1]))
else:
print("""
That is not one of the allowed coins,
please insert a penny, nickel, dime, quarter,
or half-dollar. Thank you.
""")
elif 'cancel' in words:
print("Cancelling transaction. Returning to main menu: ")
CashBox.returnCoins(self)
elif 'quit' in words:
print("Have a nice day!")
else:
print("That is not an option")
def totalCash(self):
pass
class Product(object):
def __init__(self,name,price,recipe):
self.name = name
self.price = price
self.recipe = recipe
def getPrice(self):
return self.price
def make(self):
print(self.recipe)
class Selector(object):
def __init__(self):
self.cashBox = CashBox
self.products = []
#self.products.append(Product.
def select(self, choiceIndex):
pass
def main():
m = CoffeeMachine()
while m.oneAction():
pass
#total = m.totalCash()
#print(f"Total Cash: ${total/100:.2f}")
if __name__ == "__main__":
main()
Exception has occurred: AttributeError
'CoffeeMachine' object has no attribute 'credit'
File "C:\Users\Tanner Harmer\Desktop\Coffee2\CashBox.py", line 7, in deposit
self.credit = amount + self.credit
File "C:\Users\Tanner Harmer\Desktop\Coffee2\CashBox.py", line 46, in oneAction
CashBox.deposit(self,int(words[1]))
File "C:\Users\Tanner Harmer\Desktop\Coffee2\CashBox.py", line 89, in main
while m.oneAction():
File "C:\Users\Tanner Harmer\Desktop\Coffee2\CashBox.py", line 95, in <module>
main()
You're calling the CashBox by using the class name, like if the method were static, but you created an instance of this class (in the constructor self.cashBox = CashBox()) so use it
CashBox.deposit(self,int(words[1])) // OLD, NO
self.cashBox.deposit(self,int(words[1])) // YES
use the cashBox of the CoffeeMachine

Is there a way to fix Name Error due to scope?

I have a function that creates a player object but when referencing the object, I get a NameError. I think it is happening due to local scope but global should fix it...
I just started out OOP and this code is working in the python shell but it is not working in script mode.
endl = lambda a: print("\n"*a)
class Score:
_tie = 0
def __init__(self):
self._name = ""
self._wins = 0
self._loses = 0
def get_name(self):
print
self._name = input().upper()
def inc_score(self, wlt):
if wlt=="w": self._wins += 1
elif wlt=="l": self._loses += 1
elif wlt=="t": _tie += 1
else: raise ValueError("Bad Input")
def player_num(): #Gets number of players
while True:
clear()
endl(10)
print("1 player or 2 players?")
endl(5)
pnum = input('Enter 1 or 2: '.rjust(55))
try:
assert int(pnum) == 1 or int(pnum) == 2
clear()
return int(pnum)
except:
print("\n\nPlease enter 1 or 2.")
def create_player(): #Creates players
global p1
p1 = Score()
yield 0 #stops here if there is only 1 player
global p2
p2 = Score()
def pr_(): #testing object
input(p1._wins)
input(p2._wins)
for i in range(player_num()):
create_player()
input(p1)
input(p1._wins())
pr_()
wherever I reference p1 I should get the required object attributes but I'm getting this error
Traceback (most recent call last):
File "G:/Python/TicTacTwo.py", line 83, in <module>
input(p1)
NameError: name 'p1' is not defined
Your issue is not with global but with the yield in create_player(), which turns the function into a generator.
What you could do:
Actually run through the generator, by executing list(create_player()) (not nice, but works).
But I suggest you re-design your code instead, e.g. by calling the method with the number of players:
def create_player(num): #Creates players
if num >= 1:
global p1
p1 = Score()
if num >= 2:
global p2
p2 = Score()
If you fix this issue, the next issues will be
1) input(p1) will print the string representation of p1 and the input will be lost, you probably want p1.get_name() instead.
2) input(p1._wins()) will raise TypeError: 'int' object is not callable
I will redesign the app to introduce really powerful python constructs that may help you when getting into OOP.
Your objects are going to represent players, then don't call them Score, call them Player.
Using _tie like that makes it a class variable, so the value is shared for all the players. With only two participants this may be true but this will come to hurt you when you try to extend to more players. Keep it as a instance variable.
I am a fan of __slots__. It is a class special variable that tells the instance variables what attributes they can have. This will prevent to insert new attributes by mistake and also improve the memory needed for each instance, you can remove this line and it will work but I suggest you leave it. __slots__ is any kind of iterable. Using tuples as they are inmutable is my recomendation.
Properties are also a really nice feature. They will act as instance attribute but allow you to specify how they behave when you get the value (a = instance.property), assign them a value (instance.property = value), or delete the value (del instance.property). Name seems to be a really nice fit for a property. The getter will just return the value stored in _name, the setter will remove the leading and trailing spaces and will capitalize the first letter of each word, and the deletter will set the default name again.
Using a single function to compute a result is not very descriptive. Let's do it with 3 functions.
The code could look like this:
# DEFAULT_NAME is a contant so that we only have to modify it here if we want another
# default name instead of having to change it in several places
DEFAULT_NAME = "Unknown"
class Player:
# ( and ) are not needed but I'll keep them for clarity
__slots__ = ("_name", "_wins", "_loses", "_ties")
# We give a default name in case none is provided when the instance is built
def __init__(self, name=DEFAULT_NAME):
self._name = name
self._wins = 0
self._loses = 0
self._ties = 0
# This is part of the name property, more specifically the getter and the documentation
#property
def name(self):
""" The name of the player """
return self._name
# This is the setter of the name property, it removes spaces with .strip() and
# capitalizes first letters of each word with .title()
#name.setter
def name(self, name):
self._name = name.strip().title()
# This is the last part, the deleter, that assigns the default name again
#name.deleter
def name(self):
self._name = DEFAULT_NAME
def won(self):
self._wins += 1
def lost(self):
self._loses += 1
def tied(self):
self._ties += 1
Now that's all we need for the player itself. The game should have a different class where the players are created.
class Game:
_min_players = 1
_max_players = 2
def __init__(self, players):
# Check that the number of players is correct
if not(self._min_players <= players <= self._max_players):
raise ValueError("Number of players is invalid")
self._players = []
for i in range(1, players+1):
self._players.append(Player(input("Insert player {}'s name: ".format(i))))
#property
def players(self):
# We return a copy of the list to avoid mutating the inner list
return self._players.copy()
Now the game would be created as follows:
def new_game():
return Game(int(input("How many players? ")))
After that you would create new methods for the game like playing matches that will call the players won, lost or tied method, etc.
I hope that some of the concepts introduced here are useful for you, like properties, slots, delegating object creation to the owner object, etc.

Python - Unexpected behaviour of class attributes

Edited in simple words
code:
class temp:
attr1 = 0
attr2 = []
t1 = temp()
t2 = temp()
t1.attr1 = 50
t1.attr2.append(50)
print(t1.attr1)
print(t1.attr2)
print(t2.attr1)
print(t2.attr2)
output:
50
[50]
0
[50]
I have called append only on attr2 object t1 but the append changes attr2 of both objects. if attr2 is shared (class attributes) then why does attr1 values are different for t1 and t2. What might have caused this unexpected behaviour ?
old question
I am writing a python code for blackjack. The code I have written is as follows.
from random import randint
from IPython.display import clear_output
deck = ["S","D","C","H"]
class Player:
cards = []
total = 0
amount = 0
def __init__(self,money=0):
self.amount = money
def busted(self):
return self.total > 21
def showCards(self):
for i in self.cards:
print("| {}{} |".format(i%13,deck[i//13]),end = " ")
print()
def hit(self):
no = randint(1,53)
self.cards.append(no)
if no % 13 == 1:
if self.total + 11 > 21:
self.total+=1
else:
self.total+=11
else:
self.total += (no%13 if no%13 <= 10 else 10)
dealer = Player(10000)
p1 = Player(0)
print("Welcome to BlackJack ....")
while True:
try:
p1.amount = int(input("Enter the amount you currrently have for the game"))
except:
print("invalid Value")
continue
else:
break
Game = True
while Game:
print(dealer.cards)
print(p1.cards)
dealer.hit()
print(dealer.cards)
print(p1.cards)
print(dealer.total)
print(p1.total)
Game = False
output of this code is as follows
Welcome to BlackJack ....
Enter the amount you currrently have for the game55
[]
[]
[45]
[45]
6
0
as you can see I had called hit() only once on dealer object but it is appending it to cards attribute of both dealer as well as p1 object. However total attribute is different. Can anyone explain what might have caused this unexpected behaviour ?
When you do t1.attr1 = 50, you're rebinding attr1 to a new value in the t1 object's attribute namespace. It previously let you access the value bound in the class namespace, but when you bind a new value, you hide the one from the class (for that instance only).
In contrast, when you do t1.attr2.append(50), you're mutating the existing list (which is bound in the class namespace, but is visible though all instances) in place, with no rebinding of variables happening at all. This is why you see the change in t2. The variables t1.attr2 and t2.attr2 are both references to the same object (which you can verify using the is operator: t1.attr2 is t2.attr2).
In general, it's usually not a good idea to use lists or other mutable values for class variables if you don't want them to be shared by all instances. It's not forbidden though, because sometimes you do specifically do want the shared behavior.
I got what you are asking. You need to differentiate all cards with player cards. So, instead of naming everything as cards, I would suggest doing this:
class Player:
all_cards = []
total = 0
amount = 0
and update __init__ as :
def __init__(self, money=0):
self.amount = money
self.player_cards = []
while doing append operation, append it to all_cards and to the player_cards. Anyway, you are printing only player cards, you can see different list of cards.
Here is full code :
from random import randint
from IPython.display import clear_output
deck = ["S","D","C","H"]
class Player:
all_cards = []
total = 0
amount = 0
def __init__(self,money=0):
self.player_cards = []
self.amount = money
def busted(self):
return self.total > 21
def showCards(self):
for i in self.player_cards:
print("| {}{} |".format(i%13,deck[i//13]),end = " ")
print()
def hit(self):
no = randint(1,53)
self.player_cards.append(no)
self.all_cards.append(no)
if no % 13 == 1:
if self.total + 11 > 21:
self.total+=1
else:
self.total+=11
else:
self.total += (no%13 if no%13 <= 10 else 10)
dealer = Player(10000)
p1 = Player(0)
print("Welcome to BlackJack ....")
while True:
try:
p1.amount = int(input("Enter the amount you currrently have for the game"))
except:
print("invalid Value")
continue
else:
break
Game = True
while Game:
print(dealer.player_cards)
print(p1.player_cards)
dealer.hit()
print(dealer.player_cards)
print(p1.player_cards)
print(dealer.total)
print(p1.total)
Game = False
This happened because list is a mutable object, and it is created once only when defining the class, that is why it becomes shared when you create two instances. Therefore, to solve this problem, we can use constructor like what I have mentioned above. When we put the list in constructor, whenever the object is instantiated, the new list will also be created.

TypeError: unorderable types: atm() >= int()

I have 3 classes, ATM (main class), atmFees (subclass of ATM) and transaction. I want to have my class atmFees inherit methods from the parent class ATM.
The atmFees class takes the atm object as a parameter, initializing with atm.__init__(self, balance)
I want to override the parent/super class's "withdrawal" method, modifying one of the parameters -- subtracting 50 cents from amount -- and then accessing the super method in atm with the new amount.
Doing so returns a TypeError: unorderable types: atm() >= int()
I have absolutely no idea what to do from here, I've changed almost everything but I can't seem to get it to work.
import transaction
import random
class atm(object):
def __init__(self, bal):
self.__balance = bal
self.transactionList = []
def deposit(self, name, amount):
self.__balance += amount
ndt = transaction.Transaction(name, amount)
self.transactionList.append(ndt)
def withdraw(self, name, amount):
if self.__balance >= amount:
self.__balance -= amount
nwt = transaction.Transaction(name, amount)
self.transactionList.append(nwt)
else:
print('Uh oh, not enough money!')
def get_balance(self):
return self.__balance
def __str__(self):
string_return = ""
for transaction in self.transactionList:
string_return += str(transaction) + "\n"
string_return = '\n' + 'The balance is $' + format(self.__balance, ',.2f')
return string_return
class atmFee(atm):
def __init__(self, balance):
atm.__init__(self, balance)
def widthrawal(cls, name, amount):
amount = amount - .50
atm.widthrawal(cls, name, amount)
def deposit():
pass
def main():
myATM = atm.atm(75)
fees = atm.atmFee(myATM)
fees.withdraw("2250",30)
fees.withdraw("1000",20)
myATM.deposit("3035",10)
print("Let's withdraw $40")
if myATM.withdraw("Amazon Prime",40) == 0:
print ("Oh noes! No more money!")
print()
print("Audit Trail:")
print(myATM)
main();
The full code is posted here:
https://gist.github.com/markbratanov/e2bd662d7ff83ca5ef61
Any guidance / help would be appreciated.
The error message means just what it says - you can't order an object and an integer. This is possible (for some reason) in Python 2, where the ordering is essentially arbitrary (for example, an empty dict {} is always greater than an integer, no matter how large...), but it is not in Python 3, because the comparison is meaningless.
You create your ATM object like this:
myATM = atm.atm(75)
fees = atm.atmFee(myATM)
So myATM, itself an ATM object, gets passed in to atmFee.__init__ as the balance. In withdraw, you expect the balance to be a number and not an ATM object (if the comparison worked, the arithmetic you do on it would then fail). You almost certainly meant to set the balance to a number by creating the object like this:
fees = atm.atmFee(75)
Note that atmFee takes exactly the same constructor signature as the superclass (this isn't a rule, but it is how you've set it up here), so you should use it in the same way.
You are also switching between using fees and myATM in the rest of your code, which seems odd. It looks like you mean to be using fees in all cases, and don't actually need myATM at all.

Python elevator simulation problem

I have a homework assignment that's really baking my noodle. It involves an elevator simulation that takes user inputs for the number of floors and the number of people using the elevator. the people's starting floor and destination floors are random numbers within the floors.
I realize that my code is very sparse and that there's quite a few gaps, but I really don't know where to go from here.
I need help within the building class, such as how to make the run() and output() sections work. any other tips would be greatly appreciated and helpful. Note that i am not looking for someone to do the code for me, but to kind of hold my hand and tell me which way to go. Classes seem to be completely mystifying to me.
import random
floors=raw_input('Please enter the number of floors for the simulation:')
while floors.isalpha() or floors.isspace() or int(floors) <=0:
floors=raw_input('Please re enter a digit for number of floors:')
customers=raw_input('Please enter the number of customers in the building:')
while customers.isalpha() or customers.isspace() or int(customers) <0:
customers=raw_input('Please re enter a digit for number of customers:')
count = 1
class building:
def num_of_floors():
num_of_floors = floors
def customer_list():
customer_list = customers
def run(self):
def output(self):
print elevator.cur_floor
class elevator:
def num_of_floors():
building.num_of_floors
def register_list():
register_list = []
def cur_floor(building):
cur_floor = 1
def direction(self):
if elevator.cur_floor == 1:
direction = up
if elevator.cur_floor == floors:
direction = down
def move(self):
if elevator.direction == up:
cur_floor +=1
if elevator.direction == down:
cur_floor -=1
def register_customer(self, customer):
register_list.append(customer.ID)
def cancel_customer (self, customer):
register_list.remove(customer.ID)
class customer:
def cur_floor(customer):
cur_floor = random.randint(0,int(floors))
def dst_floor(customer):
dst_floor = random.randint(0,int(floors))
while dst_floor == cur_floor:
dst_floor = random.randint(0,int(floors))
def ID():
cust_id = count
count+=1
def cust_dict(cust_id,dst_floor):
cust_dict = {cust_id:dst_floor}
def in_elevator():
in_elevator = 0
if customer.ID in register_list:
in_elevator = 1
def finished():
if customer.ID not in register_list:
pass
You need to understand the self
parameter to all methods.
You need to understand __init__,
the constructor.
You need to understand self.varible
for your member variables.
You need to understand how to setup a
main function.
You need to understand how to
return a value from a function or
method.
You need to understand how to assign to global variables from within a function or method.
Maybe your building class should start like this.
class building:
def __init__(self, floors, customers):
self.num_of_floors = floors
self.customer_list = customers
self.elevator = elevator()
You should definately spend some time on Python Tutorial or Dive into Python.
The first parameter of every method is a reference to the object and is usually called self. You need it to reference instancemembers of an object.
Second, referencing global variables from inside a class is considered a bad idea. You can better pass them to a class via the constructor or parameters.

Categories