【问题标题】:What determines if the variable will be altered or not?是什么决定了变量是否会改变?
【发布时间】:2020-08-05 03:22:01
【问题描述】:
class MyClass:
    def __init__(self, a):
        self.a = a

def append(some_list):
    some_list.append(["d"])
    
foo =[["a"],["b"],["c"]]
bar = foo
my_class = MyClass(foo)

append(bar)

for item in bar:
    item[0] += "x"
    letters = item[0]
    letters += "z"
print (my_class.a)

产生输出

[['ax'], ['bx'], ['cx'], ['dx']]

这个例子中发生了很多事情,我对所有这些都感觉很好,除了我希望“z”也会被标记到字符串上,但事实并非如此。

有人可以解释为什么“z”不包含在字符串中是有意义的吗?

我认为索引会返回带有字符串的“容器”,然后附加“z”会改变存储的字符串。显然制作了一个独特的“容器”,但我不明白如何或为什么。

(如果附加到字符串会生成一个新字符串,我不知道为什么我测试过的整数也会发生相同的行为......使用浮点数会产生不同的结果吗?)

【问题讨论】:

  • @deadshot 没有,因为它没有回答为什么 letters = item[0]bar = foo 的行为不同——一个修改它派生的变量,另一个不修改。为什么容器被指向相同的一个而不是另一个? item[0] 会在内存中创建一个新位置吗?为什么他们会这样做而不是bar = foo
  • @financial_physician 你真的应该阅读以下内容:nedbatchelder.com/text/names.html。在任何情况下,这些赋值语句的行为都没有不同。但是,在一种情况下,您正在改变一个列表,在另一种情况下,您正在创建一个新字符串(这是 + 运算符对 stings 所做的)。
  • @juanpa.arrivillaga 这是一篇好文章。我认为它解释了 AerysS 的文章。关于可变对象与不可变对象的快速段落是我在知识上的差距所在。两篇文章都明确区分。

标签: python pass-by-reference


【解决方案1】:

这是因为可变对象。例如

>>>l1 = [1,2,3]
>>>l2 = l1
>>>l2[0]=4
>>>print(l1[0])
4

在示例中,l1l2 指向同一个内存位置。要将l1 创建为l2 的副本,请使用copy()

>>>l1 = [1,2,3]
>>>l2 = l1.copy()
>>>l2[0]=4
>>>print(l1[0]) 
1
>>>print(l2[0])
4

编辑:根据建议的评论更改解释。

在您的示例中,foobar 指向相同的内存位置:您在 foo 中更改的内容也会在 bar 中更改。为什么它不附加“z”是因为letters 是一个声明的变量,其值为item[0],但它不会发生变异。 如果您print(letters),它将打印"dz"

【讨论】:

  • 好的,那么声明变量和声明一个变量等于另一个变量有什么区别呢?似乎您在它们两个中都声明了变量,所以我很难弄清楚为什么在声明 letters = item[0] 而不是在声明 bar = foo 时它应该是一个不同的容器
  • barfoo 是可变对象,而 letters=item[0] 不是,它是如何工作的:medium.com/@meghamohan/…
  • 为我工作。谢谢!
  • @AerysS 您的解释不正确。 “因为letters 是一个声明变量,其值为item[0],但它并不指向该内存地址。”是的,它确实指向同一个对象(谈论内存地址在 Python 中并没有真正的帮助,但如果我们这样做,那么它们指向同一个地址)。在这两个示例中,变量引用 与列表中的对象相同的对象,但在列表的情况下,您正在改变对象,即item[0] += "x",而在第二种情况下,您没有改变字符串,即letters += "z".
  • @financial_physician 不是,这个解释是错误的。区别很简单,list 对象暴露了 mutator 方法,即。它们是可变的。 item[0] += "x" mutatuesitem 引用的列表,与bar 中的列表相同。另一方面,letters += "z" 不会改变 letters 所引用的字符串对象,字符串对象不会公开 mutator 方法(它们是不可变的)。即使lettersitem[0] 是同一个列表对象
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-22
  • 1970-01-01
  • 2021-07-02
  • 2012-10-21
  • 1970-01-01
相关资源
最近更新 更多