I have been trying to alter a list in class Inventory from class Pod, but I get an error that I am popping from an empty set. Is there anyway that I can pop from a list from an Inventory instance that I know is populated? Essentially, I am trying to transfer widgets from Inventory to Pod.
class Widget():
def __init__(self):
self.cost = 6
self.value = 9
class Inventory():
def __init__(self):
self.widgets_inv = []
self.cost_inv = 0
self.value_inv = 0
def buy_inv(self):
x = int(input("How many widgets to you want to add to inventory? "))
for i in range(0, x):
self.widgets_inv.append(Widget())
def get_inv(self):
print("You have " + str(len(self.widgets_inv)) + " widgets in inventory.")
def cost_of_inv(self):
cost_inv = len(self.widgets_inv) * Widget().cost
print("The current cost of your inventory is: " + cost_inv + " USD.")
def value_of_inv(self):
val_inv = len(self.widgets_inv) * Widget().value
print("The current value of your inventory is: " + val_inv + " USD.")
class Pod():
"""A pod is a grouping of several widgets. Widgets are sold in pods"""
def __init__(self):
self.pod = []
def creat_pod(self):
x = int(input("How many widgets would you like to place in this pod? "))
for i in range(0, x):
self.pod.append(Widget())
Inventory().widgets_inv.pop()
You should modify the creat_pod-method, so that you can handover the Inventory-object. This allows you to add widgets to the inventory-object before calling creat_pod-method:
def creat_pod(self, inventory):
x = int(input("How many widgets would you like to place in this pod? "))
for i in range(0, x):
self.pod.append(Widget())
inventory.widgets_inv.pop()
In your original code you create always a new Inventory-object, which has therefore and empty widget-list:
Inventory().widgets_inv.pop()
Related
I am very new to Object oriented programming and I am having trouble accessing items in my class when I run my main method. My program is trying to allow a user to add item prices to a cart until they are finished and prints the number of items and total.
class CashRegister:
print("Welcome to shopping world!")
def __init__(self, price):
self.price = price
def addItem(self, price):
CashRegister.totalPrice = CashRegister.totalPrice + price
CashRegister.itemCount = CashRegister.itemCount + 1
#property
def getTotal(self):
return totalPrice
#property
def getCount(self):
return itemCount
def main():
selection = "Y"
while selection != "N":
selection = input("Would you like to add another item to the
cart Y or N")
selection = selection.upper()
if selection == "Y":
price = input("What is the price of the item?")
CashRegister.addItem(price)
else:
print(CashRegister.getCount)
print(CashRegister.getTotal)
print(selection)
main()
Here is the error I am getting when I select yes:
TypeError: addItem() missing 1 required positional argument: 'price'
Here is the output I am getting when I select no:
Welcome to shopping world!
Would you like to add another item to the cart Y or Nn
<property object at 0x0000022CFFCA2598>
<property object at 0x0000022CFFCA2548>
N
first, you don't use the class name for declaring variables in its methods: you have self for that (which you can rename to whatever you like, but 'self' is convention)
second, you have to initialize your class object in the main function, otherwise Python won't know what to do with the methods you call (when you define a method in a class, the first argument self stands for the class object, so each time you initialize an object and then call a method on that, the argument you pass inside the brackets is actually the second argument, first one being the object itself)
third: this is more of a style thing, but you don't really use CamelCase in python except for names of classes, all the rest is in snake_case
fourth: += is more readable and faster than example = example + 1
class CashRegister(object) :
def __init__(self) :
self.total_price = 0
self.item_count = 0
def add_item(self, price) :
self.total_price += int(price)
self.item_count += 1
def get_total(self) :
return self.total_price
def get_count(self) :
return self.item_count
def main() :
register = CashRegister()
selection = True
while selection :
selection = input("Would you like to add another item to the cart Y or N\n\t").upper()
if selection == "Y" :
price = input("What is the price of the item?\n\t")
register.add_item(price)
else :
print(register.get_total())
print(register.get_count())
print(selection)
selection = False
main()
this is how I would probably do it, I've taken out the #property decorators because I don't know if you really have a need for them there, you can just call the methods with brackets () at the end to get what you want
Then, there's a bunch more stuff you should do if you really want to to use this, and that would be exception catching, determine how the cash register behaves if a negative value is passed as price, and so on... good luck and enjoy Python
you have many mistakes you need the determine totalprice and itemcount in self, you need to determine a variable with cashregister class
class CashRegister:
print("Welcome to shopping world!")
def __init__(self):
self.totalPrice=0
self.itemCount=0
def addItem(self, price):
self.totalPrice = self.totalPrice + price
self.itemCount = self.itemCount + 1
#property
def getTotal(self):
return self.totalPrice
#property
def getCount(self):
return self.itemCount
def main():
selection = "Y"
box=CashRegister()
while selection != "N":
selection = input("Would you like to add another item to thecart Y or N\n\t:")
selection = selection.upper()
if selection == "Y":
price = input("What is the price of the item?\n\t:")
box.addItem(int(price))
else:
print(box.getCount)
print(box.getTotal)
print(selection)
main()
I'm having trouble understanding how to instantiate a class, and update that instances variables. If I __init__ a series of self.x variables, then instance that class, I want to update self.x = 40. However, self.x always stays constant.
I have a feeling I'm not wrapping my head around the class variable, init variable, and instanced class variables. I can always access them, I just can't seem to change them. I have coded an example of what I am trying to do.
class Engine(object):
def __init__(self, board):
self.board = board
def play_game(self):
print(self.board.sheet[0])
number_one = int(input("Please enter a number."))
self.board.a = number_one
number_two = int(input("Please enter another number."))
self.board.b = number_two
number_three = int(input("Please enter a third number."))
self.board.c = number_three
number_four = int(input("Please enter a final number."))
self.board.d = number_four
print("Thank you! List updated.")
print(self.board.sheet[0])
class ScoreBoard(object):
def __init__(self):
self.a = "_____"
self.b = "_____"
self.c = "_____"
self.d = "_____"
self.sheet = [f"""
1. Number One: {self.a}
2. Number Two: {self.b}
3. Number Three: {self.c}
4. Number Four: {self.d}
"""]
new_board = ScoreBoard()
new_game = Engine(new_board)
new_game.play_game()
When I print self.board.sheet[0] I would like to show the numbers instead of the lines for self.a through self.d.
You need to recompute self.sheet after self.a through self.d are set. After self.sheet is assigned it just contains a simple string. That string isn't automatically updated when the fields are changed; you have to do it yourself.
Better yet, make sheet a method rather than a static variable.
class ScoreBoard(object):
def __init__(self):
self.a = "_____"
self.b = "_____"
self.c = "_____"
self.d = "_____"
def sheet(self):
return f"""
1. Number One: {self.a}
2. Number Two: {self.b}
3. Number Three: {self.c}
4. Number Four: {self.d}
"""
I'm currently working on an OOP project in my CSI class in which I have to create various sports team and athlete objects as well as a method addPlayer() for adding the athletes to a roster. This is what I have so far.
class Athlete:
def __init__(self, name, number):
self.name = name
self.number = number
def __str__(self):
return "Athlete(" + self.name + ", " + self.number + ")"
def name(self):
return self.name
def number(self):
return self.number
from Athlete import *
class SportsTeam:
roster = []
def __init__(self, city, name, colors):
self.city = city
self.name = name
self.colors = colors
SportsTeam.roster = roster
def __str__(self):
return "SportsTeam(" + self.city + ", " + self.name + \
", " + str(self.colors) + ", " + ")"
def getcity(self):
return self.city
def getname(self):
return self.name
def getcolors(self):
return self.colors
def getRoster(self):
return SportsTeam.roster
def printRoster(self):
for player in roster:
print("Current Team Roster: " + str(SportsTeam.roster))
def addPlayer(self, player):
SportsTeam.roster.append(player)
return SportsTeam.roster
The thing is when I try to use the addPlayer() method I created, I get an error message telling me that list has no attribute. Not sure what needs to be added to fix this.
P.S I have only been programming for a couple of months, so I apologize if the solution is obvious
When you are dealing with classes, you have your instance variables (like self.city = city) and your class variables (like roster = []).
Instance variables are tied to an instance of the class. So if you create 2 SportsTeam objects, they each have their own city.
Class variables are a little different. They are not tied to an instance of the class; meaning, no matter how many SportsTeam objects you create, there will only be one roster variable.
To me, roster being a class variable seems a bit odd because each SportsTeam should have its own roster. However, if you are required to use class variables for you CSI class, maybe you could keep a list of all_teams and/or all_players.
Taking this into consideration:
class SportsTeam:
all_teams = []
all_players = []
def __init__(self, city, name, colors):
self.city = city
self.name = name
self.colors = colors
self.roster = []
SportsTeam.all_teams.append(self)
def __str__(self):
return "SportsTeam(" + self.city + ", " + self.name + ", " + str(self.colors) + ")"
def getCity(self):
return self.city
def getName(self):
return self.name
def getColors(self):
return self.colors
def getRoster(self):
return self.roster
def printRoster(self):
# the for loop was unnecessary
print("Current Team Roster:", str(self.roster))
def addPlayer(self, player):
SportsTeam.all_players.append(player)
self.roster.append(player)
return self.roster
If you would like to keep roster as a class variable, leave a comment and I can help you adjust the code to accommodate for this.
Please am very new in python, and I am trying to do a Binary CSP instance, where it generates variables based on the number of variables the user wants. So if the user wants 4 variables, it generates X1, X2, X3, X4 and then appends to a list. I have tried working on it, still can't place it
class CSP:
def __init__(self, variables):
self.variables = list(variables)
def get_variables(self):
return self.variables
class Map(CSP):
n = input("Enter number of variables: ")
for i in range(n):
vare = 'X' + 'i'
def __init__(self):
super().__init__(self._collect_variables())
def _collect_variables(self):
variables = []
variables.append(self.vare) #list the user appends to
def main():
Map()
if __name__ == '__main__':
main()
Your code is not working for a simple reason: it does not generate several variables. Instead of it, it updates single variable 'vare'.
I should do it in the following way:
class Map(CSP):
self._vare = []
def __init__(self):
n = input("Enter number of variables: ")
for i in range(n):
vare.append ('X' + 'i')
super().__init__(self._get_variables())
def _get_variables(self):
return self._vare
I have been trying to build my skills in Python and am trying to create a risk style game.
I am not far in to it at the moment as I am trying to get to grips with classes and Tkinter.
My first trial is to create a series of buttons to take the place of the different countries. I then want these buttons to update the amount of armies on the country when they are clicked.
So far I have been able to get the map to generate from the class I have created and the buttons are clickable. When a button is clicked it updates the amount of armies but always for the last button.
How do I get it so that the button I click updates and not the last one?
Have I gone about this in entirely the wrong way?
from tkinter import *
import random
class territory:
def __init__ (self, country, player = "1", current_armies = 0, x=0, y=0):
self.country = country
self.current_armies = current_armies
self.player = player
self.y = y
self.x = x
def get_armies(self):
print(self.country + " has " + str( self.current_armies)+ " armies.")
def add_armies (self, armies):
self.current_armies += armies
def roll_dice (self, dice=1):
rolls = []
for i in range(0, dice):
rolls.append(random.randint(1,6))
rolls.sort()
rolls.reverse()
print (self.country + " has rolled " + str(rolls))
return rolls
def owner(self):
print (self.country + " is owned by " + self.player)
def get_country(self):
print(country)
def button (self):
Button(window, text = territories[0].current_armies, width = 10, command = click1(territories, 0)).grid(row=y,column=x)
window = Tk()
def create_territories():
countries = ["UK", "GER", "SPA", "RUS"]
terr_pos = [[1,0],[2,0],[1,5],[4,1]]
sta_arm = [1,1,1,1]
terr = []
player = "1"
for i in range(len(countries)):
terr.append(territory(countries[i],player, sta_arm [i] , terr_pos[i][0],terr_pos[i][1]))
if player == "1":
player = "2"
else:
player = "1"
return terr
def click1(territory, i):
territory[i].current_armies += 1
build_board(territory)
def build_board(territories):
for i in range(0,4):
Button(window, text = territories[i].country+"\n"+str(territories[i].current_armies), width = 10, command = lambda: click1(territories, i)).grid(row=territories[i].y,column=territories[i].x)
territories = create_territories()
window.title ("Domination")
create_territories()
build_board(territories)
window.mainloop()
In your def button(self):... you are always referencing territories[0]:
Button(window, text=territories[0].current_armies,... command=click1(territories, 0)...
As such, you are always using the first territory as your reference, so you ought to initialize each territory with its index in territories[] so you can pass that into your Button constructor.
On your question of "entirely the wrong way," I'd personally send that question over to CodeReview, since that's more of their domain (we fix broken code, they address smelly code), though there is significant overlap. We do prefer one question per question, however, and "is this whole thing wrong?" is a little broad for StackOverflow.