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
Related
Imagine that I have a class called foo and its definition is following
class foo:
def __init__(self, id):
self.id = id
and I want this to happen
dummylist = [foo(3), foo(4), foo(10)]
# I want to do that if possible
print(dummylist[10]) # and get the last object in the list
What I want is that I have a class with a lot of attributes and I want to have a list of objects of that class and would be able to retrieve a specific object with a value of its attribute.
I know that I can do that with next or list comprehension but I want to do so by indexing the list of object with []
You could make your own list using collections.UserList:
from collections import UserList
class myList(UserList):
def _lookup(self, name):
for item in self.data:
if item.id == name:
return item
def __getitem__(self, name):
return self._lookup(name)
def __call__(self, name):
return self._lookup(name)
class foo:
def __init__(self, id):
self.id = id
dummylist = myList([foo(3), foo(4)])
dummylist.append(foo(10))
print(dummylist(10), dummylist(10).id)
print(dummylist[3], dummylist[3].id)
Out:
<__main__.foo object at 0x104a52460> 10
<__main__.foo object at 0x1049cfa00> 3
I have two objects with inventory lists of class instances, and I want to move those instances between them. However, I'm not sure how to actually reference a class instance that I haven't explicitly named.
In this example, multiple copies of class instances may be in an inventory, and I want to first check that a copy exists, then add it to the destination object's inventory and remove it from the source object's inventory.
How can I reference the Thing directly, or is there a better solution entirely?
class Foo():
def __init__(self):
self.inventory = []
def move_item(self, item, destination):
if item in self.inventory:
destination.add_item(item)
self.inventory.remove(item)
def add_item(self, item):
self.inventory.append(item)
class Bar():
def __init__(self):
self.inventory = []
def add_item(self, item):
self.inventory.append(item)
class Thing():
def __init__(self):
self.name = "Thing"
foo = Foo()
bar = Bar()
foo.add_item(Thing())
foo.move_item(Thing, bar)
Save a reference, or give your other classes a way to return a reference
For example, by saving a reference:
thing = Thing()
foo.add_item(thing)
foo.move_item(thing, bar)
An example that gets a reference:
foo.add_item(thing)
foo.move_item(foo.inventory[0], bar)
Or, if you modify add_item to return the item that was added:
class Foo():
...
def add_item(self, item):
self.inventory.append(item)
return item
...
thing = foo.add_item(Thing())
foo.move_item(thing, bar)
I have a class, Record, that is used to contain the results of reading text file. The file contains a simple database with fields and tags. I would like to have each Record instance only have the properties associated with its database. Basically:
R1 = Record("file1")
R2 = Record("file2")
print(R1.TI) #"Record 1's title"
print(R2.TI) #AttributeError: 'Record' object has no attribute 'TI'
unfortunately some of the fields may require a large amount of processing to return something useful, and those values may never be needed. So I would like the value to be determined the first time they are called not when the object is initialized.
Because I know the tags name's only I have tried:
class tagWrapper(object):
def __init__(self, tag):
self.tag = tag
self.data = None
def __get__(self, instance, owner):
if self.data == None:
try:
#tagToFunc is a dictionary that maps tags to their processing function
self.data = tagToFunc[self.tag](instance._rawDataDict[self.tag])
except KeyError: #I do not know the full list of tags
self.data = instance._rawDataDict[self.tag]
return self.data
class Record(object):
def __init__(self, file):
#Reading file and making _rawDataDict
setattr(self, tag, tagWrapper(tag))
This causes R1.TI to produce the wrapper object not the value I want. So I suspect I am screwing something up with the get method.
Note: I am trying to make the attributes part of the individual class instances and not evaluated until needed. I can implement one or the other but have not been able to determine how to do both.
You are implementing the descriptor protocol, and descriptor belongs to the class instead of an instance of the class, so you can not assign it to an instance attribute.
class Tag(object):
def __init__(self, tag):
self.tag = tag
self.data = None
def __get__(self, instance, owner):
if not instance: # if accessed with the class directly, ie. Record.T1, just return this descriptor
return self
if self.data is None:
print "Reading data"
self.data = range(10)
return self.data
class Record(object):
T1 = Tag('T1')
I have a solution that seems to work although it is quite ugly:
class Record(object):
def __init__(self, file):
self._unComputedTags = set() #needs to be initialized first
#stuff
self._unComputedTags = set(self._fieldDict.keys())
for tag in self._fieldDict:
self.__dict__[tag] = None
def __getattribute__(self, name):
if name == '_unComputedTags':
#This may be unnecessary if I play with things a bit
return object.__getattribute__(self, '_unComputedTags')
if name in self._unComputedTags:
try:
tagVal = tagToFunc[name](self._fieldDict[name])
except KeyError:
tagVal = self._fieldDict[name]
setattr(self, name, tagVal)
self._unComputedTags.remove(name)
return object.__getattribute__(self, name)
I do not like overwriting __getattribute__ but this seems to work.
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.
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 ()
....