通过查看源文件npyio.py,似乎是因为处理请求的DataSource对象在创建时没有传递相关参数导致的。 当然,修改库源代码以禁用缓存很容易,但这意味着我必须在每次升级后重复此操作。
除了每次删除缓存目录之外,还有其他解决方案吗?
如果库的功能与所需行为不完全匹配,该怎么办?
特别是如何处理genfromtxt
的缓存行为?
关于第一点,包装(可能带有注入)比修补库更具弹性(除非在库的repo中进行了修补)。
因此,可以像这样包装genfromtxt
:
def patched_gen_from_text(*args, **kwargs):
# Do something regarding caching
return numpy.genfromtxt(*args, **kwargs)
import numpy
numpy.genfromtxt = patched_gen_from_text
关于第二点,这取决于您对远程文件系统的访问权限(例如,您是否可以在那里运行进程?是否可以挂载它?)以及所需速度和确定性之间的权衡。
例如,在一个极端情况下,您的修补版本可以无条件地删除本地文件(确切但慢)。或者,您可以请求远程文件的更新时间和长度,并查看它们与本地文件的对应关系。在另一个极端情况下,您可能可以在另一台计算机上通过RPC运行md5检查。
您可能想要查看filecmp以获取不同的比较选项,以及一些情况下可能的实际构建块。
研究库源码后,我意识到可以通过修改numpy的datasource模块中名为open的小助手函数的默认值来实现所需的行为。如上所述,这可以在不修改库源码的情况下实现。以下是我编写的代码:
import numpy
from numpy.lib._datasource import DataSource
#def open(path, mode='r', destpath=os.curdir):
def openm(path, mode='r', destpath=None):
ds = DataSource(destpath)
return ds.open(path, mode)
numpy.lib._datasource.open=openm
在调用genfromtxt或其派生函数之前,必须包含它。
但是我的研究进一步揭示了这些函数非常缓慢,在Windows中禁用缓存会产生警告 - 这不是由于上面的重新定义,而似乎与mktemp函数在Windows中的实现方式有关。此外,缓存文件和相关的临时目录没有被删除。
这似乎与处理请求的数据源在文件读取和关闭之前就超出了范围(因此被删除)有关。当数据源的析构函数执行时,它尝试删除数据源的目录,由于文件句柄仍然打开,所以出现警告。我考虑将数据源实例化移动到genfromtxt函数中。 我确认将数据源实例化移动到genfromtxt函数中在Windows和Linux下都可以正常工作,因此我认为这是正确的解决方案。
我得出结论,最干净的方法是修改numpy库并将缓存参数添加到genfromtxt
以下是对npyio.py进行的必要修改,只需要修改几行即可。 genfromtxt函数原型更改为
def genfromtxt(fname, dtype=float, comments='#', delimiter=None,
skiprows=0, skip_header=0, skip_footer=0, converters=None,
missing='', missing_values=None, filling_values=None,
usecols=None, names=None,
excludelist=None, deletechars=None, replace_space='_',
autostrip=False, case_sensitive=True, defaultfmt="f%i",
unpack=None, usemask=False, loose=True, invalid_raise=True):
添加了一个新的缓存参数
def genfromtxt(fname, dtype=float, comments='#', delimiter=None,
skiprows=0, skip_header=0, skip_footer=0, converters=None,
missing='', missing_values=None, filling_values=None,
usecols=None, names=None,
excludelist=None, deletechars=None, replace_space='_',
autostrip=False, case_sensitive=True, defaultfmt="f%i",
unpack=None, usemask=False, loose=True, invalid_raise=True,cache=True):
并且打开文件/URL的代码行会改变
if isinstance(fname, basestring):
fhd = iter(np.lib._datasource.open(fname, 'rbU')
own_fhd = True
到
if isinstance(fname, basestring):
ds=DataSource('.' if cache==True else None)
fhd = iter(ds.open(fname, 'rbU'if cache==True else 'rbUD'))
own_fhd = True
def mgenfromtxt(fname,cache=True,**karg):
if cache==False and isinstance(fname, basestring) and numpy.DataSource()._isurl(fname):
ds=numpy.DataSource(None)
fhd = iter(ds.open(fname,'rbUD'))
l1=numpy.genfromtxt(fhd,**karg)
fhd.close()
del ds
return l1
else:
return(numpy.genfromtxt(fname,**karg))
fhd = iter(np.lib._datasource.open(fname, 'rbU',None))
。 - NameOfTheRosegenfromtxt
,这样做有帮助吗? - hpaulj