【发布时间】:2022-01-20 02:12:38
【问题描述】:
我相信我知道这个问题的答案,但我想仔细检查一下,因为我觉得这有点令人困惑。
def outerFunc():
mySet = set()
a = 0
def innerFunc():
mySet.add(1)
mySet.add(2)
a = 7
innerFunc()
print(mySet) # {1, 2}
print(a) # 0
这里,如果我想改变a的值,我需要使用nonlocal。集合改变的事实仅仅是因为集合是通过引用传递的吗?那么,在内部函数中,我们可以访问外部函数变量的值,但不能修改它们,除非它们是引用?
【问题讨论】:
-
sets 并没有什么特别之处。如果不使用nonlocal,您根本无法重新分配变量。如果您尝试使用mySet = {1, 2},那么不使用nonlocal也将无法正常工作。 -
@GlennEdstrom 没有。可变性是无关的。相关细节是分配。
-
所以简而言之,分配总是自动本地。这意味着赋值语句(函数中的任何位置)会将该变量标记为本地变量(由编译器!)除非您使用
nonlocal或global。所涉及的对象的类型无关紧要,正如@rchome 所述,您可以使用mySet = {1, 2},您将获得与a = 7相同的行为。但是,您可以引用来自封闭范围的变量,并且遵守正常的查找规则,而无需声明任何内容。 -
所以
mySet.add(2)有效,因为没有分配,它找到最接近的封闭范围并正确解析为您在outerFunc中定义的集合。再说一次,被引用的对象的类型是无关紧要的。您可以在innerFunc中执行print(a.as_integer_ratio()),它将正确解析为outerFunc中的int对象。当然,int方法都不会改变int的值——即int对象是不可变的(它们缺少mutator 方法)。 -
Python的求值策略,既不是引用调用也不是值调用。该名称实际上是“通过共享调用”,尽管这是一个晦涩的术语。它是由 Barbara Liskov(Liskov Substitution Principle!)为语言 CLU 创造的,这对 OOP 的发展非常有影响。请注意,在 Java 社区中,他们说“Java 是按值调用,但值是对象引用”,这只是混淆了语义的实现,而且它不是纯面向对象的,因为 Java 有一个“原始”类型和“参考”类型之间的区别。
标签: python set nested-function python-nonlocal