people. I'm python newbie. I have two def functions as below under a class.
def add_item(self, itemID, itemlist):
lines = []
self.itemID = itemID
self.itemlist = itemlist
for line in self.itemID, itemlist:
lines.append(line)
and
def get_keys(self):
i = []
i.append(self.itemID)
return i
If I do
example.add_item('abc', item list)
example.add_item('abcd', item list)
example.add_item('abce', item list)
then when I do
example.get_keys()
It should give:
['abc', 'abcd', 'abce']
but mine only gives the latest one that is ['abce'].
Can anyone please let me know how to fix?
If I understand correctly, you want to add several couple of key and item_list to your example, and be able to retrieve the keys you added so far ? The easiest is to store the keys and the itemlist in two lists
Assuming that you initialize your object as such
def __init__(self, *args, **kwargs):
self.itemID = []
self.itemlist = []
...
Now, your add_item can simplify in
def add_item(self, itemID, itemlist):
self.itemID.append(itemID)
self.itemlist.append(itemlist)
and your get_key is only:
def get_keys():
return self.itemID
Note that the get_key is exactly the one you have suggested, just simpler (no need to create a temporary list).
When you do
lines = []
for line in self.itemID, itemlist:
lines.append(line)
line first takes the value self.itemID, then itemlist. Eventually, your lines is just [self.itemID, itemlist]. Probably not what you had in mind.
To add a new key to a dictionary, just assign it.
dict['new_key'] = 'value'
Perhaps
i.extend(self.itemID)
Might be what you are looking for
It looks like you are overwriting the item each time you add it.
When you call add_item, you are creating this variable "lines" that is never used again, and item_id and item_list are over-written with the new inputs.
You could also use the built-in method update:
example.update({'Key':'value'})
def add_item(self, itemID, itemlist):
lines = []
You are initializing your lines variable with empty list...
So, each time you invoke this method, it create a new list, and add the item to it..
You can rather return your lines from this method and store it in some variable where you are invoking this method..
Or, just declare lines as instance variable.
example = Example();
example.lines = []
example.lines.extend(example.add_item(itemId1, item_list1));
example.lines.extend(example.add_item(itemId2, item_list2));
Or, you can rather add your itemId and list to dictionary __dict__ of your class..
dict[itemId] = value;
** NOTE: - Just saw that, you have not used your for-loop correctly.. You don't iterate over two iterable like this..
You need to go through a good Python Book.. Or rather, Python Documentation..
First thing I see: You are iterating over two elements at once which is usually done by using zip(), at least if both elements are lists. Otherwise just use the container you want to loop over.
for id,line in zip(self.itemID, itemlist):
lines.append(line)
But I don't see any dict...
Related
I am working on a code which pulls data from database and based on the different type of tables , store the data in dictionary for further usage.
This code handles around 20-30 different table so there are 20-30 dictionaries and few lists which I have defined as class variables for further usage in code.
for example.
class ImplVars(object):
#dictionary capturing data from Asset-Feed table
general_feed_dict = {}
ports_feed_dict = {}
vulns_feed_dict = {}
app_list = []
...
I want to clear these dictionaries before I add data in it.
Easiest or common way is to use clear() function but this code is repeatable as I will have to write for each dict.
Another option I am exploring is with using dir() function but its returning variable names as string.
Is there any elegant method which will allow me to fetch all these class variables and clear them ?
You can use introspection as you suggest:
for d in filter(dict.__instancecheck__, ImplVars.__dict__.values()):
d.clear()
Or less cryptic, covering lists and dicts:
for obj in ImplVars.__dict__.values():
if isinstance(obj, (list, dict)):
obj.clear()
But I would recommend you choose a bit of a different data structure so you can be more explicit:
class ImplVars(object):
data_dicts = {
"general_feed_dict": {},
"ports_feed_dict": {},
"vulns_feed_dict": {},
}
Now you can explicitly loop over ImplVars.data_dicts.values and still have other class variables that you may not want to clear.
code:
a_dict = {1:2}
b_dict = {2:4}
c_list = [3,6]
vars_copy = vars().copy()
for variable, value in vars_copy.items():
if variable.endswith("_dict"):
vars()[variable] = {}
elif variable.endswith("_list"):
vars()[variable] = []
print(a_dict)
print(b_dict)
print(c_list)
result:
{}
{}
[]
Maybe one of the easier kinds of implementation would be to create a list of dictionaries and lists you want to clear and later make the loop clear them all.
d = [general_feed_dict, ports_feed_dict, vulns_feed_dict, app_list]
for element in d:
element.clear()
You could also use list comprehension for that.
In web2py I have been trying to break down this list comprehension so I can do what I like with the categories it creates. Any ideas as to what this breaks down to?
def menu_rec(items):
return [(x.title,None,URL('shop', 'category',args=pretty_url(x.id, x.slug)),menu_rec(x.children)) for x in items or []]
In addition the following is what uses it:
response.menu = [(SPAN('Catalog', _class='highlighted'), False, '',
menu_rec(db(db.category).select().as_trees()) )]
So far I've come up with:
def menu_rec(items):
for x in items:
return x.title,None,URL('shop', 'category',args=pretty_url(x.id, x.slug)),menu_rec(x.children))
I've got other variations of this but, every variation only gives me back 1(one) category, when compared to the original that gives me all the categories.
Can anyone see where I'm messing this up at? Any and all help is appreciated, thank you.
A list comprehension builds a list by appending:
def menu_rec(items):
result = []
for x in items or []:
url = URL('shop', 'category', args=pretty_url(x.id, x.slug))
menu = menu_rec(x.children) # recursive call
result.append((x.title, None, url, menu))
return result
I've added two local variables to break up the long line somewhat, and to show how it recursively calls itself.
Your version returned directly out of the for loop, during the first iteration, and never built up a list.
You don't want to do return. Instead append to a list and then return the list:
def menu_rec(items):
result = []
for x in items:
result.append(x.title,None,URL('shop', 'category',args=pretty_url(x.id, x.slug)),menu_rec(x.children)))
return result
If you do return, it will return the value after only the first iteration. Instead, keep adding it to a list and then return that list at the end. This will ensure that your result list only gets returned when all the values have been added instead of just return one value.
I'm python newbie and found something difficult while doing some practices.
I have few def functions under a class look like:
Class A(object):
def __init__(self):
self.itemID = []
self.itemlist = []
def add(self, ID, list):
self.itemID.append(ID)
self.itemlist.append(list)
def get_item(self,ID):
self.ID = ID
result = []
for self.ID in self.itemlist:
result.append(self.itemlist)
return result
I'm having problems with "def get_item". Here's an example..
if i do:
A.add('abc', 'bcd')
A.add('abc1', 'bcd1')
A.get_item('abc')
This should return abc, bcd but mine returns [['bcd', 'bcd1'], ['bcd', 'bcd1']]...
Apologise for the long complicated dumb looked codes.... Any feedbacks would be so appreciated.. Thanks
Why not use a dict?
A = {}
A['abc'] = 'bcd'
A['abc1'] = 'bcd1'
Then, A['abc'] returns 'bcd', as you want.
You can access the IDs with A.keys() and the items A.values() so you don't lose any functionality.
As #Stals points out in the comments, if you want to retain the order that you add things, you can also use an OrderedDict.
If you really need more than one item with the same ID, there are various multidict recipes that might work.
Others have explained how to make it work; I'm going to explain why what you had doesn't work.
The problem here is that Python is doing exactly what you tell it to do:
for self.ID in self.itemlist:
result.append(self.itemlist)
In a loop, set self.ID to each element of self.itemlist in order. (By the way, it is entirely unnecessary to use an instance attribute for this since there's no need to keep the ID when the method is done; you should probably use a local variable here instead.)
Each time through the loop, append a reference to self.itemlist to the result.
In other words, you are asking for individual items from your self.itemlist, but not doing anything with the items. All your append operations append the original list, not the current item from the list.
As a result, your method returns a list with as many copies of self.itemlist as there are elements in it.
your get_item function is absolutely wrong :)
Here's how it should look like:
def get_item(self,ID):
result = []
for x in range(0, len(self.itemID)):
if (self.itemID[x] == ID):
result.append(self.itemlist[x])
return result
Or even better:
def get_item(self, ID):
return [self.itemlist[x] for x in range(0, len(self.itemID) if self.itemID[x] == ID]
Now, if I understand the logic behind your class, you want to be able to retrieve a list of object given a common ID. This can be better done using a dict
class A:
def __init__(self):
self.content = {}
def add(self, ID, object):
list = self.get_item(ID)
list.append(object)
content[ID] = list
def get_item(self, ID):
return content.get(ID, [])
Your get_item code is very confused. It overwrites self.ID, several times, when it should only read it, and the loop appends the entire itemlist (or, rather, the itemlist itself) to the result - and it does this at every iteration. This is why you are seeing such a strange result.
What you are probably thinking of is this:
def get_item(self, ID):
for index in range(self.ID.length):
if self.id[index] == ID:
return self.itemlist[index]
That is: iterate over the indexes of both lists, and when you find the one that has a matching ID at that position in the ID list, return the thing in the corresponding position in itemlist.
This code can be improved a bit by using Python's built-in functions. For example, you could use zip - which can take both your lists (ID and itemlist), and give you back pairs of corresponding items - so, you have:
def get_item(self, ID):
for id, item in zip(self.ID, self.itemlist):
if id == ID:
return item
But you can get rid of the loop entirely by using list methods - list.index does the search for you:
def get_item(self, ID):
return self.itemlist[self.ID.index(ID)]
I might be doing this wrong, if I am, let me know, but I'm curious if the following is possible:
I have a class that holds a number of dictionaries, each of which pairs names to a different set of objects of a given class. For example:
items = {"ball" : ItemInstance1, "sword" : ItemInstance2}
people = {"Jerry" : PersonInstance1, "Bob" : PersonInstance2, "Jill" : PersonInstance3}
My class would then hold the current items and people that are availible, and these would be subject to change as the state changes:
Class State:
def __init__(self, items, people):
self.items = items
self.people = people
I would like to define a iter() and next() method such that it iterates through all of the values in its attributes. My first question is whether or not this is possible. If it is, will it be able to support a situation as follows:
I define items and people as above then:
state = State(items, people)
for names, thing in state:
print name + " is " + thing.color
items[cheese] = ItemInstance3
for names, thing in state:
print name + " weighs " + thing.weight
While I feel like this would be usefull in the code I have, I don't know if it's either possible or the right approach. Everything I've read about user defined iterators has suggested that each instance of them is one use only.
If I understand you question correctly then adding the following method to your class should do it:
def __iter__(self):
import itertools
return itertools.chain(self.items.itervalues(), self.people.itervalues())
This chains together two iterators, and the ones chosen here are for the values of items and the values of people.
To make your later code work though, you'll want to iterate over the items - the key-value pairs. In which case this would do it:
def __iter__(self):
import itertools
return itertools.chain(self.items.iteritems(), self.people.iteritems())
There are lots of ways to do what you want. You can indeed have such a State class, and implement the iter() method (http://docs.python.org/library/stdtypes.html).
You could also create a generator function:
def iterate_two(l1, l2):
for k in l1:
yield k, l1[k]
for k in l2:
yield k, l2[k]
You can use itertools.chain. You can use list comprehensions and generator expressions. Etc.
I, personally, wouldn't create the State class as you suggest, if all it is is an iterator mechanism - I'd probably use a list comprehension.
I'm trying to remove duplicate items in a list through a dictionary:
def RemoveDuplicates(list):
d = dict()
for i in xrange(0, len(list)):
dict[list[i]] = 1 <------- error here
return d.keys()
But it is raising me the following error:
TypeError: 'type' object does not support item assignment
What is the problem?
You should have written:
d[list[i]] = 1
But why not do this?
def RemoveDuplicates(l):
return list(set(l))
Also, don't use built-in function names as variable names. It can lead to confusing bugs.
In addition to what others have said, it is unpythonic to do this:
for i in xrange(0, len(lst)):
do stuff with lst[i]
when you can do this instead:
for item in lst:
do stuff with item
dict is the type, you mean d[list[i]] = 1.
Addition: This points out the actual error in your code. But the answers provided by others provide better way to achieve what you are aiming at.
def remove_duplicates(myList):
return list (set(myList))
From looking at your code it seems that you are not bothered about the ordering of elements and concerned only about the uniqueness. In such a case, a set() could be a better data structure.
The problem in your code is just to use a function argument name which is not the name of the built-in type list and later on the type dict in the expression dict[list[i]].
Note that using list(set(seq)) will likely change the ordering of the remaining items. If retaining their order is important, you need to make a copy of the list:
items = set()
copy = []
for item in seq:
if not item in items:
copy.add(item)
items.append(item)
seq = copy