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)]
Related
I have to update a nested JSON object.
If I knew the specifics of which items were to be updated I could do :
json_object['basket']['items']['apple'] = 'new value'
However, my list of elements to target is dynamic.
> basket.items.apple = 'green'
> name = 'my shopping'
> basket.cost = '15.43'
I could do this by looping through elements.
Find 'basket' > then find 'items > then find 'apple' > set value
Find 'name' > set value
However, was hoping that there was a way to just reference directly/dynamicaly.
i.e. from a string 'basket.cost', build the expression :
json_object['basket']['cost']
P.s. it has to cope with lists of dictionaries too !
Any guidance appreciated :)
Once you have the string "basket.cost", you can split it on "." and it's pretty easy to drill down into json_object['basket']['cost'] using a loop. Functionally, there is no difference between doing this and doing it "directly": you are still getting the 'basket' key first, and then getting the 'cost' key from the value of json_object['basket'].
def get_element(d, path):
# This function can take the string "basket.cost", or the list ["basket", "cost"]
if isinstance(path, str):
path = path.split(".")
for p in path:
d = d[p]
return d
def set_element(d, path, value):
path = path.split(".")
dict_to_set = get_element(d, path[:-1])
key_to_set = path[-1]
dict_to_set[key_to_set] = value
set_element(json_object, "basket.items.apple", 100)
Now, this assumes all elements of your path already exist, so let's say you create a dictionary that looks like so:
json_object = {"basket": {"items": dict()}}
set_element(json_object, "basket.items.apple", 100)
set_element(json_object, "basket.cost", 10)
print(json_object)
# Output: {'basket': {'items': {'apple': 100}, 'cost': 10}}
print(get_element(json_object, "basket.cost"))
# Output: 10
If you try to access an element that doesn't already exist, you get a KeyError:
get_element(json_object, "basket.date")
# KeyError: 'date'
This also happens if you try to set a value in an element that doesn't exist:
set_element(json_object, "basket.date.day", 1)
# KeyError: 'date'
If we want to allow your function to create the dictionaries when they don't exist, we can modify the get_element function to account for this situation and add the key:
def get_element(d, path, create_missing=False):
# This function can take the string "basket.cost", or an iterable containing the elements "basket" and "cost"
if isinstance(path, str):
path = path.split(".")
for p in path:
if create_missing and p not in d:
d[p] = dict()
d = d[p]
return d
def set_element(d, path, value, create_missing=True):
path = path.split(".")
dict_to_set = get_element(d, path[:-1], create_missing)
key_to_set = path[-1]
dict_to_set[key_to_set] = value
set_element(json_object, "basket.date.day", 1)
print(json_object)
# Output: {'basket': {'items': {'apple': 100}, 'cost': 10, 'date': {'day': 1}}}
If using third party package is an option, you can try python-box. It comes with lots of options and utilities to load from json, yaml files. The implementation is optimized for speed using Cython.
from box import Box
test_data = {
"basket": {
"products": [
{"name": "apple", "colour": "green"}
],
}
}
a = Box(test_data)
a.basket.cost = 12.3
a.basket.products[0].colour = "pink"
a.basket.products.append({"name": "pineapple", "taste": "sweet"})
print(a.basket.products[1].taste)
You can get exactly what you want by overloading some python magic methods: __getattr__ and __setattr__. I'll show an example of the API to wet the appetite and then the full code:
test_data = {'basket': {'items': [{'name': 'apple', 'colour': 'green'},
{'name': 'pineapple', 'taste': 'sweet',},
],
'cost': 12.3,
},
'name': 'Other'}
o = wrap(test_data) # This wraps with the correct class, depending if it is a dict or a list
print(o.name) # Prints 'Other'
print(o.basket.items) # Prints the list of items
print(o.basket.cost) # Prints 12.3
o.basket.cost = 10.0 # Changes the cost
assert o.basket.cost == 10.0
assert len(o) == 2
assert len(o.basket.items) == 2
o.basket.items.append({'name': 'orange'})
o.basket.items[2].colour = 'yellow' # It works with lists!
assert o.basket.items[2].name == 'orange'
assert o.basket.items[2].colour == 'yellow'
# You can get a part of it and it holds a reference to the original
b = o.basket
b.type = 'groceries'
assert o.basket.type == 'groceries'
# It is also possible to create a separate wrapped part and then join:
employees = wrap({})
employees.Clara.id = 101
employees.Clara.age = 23
employees.Lucia.id = 102
employees.Lucia.age = 29
o.employees = employees
The implementation is based on special wrapper classes, one for dicts, another for lists. They all inherit from a base class. Note that the need to use super().__setattr__ instead of simply self._data is because we will override the __getattr__ and __setattr__ methods to look for the data inside _data. Of course it gives an infinite loop when you try to define _data.
from collections.abc import Mapping, Sequence, MutableSequence
class BaseWrapper:
__slots__ = ('_data')
def __init__(self, data):
super().__setattr__('_data', data)
def __repr__(self):
return f'{self.__class__.__name__}({repr(self._data)})'
The wrapper for dictionaries is the most interesting: it uses __getattr__ to look for a key in the wrapped dictionary. This allows for a very natural API: if o is a wrapped dictionary, o.entry will give the same result as o['entry']. Most of the code should be self-explanatory, there are only two tricks: the first is that __getattr__ checks if the output is a dict or list and wraps it. This allows for chaining of calls like o.basket.cost. The downside is that a new wrapper is created every call. The second trick is when setting an attribute: it checks if what is being set is a wrapped instance and un-wraps it. Thus, wrapped dictionaries can be combined and the underlying dictionary is always "clean".
class MappingWrapper(BaseWrapper):
"""Wraps a dictionary and provides the keys of the dictionary as class members.
Create new keys when they do not exist."""
def __getattr__(self, name):
# Note: these two lines allow automatic creation of attributes, e.g. in an object 'obj'
# that doesn't have an attribute 'car', the following is possible:
# >> o.car.colour = 'blue'
# And all the missing levels will be automatically created
if name not in self._data and not name.startswith('_'):
self._data[name] = {}
return wrap(self._data[name])
def __setattr__(self, name, value):
self._data[name] = unwrap(value)
# Implements standard dictionary access
def __getitem__(self, name):
return wrap(self._data[name])
def __setitem__(self, name, value):
self._data[name] = unwrap(value)
def __delitem__(self, name):
del self._data[name]
def __len__(self):
return len(self._data)
The list wrapper is simpler, no need to mess around with attribute access. The only special care we have to take is to wrap and unwrap the list elements when one is requested/set. Note that, just like with the dictionary wrapper, the same wrap and unwrap functions are used (in __getitem__/__setitem__/insert).
class ListWrapper(BaseWrapper, MutableSequence):
"""Wraps a list. Essentially, provides wrapping of elements of the list."""
def __getitem__(self, idx):
return wrap(self._data[idx])
def __setitem__(self, idx, value):
self._data[idx] = unwrap(value)
def __delitem__(self, idx):
del self._data[idx]
def __len__(self):
return len(self._data)
def insert(self, index, obj):
self._data.insert(index, unwrap(obj))
Finally, the definition of wrap, which just selects the correct wrapper based on the type of the input, and unwrap, which extracts the raw data:
def wrap(obj):
if isinstance(obj, dict):
return MappingWrapper(obj)
if isinstance(obj, list):
return ListWrapper(obj)
return obj
def unwrap(obj):
if isinstance(obj, BaseWrapper):
return obj._data
return obj
The full code can be found in this gist.
An important caveat: to keep the implementation simple, wrapper objects are created at every access. Thus using this method inside large loops may cause performance issues (per my measurements, this method of access is between 12 to 30 times slower).
I'm going to assume that you already know how to handle the value errors that will probably come up with this nested collection accessing, so I won't focus on it in my approach.
I would split this in two parts:
Traversing a nested collection according to a list of keys for each level
Getting a list of keys out of a string
The first one is quite trivial, where as you said simply looping through the keys and getting to the end of those gives you access to the collection element in question. A simple implementation of that could look something like this:
def get_nested(collection, key):
for part in key:
collection = collection[part]
return collection
def set_nested(collection, key, value):
for part in key[:-1]:
collection = collection[part]
collection[key[-1]] = value
Here the key is expected to be some iterable of keys, such as a tuple or list.
Of course that means there is an expectation that your string representing a path along the collection is already parsed. We can get to that next.
This step would also be very trivial, since one could simply expression.split(".") it. However, since you also want to be able to index nested lists along with dicts, it get's a little more complicated.
There is a tradeoff to be made here. One could simply say: "Any time that one of the items in expression.split(".") can be parsed to an int, we will do just that, and assume that it was ment as an index in a list", however naturally that isn't necessarily the case. There is nothing preventing you from using a number in string form as a key in a dict. However if you think this is never going to be the case for you, perhaps the you can just call it like this:
set_nested(
collection,
(int(part) if part.isdigit() else part for part in expression.split(".")),
"target value",
)
(or of course wrap it in another function like this).
However if the consideration of using digit keys in dicts is important for you, there is another solution:
Whenever traversing the nested collection downward, we check if the collection we are currently looking at is a list. Only if it is a list, do we actually try to parse the path part as an int.
This would be the respective set_nested and get_nested functions for that:
def get_nested(collection, key: str):
for part in key.split("."):
if type(collection) == list:
part = int(part)
collection = collection[part]
return collection
def set_nested(collection, key: str, val):
key = key.split(".")
for i, part in enumerate(key):
if type(collection) == list:
part = int(part)
if i == len(key) - 1:
collection[part] = val
else:
collection = collection[part]
I believe that's the simplest solution to your problem, though of course it's important to keep in mind:
There is no error handling in this code, and indexing on dynamic paths is a topic where you are bound to run into errors. Depending on where and how you want to handle those it's going to be easy or very tedious.
There is no checking of setting values in dicts that don't exist yet, or for expanding arrays to a specific size, but since you didn't mention those that as a requirement I'm presuming it's not an issue. It might be for others reading this.
This is tricky and I would discourage it unless necessary as it is an easy thing to design and implmenet badly.
First: it's easy to split on path separator and follow the object tree to the desired key.
But after a while questions will start to appear. E.g.: what separator to split on?
A slash? It can appear in the JSON dictionary key... A dot? Same.
We'll need to either restrict legal / handled paths or implement some kind of escaping mechanism.
How do you handle empty strings?
Another goal: handle lists... Ok. So how do we interpret a path a.0? Is it ['a'][0] or ['a']['0'] ?
It seem that we'll have to complicate the language or drop the requirement.
So, in general -- I'd avoid it. Ultimately here's a quick implementation which
desing choices may or may not satisfy you:
there's basic backslash escaping of path separator
empty string is allowed as a key
lists are not handled due to ambiguity
def deep_set(root: dict, path: str, value):
segments = [*iter_segments(path, '.')]
for k in segments[:-1]:
root = root[k]
root[segments[-1]] = value
def iter_segments(path: str, separator: str = '.'):
segment = ''
path_iter = iter(path)
while True:
c = next(path_iter, '')
if c in ('.', ''):
yield segment
segment = ''
if c == '':
break
continue
elif '\\' == c:
c = next(path_iter, '')
segment += c
there might be a question with a similar title, but it does not help.
I am programming a dictionary (english, german) and my aim is now, to sort the cache(a list of all vocab-objects) alphabetically.
Each attribute of the class vocab is a list, whereby the first element/word in the list the most important one is and therefore the word you use to sort.
Here is a working minimal version:
class vocab:
def __init__(self, english, german, context, box=0):
""" self.eng/ger/con supposed to be lists"""
self.eng = english
self.ger = german
self.con = context
def present(self):
return "English: {}\n\nGerman: {}\n\nExample: {}\n{}\n".format(self.eng,self.ger,self.con,"-"*20)
#...
class dictionary:
def __init__(self, Cache=[]):
self.cache = Cache
def sort_cache(self, sortby="eng"):
"""sort cache alphabetically (default = english)"""
#list with sorted items
# -->item: (word used to sort, related vocObject)
sort_cache = sorted([(getattr(voc,sortby),voc) for voc in self.cache])
self.cache = [item[1] for item in sort_cache]
def show_cache(self):
""" print all vocabs from self.cache"""
out = ""
for voc in self.cache:
out += voc.present()
return out
#...
#e.g.
voc1 = vocab(["to run"],["rennen","laufen"],["Run Forest! Run!!"])
voc2 = vocab(["to hide"],["(sich) verstecken","(etw.) verbergen"],["R u hidin sth bro?"])
voc3 = vocab(["anything"],["irgendwas"],["Anything ding ding"])
voc4 = vocab(["example","instance","sample"],["Beispiel"],["sample"])
MAIN_DIC = dictionary([voc1,voc2,voc3,voc4])
print MAIN_DIC.show_cache() #-->prints vocabs in order: to run, to hide, anything, example
# (voc1), (voc2) , (voc3) , (voc4)
MAIN_DIC.sort_cache()
print MAIN_DIC.show_cache() #-->prints vocabs in wanted order: anything, example, to hide, to run
# (voc3) , (voc4) , (voc2) , (voc1)
Since I am creating an entirely new cache in my sort_cache method ,I wondered what a more efficient way would look like. I'm sure there is one.
For example. I would reckon that it would be more efficient(save time), to only sort the elements in self.cache without creating any copy etc..
This is the "decorate-sort-undecorate" pattern:
sort_cache = sorted([(getattr(voc,sortby),voc) for voc in self.cache])
self.cache = [item[1] for item in sort_cache]
It was a preferred approach to sorting in Python for many years. It has been replaced by built-in support in the sort and sorted functions:
self.cache = sorted(self.cache, key=lambda item: getattr(item, sortby))
Or
self.cache.sort(key=lambda item: getattr(item, sortby))
You may also want to consider maintaining self.cache in sorted order (by inserting things in the correct position in the first place - see the bisect module for help with this), thus amortizing the cost of sorting across your insertions (which may be more expensive overall but less expensive on any individual operation).
Also note that:
def __init__(self, Cache=[]):
gives you a single shared cache list across all dictionary instances that use this default. Mutable default values is typically not what you want in Python.
I am trying to set up a function that will query an item for its sub components if those exists and return those else return the item itself.
Imagine an object that can contain more objects within it. To access those objects i would do object.GetSubComponentIds() now if that object contains sub objects it would return a list of those sub objects or EmptyList if there are none. In case that there are sub objects contained within it I want to keep going and then for each subobject i want to check if there are any subobjects contained within them. So for every SubObject.GetSubComponentIds() now if those do not contain anything then i would love to return them while maintaining nested structure of objects that they came from.
object1(contains 3 sub objects)
object2(contains 3 sub object and each sub object contains one more sub object)
object3(does not contain sub objects)
inputlist = [object1, object2]
outputlist = [[obj1sub1, obj1sub2, obj1sub3],[[obj2sub1sub1],[obj2sub2sub1],[obj2sub3sub1]],[obj3]]
I am interested in maintaining that nested list structure that will allow me to always trace back the origin of the sub object. Again, a method to get a sub object list is object.GetSubComponentIds() and it will either return a list or Empty List.
Can anyone help me set up an iterative function to retrieve them. Keep in mind that I do not know whether there are any sub objects contained within an object or haw many levels deep are they. It's basically that if it returns a list i need to check every item on that list for more sub objects.
Thank you in advance
Here's my humble first try:
#unwrap all elements to use with API
elements = []
for i in IN[0]:
elements.append(UnwrapElement(i))
#create element set from python list
elementSet = Autodesk.Revit.DB.ElementSet()
for i in elements:
elementSet.Insert(i)
#convert element set to List[Element]
setForCheck = List[Autodesk.Revit.DB.Element]()
elemIter = elementSet.ForwardIterator()
elemIter.Reset()
while elemIter.MoveNext():
curElem = elemIter.Current
setForCheck.Add(curElem)
#iterate throuh all elements to extract nested elements
setLoop = List[Autodesk.Revit.DB.Element]()
elemSet = List[Autodesk.Revit.DB.Element]()
itemOut = []
counter = 0
while setForCheck.Count >= 1:
setLoop.Clear()
for i in setForCheck:
itemOut.append(i)
if i.GetSubComponentIds().Count >= 1:
elem = Autodesk.Revit.DB.ElementSet()
for j in i.GetSubComponentIds():
elem.Insert(doc.GetElement(j))
elemIterA = elem.ForwardIterator()
elemIterA.Reset()
while elemIterA.MoveNext():
curElemA = elemIterA.Current
setLoop.Add(curElemA)
setForCheck.Clear()
elemIterB = setLoop.GetEnumerator()
elemIterB.Reset()
while elemIterB.MoveNext():
curElemB = elemIterB.Current
setForCheck.Add(curElemB)
counter += 1
if counter > 1000:
break
#Assign your output to the OUT variable
OUT = itemOut
You're using some specific libraries, like Autodesk, that I'm not familiar with. Let me answer your question in terms of an abstract example.
Suppose we're dealing with Thing objects, where Thing is defined as:
class Thing(object):
def __init__(self, name):
self.name = name
self.inside = []
We can make Things and put other things inside of them. The example you give in your post can be written:
ob1 = Thing("ob1")
ob1.inside.extend([Thing("ob1sub1"), Thing("ob1sub2"), Thing("ob1sub3")])
ob2 = Thing("ob2")
for i in xrange(1,4):
name = "ob2sub{}".format(i)
thing = Thing(name)
thing.inside.append(Thing(name + "sub1"))
ob2.inside.append(thing)
ob3 = Thing("ob3")
things = [ob1, ob2, ob3]
This makes a sort of tree. Now we'd like to return a nested list of all of the leaf nodes in the tree:
def search_things(things):
names = []
for thing in things:
if not thing.inside:
names.append(thing)
else:
names.append(search_things(thing.inside))
return names
A test:
>>> search_things(things)
[['ob1sub1', 'ob1sub2', 'ob1sub3'],
[['ob2sub1sub1'], ['ob2sub2sub1'], ['ob2sub3sub1']],
'ob3']
I'll let you transform this to your specific problem, but this is the general idea. Note that the algorithm is recursive, not iterative. You said you wanted an iterative algorithm -- and the above can be written iteratively -- but this gives you the idea.
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...
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.