Python中的递归类对象和成员变量

2024-09-29 23:15:38 发布

您现在位置:Python中文网/ 问答频道 /正文

遵守以下代码:

class permcom:
  def __init__(self, INPUT_SET, IS_PERM, REPETITION):
    self.end_set = []
    self.input_set = INPUT_SET
    self.is_perm = IS_PERM
    self.repetition = REPETITION
  def helpfunc(self, seen, depth, current):
    if depth == 0:
      self.end_set.append(seen)
    else:
      for i in range(0, len(self.input_set)):
        if(self.repetition):
          seen.append(self.input_set[i])
          if(self.is_perm):
            self.helpfunc(seen, depth - 1, 0)
          else:
            self.helpfunc(seen, depth - 1, i)
          del seen[-1]

# return all permutations with repetition
def rapwr(INPUT_SET, subset_size):
  instance = permcom(INPUT_SET, True, True)
  A = []
  instance.helpfunc(A, subset_size, 0)
  return instance.end_set

A = [1,2,3]
B = rapwr(A, 2)
for i in range(0, len(B)):
  print B[i]

输出如下:

^{pr2}$

但是,预期输出如下:

[1, 1]
[1, 2]
[1, 3]
[2, 1]
[2, 2]
[2, 3]
[3, 1]
[3, 2]
[3, 3]

我花了太多的时间来研究这些代码,不幸的是,我仍然无法确定到底是什么地方出了问题。关于成员变量在Python中的工作方式,我肯定有一些基本的东西我不理解,但是我仍然不太理解这里发生了什么以及代码为什么不能工作。有人能解释一下吗?在


Tags: instance代码selfinputifdefendseen
1条回答
网友
1楼 · 发布于 2024-09-29 23:15:38

简短回答

您需要的是列表切片[:]。改变陈述

if depth == 0:
  self.end_set.append(seen)

^{pr2}$

给出了预期的答案

长答案

在python解释器中尝试这个示例代码

a = [1,2]
b = []
b.append(a)
a[0] = 3
print b
# output is [[3, 2]]

现在试试这个代码

a = [1,2]
b = []
b.append(a[:])
a[0] = 3
print b
# output is [[1, 2]]

为什么会这样?在第一种情况下,当您将a附加到列表b时,追加的不是a,而是对[1,2]值的一个引用/标记。您可以通过打印id(b[0])id(a)来验证这一点。两者的值相同。因此,当您修改a列表中的任何值时,b列表中的值也会更改。在

你的代码也是如此。由于您正在执行del seen[-1],因此self.end_set中相应的值也将被删除。您可以通过在depth == 0块中打印self.end_set的值来确认这一点。在

为了避免这种情况,可以将一个列表的克隆附加到另一个列表。这是通过使用拼接语法[:]完成的。从列表的开始处创建列表的副本。您可以了解有关切片here的更多信息。在

PS:使用切片时,请尝试打印两个列表的id()值将不同

这是我得到的

a = [1,2]
b = []
b.append(a)
print id(b[0])
#output is 43337352L
print id(a)
#output is 43337352L
b = []
b.append(a[:])
print id(b[0])
#output is 43337608L

看看这个pythonmemory model diagram,可以更好地理解上面的内容

更新:一些建议

  1. 由于B和{}都是列表,所以更喜欢使用惯用的for i in B和{}。在
  2. 确保函数名可以理解。总有一天它会帮你的。通常情况下,如果要为变量或函数名编写注释,则最好使用注释本身的缩写来命名函数/变量。因此rapwr可以重命名为return_all_permutations_with repetition。虽然名称很大,但是现在不看方法体就很容易理解它的作用。在

相关问题 更多 >

    热门问题