Why does setting a default make this function private?

I am writing an application in which tags are related to each other and you need to get the whole chain of related tags. Self reference is not allowed. Execution of the following code ends with very strange results:

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

Results:

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: []

So, for some reason, I accidentally created a closure. As far as I can tell, the famous ones had to go out of scope and die after the function call was completed.

If I change the definition of chain_tags () so as not to set a default value, the problem disappears:

...
def tag_chain(tag, known):
...
o = tag_chain(a, [])
print "Result:", o
print "------------------"
o = tag_chain(a, [])
print "Result:", o

Why is this?

+3
source share
2 answers

This is a common mistake in Python:

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

known=[] , , , ; "" . , , .

, , :

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

known , .

+9

, , : (.. tag_chain.func_defaults Py2) :

>>> def x(a=['here']):
...     a.append(a[-1]*2)
...
>>> x
<function x at 0x0053DB70>
>>> x.func_defaults
(['here'],)

, :

>>> x()
>>> x.func_defaults
(['here', 'herehere'],)
>>> x()
>>> x.func_defaults
(['here', 'herehere', 'herehereherehere'],)

.

+3

Source: https://habr.com/ru/post/1772950/


All Articles