Dive into Python: XML Processing -
这里我指的是kgp.py
程序的一部分 -
def getDefaultSource(self):
xrefs = {}
for xref in self.grammar.getElementsByTagName("xref"):
xrefs[xref.attributes["id"].value] = 1
xrefs = xrefs.keys()
standaloneXrefs = [e for e in self.refs.keys() if e not in xrefs]
if not standaloneXrefs:
raise NoSourceError, "can't guess source, and no source specified"
return '<xref id="%s"/>' % random.choice(standaloneXrefs)
self.grammar:
已解析{ - 1}}表示(XML
) -
using xml.dom.minidom
<?xml version="1.0" ?>
<grammar>
<ref id="bit">
<p>0</p>
<p>1</p>
</ref>
<ref id="byte">
<p><xref id="bit"/><xref id="bit"/><xref id="bit"/><xref id="bit"/>\
<xref id="bit"/><xref id="bit"/><xref id="bit"/><xref id="bit"/></p>
</ref>
</grammar>
是self.refs:
refs
密钥的XML
进行缓存
我对这段代码有两个疑问:
怀疑1:
id
eventaully for xref in self.grammar.getElementsByTagName("xref"):
xrefs[xref.attributes["id"].value] = 1
xrefs = xrefs.keys()
将id值保存在列表中。我们不能简单地通过 -
xrefs
怀疑2:
xrefs = [xref.attributes["id"].value
for xref in self.grammar.getElementsByTagName("xref")]
在这里,我们保存 standaloneXrefs = [e for e in self.refs.keys() if e not in xrefs]
...
return '<xref id="%s"/>' % random.choice(standaloneXrefs)
ref
,我们在计算的self.refs
中看不到。{1}}。但接下来不是创建xrefs
元素,而是创建具有相同ID的<ref>
。这使我们向后退一步,因为以后我们无论如何都会找到此计算<xref>
的交叉引用并最终到达<xref>
。我们本来可以从这个<ref>
开始。
我绝不试图对这本书发表评论。我甚至没有资格。
我喜欢读这本书的每一刻。我发现很少有章节已经消失outdated,但我喜欢Mark Pilgrim's写作风格,我不能停止阅读。
答案 0 :(得分:7)
Dive Into Python现在已经七岁了(2004年出版),并不总是包含最现代的代码。所以你需要轻松上手:Dive Into Python 3可能是更好的选择。
您怀疑的建议1更改了代码的含义:将ID放入字典的键中然后再将它们删除会消除重复,而列表理解则包含重复项。现代方法是使用集合理解:
xrefs = {xref.attributes["id"].value
for xref in self.grammar.getElementsByTagName("xref")}
但这在2004年没有。
关于你的疑问2,我不完全确定我看到了问题。是的,从某种意义上讲,这是一种浪费,但另一方面,代码已经有了xref
案例的处理程序,因此重新使用该处理程序而不是添加额外的特殊情况是有意义的。
该示例中还有其他一些代码可以进行现代化。例如,
source and source or self.getDefaultSource()
现在是source or self.getDefaultSource()
。行
standaloneXrefs = [e for e in self.refs.keys() if e not in xrefs]
可以更好地表达为设置差异操作,例如:
standaloneXrefs = set(self.refs) - set(xrefs)
但随着语言变得更具表现力,会发生这种情况:旧代码开始看起来相当不优雅。
答案 1 :(得分:1)
for xref in self.grammar.getElementsByTagName("xref"):
xrefs[xref.attributes["id"].value] = 1
xrefs = xrefs.keys()
这是构建集合的极其粗糙的方法。这应该写成
set(xref.attributes["id"].value
for xref in self.grammar.getElementsByTagName("xref"))
或甚至(在Python 2.7+中):
{xref.attributes["id"].value
for xref in self.grammar.getElementsByTagName("xref")) }
如果避免重复不是问题,那么您的解决方案(构建列表)也会起作用。因为无论如何迭代了xref,甚至可以生成迭代器。
standaloneXrefs = [e for e in self.refs.keys() if e not in xrefs]
...
return '<xref id="%s"/>' % random.choice(standaloneXrefs)
如果外部参照包含"
或&
等特殊字符,则此代码完全中断。
但是,原则上,在此构建<xref>
元素是正确的,因为它必须与外部source
具有相同的格式(getDefaultSource
称为
self.loadSource(source and source or self.getDefaultSource())
)。
这两个代码摘录都是糟糕编程的例子,不应该包含在有意教人们如何编程的书中。 Dive Into Python3有better XML examples and code。
答案 2 :(得分:1)
你的怀疑是完全合理的:代码对我来说根本不是很好。例如,它使用1
作为布尔值,其中True
已经足够并且更加清晰。
这两个片段没有做同样的事情。如果有重复项,原始代码会过滤掉它们,但您的替代方案不会。另一方面,您的代码保留原始顺序,而原始代码以任意顺序返回元素。
为了完全等效,我们可以使用set
内置:
xrefs = list(set([xref.attributes [“id”]。value 对于self.grammar.getElementsByTagName(“xref”)中的xref)))
(但转换回列表可能没有意义。)
没时间,跑步,抱歉......