潜入python书中对kgp.py程序的具体怀疑

时间:2011-07-31 11:38:45

标签: python xml

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写作风格,我不能停止阅读。

3 个答案:

答案 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已经足够并且更加清晰。

怀疑1:

这两个片段没有做同样的事情。如果有重复项,原始代码会过滤掉它们,但您的替代方案不会。另一方面,您的代码保留原始顺序,而原始代码以任意顺序返回元素。

为了完全等效,我们可以使用set内置:

xrefs = list(set([xref.attributes [“id”]。value                     对于self.grammar.getElementsByTagName(“xref”)中的xref)))

(但转换回列表可能没有意义。)

怀疑2:

没时间,跑步,抱歉......