经典Py形参陷井

iasybvm <[email protected]>
reply-to        [email protected]
to      python-cn <[email protected]>
date    Sat, Jan 30, 2010 at 19:55
subject [CPyUG] 一段灵异代码,汗。。。

现象

   1 class Category(object):
   2  def __init__(self, id):
   3   self.children = []
   4   self.id = id
   5  def recurse_for_children(self, node):
   6   children = []
   7   children.append(node)
   8   for child in node.children:
   9    if child != self:
  10     children_list = self.recurse_for_children(child)
  11     children.append(children_list)
  12   return children
  13  def recurse_normal_children(self, node, children=[]):
  14   children.append(node)
  15   for child in node.children:
  16    if child != self:
  17     self.recurse_normal_children(child, children)
  18   return children
  19  def __str__(self):
  20   return "Category %d" % self.id
  21 
  22 def get_flat_list(sequence):
  23  result = []
  24  for item in sequence:
  25   if type(item) == types.ListType:
  26    result.extend(get_flat_list(item))
  27   else:
  28    result.append(item)
  29  return result

get_flat_list和 recurse_for_children

加起来应该和get_normal_children等价的。

但是,结果却并不是这样,get_normal_children会给出多得多的结果。

>>> def recurse_for_normal(node, children=[]):
...  children.append(node)
...  for child in node.children:
...   recurse_for_normal(child, children)
...
这一个好一些。
为什么会这样啊?

原因分析

HYRY  <[email protected]>
reply-to        [email protected]
to      python-cn`CPyUG`华蟒用户组 <[email protected]>
date    Sat, Jan 30, 2010 at 20:59

Python的经典陷坑:

def recurse_normal_children(self, node, children=[]):

看下面的例子:

   1 def test(t=[]):
   2    t.append(2)
   3    print t
   4 
   5 test()
   6 test()

输出为

[2]
[2, 2]

设置初始值是在函数创建时,而不是在函数调用时。

   1 def test(tmp=[1]):
   2    return tmp
   3 
   4 print test.func_defaults
   5 
   6 print id(test.func_defaults[0])
   7 print id(test())
   8 print id(test())

输出为

([1],)
57736168
57736168
57736168

也就是说每次调用test函数并没有创建一个新列表,而是直接使用 创建函数时所创建的那个缺省值列表。因此输出的三个id是一样的。

一般处置

KDr2  <[email protected]>
sender-time     Sent at 21:03 (GMT+08:00). Current time there: 9:22 PM. ✆
reply-to        [email protected]
to      [email protected]
date    Sat, Jan 30, 2010 at 21:03

嗯,一般是

def function(default_arg=None):
      if default_arg==None:default_arg=[]
      #....

PS:动态的参数

机械唯物主义 <[email protected]>
sender-time     Sent at 21:09 (GMT+08:00). Current time there: 9:23 PM. ✆
reply-to        [email protected]
to      [email protected]
date    Sat, Jan 30, 2010 at 21:09

还有就是动态建立function的时候,如果用到外面的变量,要传进去,不然就会被覆盖掉。

   1 for i in rannge(12):
   2    button = QPushButton("number: "+str(i+1))
   3    def func(button=button):
   4        doSomething(button)
   5    connect(button, "clicked()", func)


反馈

创建 by -- ZoomQuiet [2010-01-30 13:23:58]

MiscItems/2010-01-29 (last edited 2010-01-30 13:50:45 by ZoomQuiet)