编写此 elementTree 搜索操作的更好方法?

Better way to write this elementTree search operation?

我正在编写 python 脚本来研究期权定价。我在 XSL 中做了很多预处理并输出一个 XML 文件,该文件使用 elementTree api.

读入我的 python 脚本

xml的结构如下:
根 XML 节点的子节点是股票元素,每个股票一个。
<stock> 元素的子元素是日元素,每天一个。
<day> 个元素的子元素是 f 个元素,一个对应于我查看的每个前瞻日。
f 元素有一些属性,"days" 表示当天的前进时间,"change" 表示当天股价的变化。

由于股票不是每天都在交易,所以“@days”的顺序有空缺。例如,与星期四关联的日元素可能如下所示:

<day [info in attributes>
<f days="1" change="-3.1"/>
<f days="4" change="-1"/>
<f days="5" change="0.4"/>
<f days="6" change="1.1"/>
...
</day>

现在,我正在尝试查找历史数据并查找 @days = X 的实例,其中 X 是输入。但是,如果给定的 <day> 元素没有这样的一天,我将选择一个 f 元素,其中 @days = X - 1。如果它没有其中之一,我将寻找一个 f 元素,其中@days = X + 1.

不幸的是,如果您尝试执行 f[@days = X].get('change') 如果没有 f 元素且 days = X,elementTree 库将抛出错误。所以我目前通过以下方式执行此操作:

Changes = []
for day in Test_Stock:
    forward_days = [int(f.get('days')) for f in day]
    if X in forward_days:
        expiry_day = [f for f in day if int(f.get('days')) == X]
        Changes.append(float(expiry_day[0].get('change')))
    elif (X - 1) in forward_days:
        proxy_day = [f for f in day if int(f.get('days')) == (X - 1)]
        Changes.append(float(proxy_day[0].get('change')))
    elif (X + 1) in forward_days:
        proxy_day = [f for f in day if int(f.get('days')) == (X + 1)]
        Changes.append(float(proxy_day[0].get('change')))

这给出了预期的结果,但我希望有一种更简单的方法可以做到这一点,并且想知道如何更好地使用 elementTree 对象。

因为对X、X-1、X+1的处理是一样的,所以可以使用这样的循环:

Changes = []
for day in Test_Stock:
    forward_days = [int(f.get('days')) for f in day]
for x in [X,X-1,X+1]:
    if x in forward_days:
        expiry_day = [f for f in day if int(f.get('days')) == x]
        Changes.append(float(expiry_day[0].get('change')))
        break

而不是.get,尝试.find with an XPath,其中returns None如果没有匹配的元素,而不是异常。

使用 findElementTree 为您进行搜索,而不需要使用 [f for f in int(f.get('days')) == x] 手动过滤。

因此,对于每个 day,您想要的 f 元素(如果存在)将是此列表中的第一个非 None 项目:

[day.find("f[@days='%d']" % index)
 for index in [X, X - 1, X + 1]]

这也意味着你可以把你的整个函数写成一个可怕的 one-liner 像这样(未经测试):

Changes = [float(d[0].get('change'))
           for d in [islice(ifilter(len, (day.find("f[@days='%d']" % candidate)
                                          for candidate in [X, X - 1, X + 1])),
                            1)
                     for day in Test_Stock]
           if d]

但请不要这样做。

但一定要调查 .find