Python NoneType 对象未按预期工作
Python NoneType object is not working as intended
我正在尝试 pass by object 一个 None
值,希望将其重新分配给实际值。有人可以解释为什么这不起作用吗?我想因为 None
是一个 NoneType
它将通过引用传入,当我使用传入的变量时,我会改变原始的 None
对象。这是不正确的吗?我在下面提供了一个片段来演示我的案例:
class MyClass:
def __init__(self):
self.value = None
def assign(self, object):
object = OtherClass()
example = MyClass()
example.assign(example.value)
结果是example.value
还是None
。这是为什么?我读过一些 SO posts 但其中 none 解释得很清楚。
编辑:不是重复的,因为我想知道为什么当我认为它应该通过引用传递时它表现得像按值传递。最后,我得出结论,NoneType
对象是不可变的,因此总是按值传递。我需要使用 list
类型的对象或可变的东西。
再次编辑:我的示例代码只是一般情况。我试图实现一个 BST,我的初始根节点是 None
,当我将根节点指定为一个 Node
对象时,它仍然是 NoneType
,这导致我成为困惑,是这个问题的原因。
最后编辑:下面的答案提供了一个非常好的对象传递的 tl;dr 总结。仅通过 searching/reading 论坛无法理解。
问题在于函数调用传递值,而不是引用。具体来说,传递给函数的引用保持不变,直到它被反弹(它的值设置),此时在函数本地创建一个副本。 other = ...
形式的任何一行都会导致这种情况发生。如果你想要这种行为,你需要使用一个可变对象,比如一个列表。例如:
class MyClass:
def __init__(self):
self.value = [None]
def assign(self, object):
object[0] = OtherClass()
example = MyClass()
example.assign(example.value)
希望对您有所帮助!
这正是对象调用(Python 规则)不同于引用调用(C++ 引用语义)的情况。
不同之处在于,分配给非限定名称会重新绑定该名称,它对该名称之前可能绑定的任何内容都没有任何影响(除了可能销毁它,如果没有其他引用保留的话)。该名称与可能引用同一对象的任何其他名称没有关联,因此不会更改这些其他名称。
所以在这种情况下,object
最初设置为指向同一个对象 example.value
指向。但是在下一行,您重新绑定 object
(不合格的名称分配),它指向一个完全不同的对象。
相比之下,如果您有:
def assign_value(self, object):
object.value = OtherClass()
并调用它:
example.assign(example)
那么 example
和 object
将引用同一个对象,并且您对限定名称的分配将替换该对象上的 value
。
综上所述,您此处的用例不需要任何此类更改。调用 example.assign(example.value)
没有任何意义,因为 self
是隐式传递的,并且会自动让您访问 value
(合格访问)。似乎您真正想要的只是在完全没有参数的情况下进行延迟初始化:
def assign(self):
self.value = OtherClass()
称为:
example.assign()
回应您的编辑:Python documents this call behavior explicitly:
The actual parameters (arguments) to a function call are introduced in the local symbol table of the called function when it is called; thus, arguments are passed using call by value (where the value is always an object reference, not the value of the object).[1]
脚注 1 说明:
[1] Actually, call by object reference would be a better description, since if a mutable object is passed, the caller will see any changes the callee makes to it (items inserted into a list).
这是有意的;当您没有其他可用的调用语义时,C++ 引用语义是行不通的,因为没有明显的选择退出方法,这意味着巨大调用链上的每个变量最终都引用同一个对象,从而导致大量操作-距离。
我正在尝试 pass by object 一个 None
值,希望将其重新分配给实际值。有人可以解释为什么这不起作用吗?我想因为 None
是一个 NoneType
它将通过引用传入,当我使用传入的变量时,我会改变原始的 None
对象。这是不正确的吗?我在下面提供了一个片段来演示我的案例:
class MyClass:
def __init__(self):
self.value = None
def assign(self, object):
object = OtherClass()
example = MyClass()
example.assign(example.value)
结果是example.value
还是None
。这是为什么?我读过一些 SO posts 但其中 none 解释得很清楚。
编辑:不是重复的,因为我想知道为什么当我认为它应该通过引用传递时它表现得像按值传递。最后,我得出结论,NoneType
对象是不可变的,因此总是按值传递。我需要使用 list
类型的对象或可变的东西。
再次编辑:我的示例代码只是一般情况。我试图实现一个 BST,我的初始根节点是 None
,当我将根节点指定为一个 Node
对象时,它仍然是 NoneType
,这导致我成为困惑,是这个问题的原因。
最后编辑:下面的答案提供了一个非常好的对象传递的 tl;dr 总结。仅通过 searching/reading 论坛无法理解。
问题在于函数调用传递值,而不是引用。具体来说,传递给函数的引用保持不变,直到它被反弹(它的值设置),此时在函数本地创建一个副本。 other = ...
形式的任何一行都会导致这种情况发生。如果你想要这种行为,你需要使用一个可变对象,比如一个列表。例如:
class MyClass:
def __init__(self):
self.value = [None]
def assign(self, object):
object[0] = OtherClass()
example = MyClass()
example.assign(example.value)
希望对您有所帮助!
这正是对象调用(Python 规则)不同于引用调用(C++ 引用语义)的情况。
不同之处在于,分配给非限定名称会重新绑定该名称,它对该名称之前可能绑定的任何内容都没有任何影响(除了可能销毁它,如果没有其他引用保留的话)。该名称与可能引用同一对象的任何其他名称没有关联,因此不会更改这些其他名称。
所以在这种情况下,object
最初设置为指向同一个对象 example.value
指向。但是在下一行,您重新绑定 object
(不合格的名称分配),它指向一个完全不同的对象。
相比之下,如果您有:
def assign_value(self, object):
object.value = OtherClass()
并调用它:
example.assign(example)
那么 example
和 object
将引用同一个对象,并且您对限定名称的分配将替换该对象上的 value
。
综上所述,您此处的用例不需要任何此类更改。调用 example.assign(example.value)
没有任何意义,因为 self
是隐式传递的,并且会自动让您访问 value
(合格访问)。似乎您真正想要的只是在完全没有参数的情况下进行延迟初始化:
def assign(self):
self.value = OtherClass()
称为:
example.assign()
回应您的编辑:Python documents this call behavior explicitly:
The actual parameters (arguments) to a function call are introduced in the local symbol table of the called function when it is called; thus, arguments are passed using call by value (where the value is always an object reference, not the value of the object).[1]
脚注 1 说明:
[1] Actually, call by object reference would be a better description, since if a mutable object is passed, the caller will see any changes the callee makes to it (items inserted into a list).
这是有意的;当您没有其他可用的调用语义时,C++ 引用语义是行不通的,因为没有明显的选择退出方法,这意味着巨大调用链上的每个变量最终都引用同一个对象,从而导致大量操作-距离。