我正在编写一个应用程序,其中的标签是可链接的,有必要检索整个链接标签链。不允许自引用运行以下代码最终会得到一些非常奇怪的结果:

class Tag(object):
  def __init__(self, name):
    self.name = name
    self.links = []

  def __repr__(self):
    return "<Tag {0}>".format(self.name)

  def link(self, tag):
    self.links.append(tag)


def tag_chain(tag, known=[]):
  chain = []
  if tag not in known:
    known.append(tag)
  print "Known: {0}".format(known)

  for link in tag.links:
    if link in known:
      continue
    else:
      known.append(link)
    chain.append(link)
    chain.extend(tag_chain(link, known))
  return chain

a = Tag("a")
b = Tag("b")
c = Tag("c")
a.link(b)
b.link(c)
c.link(a)

o = tag_chain(a)
print "Result:", o
print "------------------"
o = tag_chain(a)
print "Result:", o

结果
Known: [<Tag a>]
Known: [<Tag a>, <Tag b>]
Known: [<Tag a>, <Tag b>, <Tag c>]
Result: [<Tag b>, <Tag c>]
------------------
Known: [<Tag a>, <Tag b>, <Tag c>]
Result: []

所以,不知怎么的,我不小心创造了一个结束。据我所见,known应该已经超出了范围,在函数调用完成后就消失了。
如果我将chain_tags()的定义更改为不设置默认值,问题就会消失:
...
def tag_chain(tag, known):
...
o = tag_chain(a, [])
print "Result:", o
print "------------------"
o = tag_chain(a, [])
print "Result:", o

这是为什么?

最佳答案

这是python中常见的错误:

def tag_chain(tag, known=[]):
  # ...

known=[]并不意味着如果known不适用,则将其设为空列表;事实上,它将known绑定到“匿名”列表。每次已知的默认列表都是相同的列表。
典型的模式是:
def tag_chain(tag, known=None):
    if known is None:
        known = []
    # ...

如果没有提供,known将正确初始化为空列表。

07-24 20:20