Python 将文件映射到内存
考虑一个文件,其内容是一个pickled python对象。为了使事情具体化,假设这个对象只是一个字符串列表,但实际上它更复杂 我的python脚本在启动时读取该文件。随后,某些事件会触发读取对象的小更新(在本例中,列表中的任何位置都会添加或删除字符串)。为了使文件保持最新,脚本会对对象进行pickle并将其写入文件(即,整个文件是从头开始写入的) 有没有办法避免每次都重写整个对象?我对存储数据的其他方式持开放态度,即不依赖酸洗。我想我正在寻找某种将文件映射到内存的方法,以便对内存中的对象进行任何更新都会立即更新文件。update tl;博士Python 将文件映射到内存,python,pickle,Python,Pickle,考虑一个文件,其内容是一个pickled python对象。为了使事情具体化,假设这个对象只是一个字符串列表,但实际上它更复杂 我的python脚本在启动时读取该文件。随后,某些事件会触发读取对象的小更新(在本例中,列表中的任何位置都会添加或删除字符串)。为了使文件保持最新,脚本会对对象进行pickle并将其写入文件(即,整个文件是从头开始写入的) 有没有办法避免每次都重写整个对象?我对存储数据的其他方式持开放态度,即不依赖酸洗。我想我正在寻找某种将文件映射到内存的方法,以便对内存中的对象进行任
- 是的,只有字符串变量适用于索引
- 对于每个键值对,对值的任何更改都需要将整个值重新写入磁盘
- 您使用的键越多,值越小,磁盘写入就越小
import shelve
d = shelve.open(filename) # open -- file may get suffix added by low-level
# library
d[key] = data # store data at key (overwrites old data if
# using an existing key)
data = d[key] # retrieve a COPY of data at key (raise KeyError if no
# such key)
del d[key] # delete data stored at key (raises KeyError
# if no such key)
flag = d.has_key(key) # true if the key exists
klist = d.keys() # a list of all existing keys (slow!)
# as d was opened WITHOUT writeback=True, beware:
d['xx'] = range(4) # this works as expected, but...
d['xx'].append(5) # *this doesn't!* -- d['xx'] is STILL range(4)!
# having opened d without writeback=True, you need to code carefully:
temp = d['xx'] # extracts the copy
temp.append(5) # mutates the copy
d['xx'] = temp # stores the copy right back, to persist it
# or, d=shelve.open(filename,writeback=True) would let you just code
# d['xx'].append(5) and have it work as expected, BUT it would also
# consume more memory and make the d.close() operation slower.
d.close() # close it
根据评论,让我解释几件事
字符串作为键:
就像tin上说的那样,你只能用字符串索引键值对。这与普通字典不同,普通字典可以将任何哈希类型作为键。例如:
import shelve
database = shelve.open(filename) #open our database
dictionary = {} #create an empty dict
ingredients = ['flour', 'sugar', 'butter', 'water'] #recipe for something tasty
database['pie dough'] = ingredients #works because 'pie dough' is a string
dictionary['pie dough'] = ingredients #works because strings are hashable
recipe = 'pie dough'
database[recipe] = ingredients #you can use a variable as long as it is of <type 'str'>
#say we want to just number our entries..
database[5] = ingredients #won't work because 5 is an integer not a string
dictionary[5] = ingredients #works because integers are hashable
database.close()
我们已经意识到我们需要在这个配方中添加盐,我们的目标是一个列表,因此我们可以相对容易地调用:
mylist.append('salt')
然后,我们可以使用简单的赋值将这个新的更新配方写回数据库或字典
database['pie dough'] = mylist
#or
dictionary['pie dough'] = mylist
此方法将始终适用于数据库和字典。当您希望直接引用对象时,就会出现这种差异。当我们可以引用字典中包含的列表本身时,仅将mylist变量创建为临时变量是多余的:
dictionary['pie dough'].append('salt')
这是一个直接的结果,因为字典中的值是对ram中原始对象的引用。当您修改字典['pie ruam']
时,您也在修改我的列表
,以及成分
,因为它们实际上是同一个对象。加载对象时使用数据库:mylist=database['pie ruam']
您正在制作硬盘上的内容的副本。您可以随意修改该副本,但它不会更改硬盘上的内容,因为它不是同一个对象(它是副本)
解决方法是使用关键字writeback=True
打开数据库。这提供了一些类似的功能,但有一些警告。。。虽然现在可以直接在字典对象上调用append(…)
,而无需进行复制,但在调用dictionary.sync()
或dictionary.close()
之前,更改不会出现。为此,我将从一个新的示例开始:
import shelve
d = shelve.open(filename)
d['dough'] = ['flour', 'sugar', 'butter', 'water']
d.close() #write initial recipe to our database
#some time later we want to update the recipe
d = shelve.open(filename, writeback=True)
d['dough'].append('salt')
d.close()
现在,只要您访问数据库的一部分,该部分就会加载到ram中,并且可以直接对对象进行更新。最大的警告是,在调用
d.close()
之前,更新不会写入硬盘。数据库通常比系统中所有可用的ram都大,并且试图在不调用d.sync()的情况下更新太多对象
将挂起的更改写入硬盘驱动器或定期关闭和重新打开数据库可能会导致内存不足的问题。听起来您应该使用数据库来存储数据。或者,您也可以使用Python的模块,它可以有效地为您提供持久的基于磁盘的词典。显然,我没有太多工作要做,所以我为您提出的问题添加了详细的解释。我看到你把它们删掉了,希望你能找到答案?如果是这样的话,我试图解释模块的一些细微差别,这些细微差别可能会因为简单的问题而被忽略,但随后会成为一个令人烦恼的难以发现的问题(例如:为什么python会占用我所有的ram?)
import shelve
d = shelve.open(filename)
d['dough'] = ['flour', 'sugar', 'butter', 'water']
d.close() #write initial recipe to our database
#some time later we want to update the recipe
d = shelve.open(filename, writeback=True)
d['dough'].append('salt')
d.close()