How do I take integer keys in shelve?
-
26-09-2019 - |
Question
I want to store an integer key in shelve. But when I try to store integer key in shelve it give me an error
Traceback (most recent call last): File "./write.py", line 12, in data[id] = {"Id": id, "Name": name} File "/usr/lib/python2.5/shelve.py", line 124, in __setitem__ self.dict[key] = f.getvalue() File "/usr/lib/python2.5/bsddb/__init__.py", line 230, in __setitem__ _DeadlockWrap(wrapF) # self.db[key] = value File "/usr/lib/python2.5/bsddb/dbutils.py", line 62, in DeadlockWrap return function(*_args, **_kwargs) File "/usr/lib/python2.5/bsddb/__init__.py", line 229, in wrapF self.db[key] = value TypeError: Integer keys only allowed for Recno and Queue DB's
My Code :
#!/usr/bin/python
import shelve
data = shelve.open("data.txt")
ans = 'y'
while ans == "y":
id = input("Enter Id : ")
name = raw_input("Enter name : ")
data[id] = {"Id": id, "Name": name}
ans = raw_input("Do you want to continue (y/n) ? : ")
data.close()
Is something wrong in my program or shelve does not supports integer keys at all ?
Edit 1 :
In program I am trying to store a dictionary of Id and Name inside another dictionary with Id as a key. And then trying to store it in a file.
Do I need to use Recno or Queue DB's along with shelve? I am a beginner and things are confusing.
Let me know if I am not clear with my question.
Thanks.
Solution
The shelve module uses an underlying database package (such as dbm, gdbm or bsddb) .
A "shelf" is a persistent, dictionary-like object. The difference with "dbm" databases is that the values (not the keys!) in a shelf can be essentially arbitrary Python objects -- anything that the pickle module can handle. This includes most class instances, recursive data types, and objects containing lots of shared sub-objects. The keys are ordinary strings. The examples section gives you the proof.
This should work. Here's what I do in my code -
import shelve
#Create shelve
s = shelve.open('test_shelf.db')
try:
s['key1'] = { 'int': 10, 'float':9.5, 'string':'Sample data' }
finally:
s.close()
#Access shelve
s = shelve.open('test_shelf.db')
try:
existing = s['key1']
finally:
s.close()
print existing
UPDATE: You could try pickle
module. It is not a key-value database but you can always build your data structure as a key-value pairs and then send it to pickle
-
If you have an object x, and a file object f that's been opened for writing, the simplest way to pickle the object takes only one line of code
pickle.dump(x, f)
To unpickle the object again, if f is a file object which has been opened for reading:
x = pickle.load(f)
I hear cPickle
is a lot faster than pickle
. You can try this if you have lot of data to store.
OTHER TIPS
In your example the keys in your database will always be integers, so it should work fine to convert them to strings,
data[str(id)] = {"Id": id, "Name": name}
My test code
def shelve_some_data(filename):
db = shelve.open(filename, flag="c")
try:
# note key has to be a string
db[str(1)] = "1 integer key that's been stringified"
db[str(2)] = "2 integer key that's been stringified"
db[str(3)] = "3 integer key that's been stringified"
db[str(10)] = "10 integer key that's been stringified"
finally:
db.close()
def whats_in(filename):
db = shelve.open(filename, flag="r")
for k in db:
print("%s : %s" % (k, db[k]))
return
filename = "spam.db"
shelve_some_data(filename)
whats_in(filename)
And the output; it works like a dict so it's not sorted.
2 : 2 integer key that's been stringified
10 : 10 integer key that's been stringified
1 : 1 integer key that's been stringified
3 : 3 integer key that's been stringified