I'm designing an inventory class in Python, it is supposed to keep track of the items a store has in stock, add new ones, and delete them, as well.
The trouble comes from my "item" definitions within the class. When I add another item to my dictionary, it replaces it, it doesn't add it. I appreciate your help! Why won't it add???
class Store:
def __init__(self, name, email):
self.name = name
self.email = email
# two accessor methods
def getName(self):
return self.name
def getEmail(self):
return self.email
# makes print work correctly
def __str__(self):
return str(self.name)
# items
def additem(self, item, price):
global items
items = {}
self.item = str(item)
self.price = float(price)
items[self.item] = price
def delitem(self, item):
items.remove(item)
def displayinventory(self):
return items
You are setting items to a new empty dictionary every time you call additem. So it always erases whatever's there before adding a new item. Instead, set items = {} once outside the function. There is also no point in doing self.item = str(item) (and the same for the price), because this will just overwrite the existing self.item, so you'll only have access to the most recent one.
Actually, what you probably should do is make items an attribute of the object, like this:
class Store:
def __init__(self, name, email):
self.name = name
self.email = email
self.items = {}
# rest of your code here. . .
def additem(self, item, price):
self.items[str(item)] = float(price)
def delitem(self, item):
del self.items[str(item)]
def displayinventory(self):
return self.items
The way you're doing it, there's only one global items dict that will be shared among all Stores. The above way gives each store its own items dict so it can keep its own record of its own items.
Even this was asked a view years ago, others might be interested in this answer.
If you want to use a dictionary globally within a class, then you need to define it in section where you use your class.
if you are using your class in main, then define it there.
A dictionary or o list are global by default.
class Store:
...
def additem (self, item, price):
self.item = str (item)
self.price = float (price)
items [self.item] = price
def main ():
...
items = dict ()
myStore = Store ()
....
Related
I have a list of objects of the Person class. This list includes myself, so I need to remove "myself" from the list.
It means I need to remove the object from the list that calls this method.
class Population:
def __init__(self):
self.people = list()
class Person:
def __init__(self):
self.friends_list = list()
def make_friends(self, population, n):
temp_list = population.copy()
temp_list.remove(self)
self.friends_list.extend(random.sample(temp_list,n))
my test:
per = Person()
per2 = Person()
per3 = Person()
per4 = Person()
per5 = Person()
pop = [per,per2,per3,per4,per5]
for per in pop:
per.make_friends(pop, 2)
print('ME: ',per)
print(per.friends_list)
My tests run well, but there are general tests that check the code and they generate an error on this line:
try:
stud_res = person.make_friends(population, count)
except Exception:
print("\tPerson.make_friends() generated error")
return
Can I use self in this way, and if not, how can I better remove "myself" from the list?
It is a perfectly fine use case. By the way, note that you're overriding the builtin list.
To use self, you have to share a list collection between instances of a Person-class. In that case this collection should be declared as a class attribute or global list variable (not an instance attribute).
These samples of code are working:
with global list variable:
class Person:
def __init__(self, name):
self.name = name
def make_friends(self, list):
list.remove(self)
def __repr__(self):
return self.name
p1 = Person("Joe")
p2 = Person("Barack")
the_list = []
the_list.append(p1)
the_list.append(p2)
p1.make_friends(the_list)
print(the_list)
With class attribute:
class Person2:
class_list = []
def __init__(self, name):
self.name = name
Person2.class_list.append(self)
def make_friends(self):
Person2.class_list.remove(self)
def __repr__(self):
return self.name
p1 = Person2("Joe")
p2 = Person2("Barack")
print(Person2.class_list)
p1.make_friends()
print(Person2.class_list)
EDIT:
Variable 3 when a list of people is inside another class.
For accessing a list inside another class you could use attribute name or public method to get it if implemented:
class ClassWithList:
def __init__(self):
self.list_collection = []
def get_list(self):
return self.list_collection
class_with_list = ClassWithList()
class Person:
def __init__(self, name):
self.name = name
def make_friends(self, list):
list.remove(self)
def __repr__(self):
return self.name
p1 = Person("Joe")
p2 = Person("Barack")
# using implemented get-method of instance list attribute
class_with_list.get_list().append(p1)
class_with_list.get_list().append(p2)
print(class_with_list.get_list())
p1.make_friends(class_with_list.get_list())
print(class_with_list.get_list())
# instance list attribute of class`ClassWithList
print(class_with_list.list_collection)
p2.make_friends(class_with_list.list_collection)
print(class_with_list.list_collection)
I'm trying to append some objects to a list but it fails with this error:
Traceback (most recent call last):
File "/home/miguelangel/PycharmProjects/reports/Output.py", line 23, in <module>
product.add_item(Item('product_id', 'product_id'))
File "/home/miguelangel/PycharmProjects/reports/Output.py", line 15, in add_item
self.items.append(item)
AttributeError: 'function' object has no attribute 'append'
I don't understand why it fails if a list is supposed to contain the append function. Here's the actual code.
class Item:
def __init__(self, column: str, alias: str):
self.column = column
self.alias = alias
class Category:
items = []
def __init__(self, category: str):
self.category = category
def add_item(self, item: Item):
self.items.append(item)
def items(self):
return self.items
product = Category('product')
product.add_item(Item('product_id', 'product_id'))
product.add_item(Item('product_name', 'product_name'))
print(product)
You make several mistakes here:
you use a class-attribute to hold items in a category. This is a mistake because there is only one of those available for all categories. So you would add all items to essentially a global list.
the root-cause of your problem is that you name the list items as well as the method. The latter one is shadowing the first, so when accessing self.items you end up with the method, that doesn't have an append method. Which is what your error tells you: a function object has no append.
Use a proper instance-variable items instead, and don't declare a needless accessor-method items. Languages like Java or C++ make you write accessors for reasons beyond the scope of this answer, but in Python one doesn't writer primitive getters and setters because attribute access is nicer, and properties are there to save the day if there would be the need for any code being run.
class Item:
def __init__(self, column: str, alias: str):
self.column = column
self.alias = alias
class Category:
def __init__(self, category: str):
self.category = category
self.items = []
def add_item(self, item: Item):
self.items.append(item)
product = Category('product')
product.add_item(Item('product_id', 'product_id'))
product.add_item(Item('product_name', 'product_name'))
Your getter for items clashes with the variable name. Change the variable name to _items or something else: it is good practice to put an underscore before private members anyways.
class Category:
_items = []
def __init__(self, category: str):
self.category = category
def add_item(self, item: Item):
self._items.append(item)
def items(self):
return self._items
how to return the name of the object-
class sampleclass:
def __init__(self):
pass
def __str__(self):
return self
dogfood = sampleclass
print(dogfood)
outputs this :
class '__main__.sampleclass'
..Trying to output dogfood
Reading the variable name is not possible easily.
You could instead use some kind of key-value store (dictionary). Then you can read out the name of the key under that a value is stored.
Attributes are one way to store a custom name string inside an object that can be retrieved later:
class sampleclass:
def __init__(self, name):
self.name = name
def __str__(self):
return self
sample_object = sampleclass('dogfood')
print(sample_object.name)
# Output: 'dogfood'
I'm not really 100% sure how to ask the question, but here goes:
I'm going through Learn Python the Hard Way, and I'm on Ex. 45, where I'm supposed to create a text-based game on my own. I've had to pull someone else's code to make an inventory (which I will supply the code for below), but I cannot for the life of me figure out this: if the user types "inventory" in any raw_input() (across multiple classes), how can I get it to display the contents of the inventory? All I can think of would be a more complex version of this:
if raw_input() == "inventory"
print ???
but I do not know how to have the game display inventory (the ???) or allow "inventory" to become a global command...
I know this looks very, very barebones, but I would not be coming here unless I researched and tried to find the answer myself. Thank you to anyone who can help out, this is getting frustrating!
Here's the inventory system I'm using:
class Item(object):
def __init__(self, name, quantity=1):
self.name = name
self.raw = name.strip().lower()
self.quantity = quantity
class Container(object):
def __init__(self, name):
self.name = name
self.inside = {}
def __iter__(self):
return iter(self.inside.items())
def __len__(self):
return len(self.inside)
def __contains__(self, item):
return item.raw in self.inside
def __getitem__(self, item):
return self.inside[item.raw]
def __setitem__(self, item, value):
self.inside[item.raw] = value
return self[item]
def add(self, item, quantity=1):
if quantity < 0:
print "ERROR."
if item in self:
self[item].quantity += quantity
else:
self[item] = item
inventory = Container("Inventory")
spare_key = Item("SPARE KEY", 1)
rock = Item("ROCK", 1)
print(spare_key in inventory)
An easy way to print the contents of an instance of the Container class:
print "Inventory: [" + ",".join((item[1].name for item in inventory)) + "]"
Consider changing this function:
def __iter__(self):
return iter(self.inside.items())
to this:
def __iter__(self):
return iter(self.inside.values())
Usually you would expect that iterating over an inventory yields just items, not tuples with item's name and item.
Given that I need to operate a machine, I need a
VendingMachine class:
Property is a stock(list) that stores Food items.
Methods:
Constructor takes in no arguments.
get_stock_names(): returns a list of strings that represents the names of
all food items in the stock.
load(food): adds the Food object to stock
and others,
#predefined
class Food(object):
def __init__(self, name, nutrition, good_until):
self.name = name
self.nutrition = nutrition
self.good_until = good_until
self.age = 0
def get_name(self):
return str(self.name)
def get_age(self):
return self.age
def get_nutrition(self):
if self.age <= self.good_until:
return self.nutrition
else:
return 0
def ripen(self, days):
self.age = self.age + days
return self.age
def is_spoiled(self):
return self.good_until < self.age
#my code below
class VendingMachine:
def __init__(self):
Property = Food.get_name #no clue how to make a Property
self.load = Food.load #same here
def get_stock_names(self, Property):
lst = []
for i in Food:
i = str(i)
lst.append(i)
return lst
def has_stock(self, name):
return name in Property
def load(self, food):
Property.append(food)
return Property
def sell(self, name):
if name in Property:
Property.remove(name)
return name
else:
return None
What I get is
AttributeError: 'VendingMachine' object has no attribute 'load' (a variable)
I'm pretty sure you've misunderstood the line of your instructions telling you about the stock property. I suspect it is just telling you to make an instance variable named self.stock which holds a list of Food instances. Since the constructor takes no arguments, it presumably starts empty. Using the term "property" seems like a red herring, since property has a specific meaning in Python (a wrapper around a method to make it look like an attribute), which doesn't make much sense in this situation.
Anyway, here's what I think you want your constructor to look like:
def VendingMachine(object):
def __init__(self):
self.stock = [] # initially empty
Your later methods can inspect or manipulate self.stock as necessary.