我在一本关于语言描述的书中看到了
On the other hand, a name can be bound to no object (a dangling pointer),
one object (the usual case), or several objects (a parameter name in a
recursive function).
我们如何将名称绑定到多个对象?我们所谓的数组是不是所有元素具有相同的名称但具有索引?对于递归函数,如下例所示:
x = 0
def f(y):
global x
x += 1
if x < 4 :
y +=100
f(y)
else: return
f(100)
名称y
是否绑定了多个递归创建的值,因为名称表已经将y
名称绑定到初始值,并使用递归进行复制?
已编辑只需按此处Visualizer即可查看其生成的内容。 :)
答案 0 :(得分:6)
没有。 名称绑定到一个对象。当我们谈论Python时 - 它要么绑定到给定上下文中的单个对象,要么根本不存在。
会发生什么,内部工作可能在几个“层”中定义了名称 - 但是您的代码只能看到其中一个。
如果名称是递归函数中的变量,则只会在当前运行的上下文中看到与它绑定的内容 - 每次在Python中执行函数调用时,执行框架都是一个包含多个函数的对象运行代码的属性(包括对局部变量的引用)被冻结。在被调用函数上,创建一个新的执行框架,然后,变量名称再次绑定到它们在被调用上下文中的任何新值。您的代码只是“看到”此实例。
然后,Python中存在全局变量和内置对象的问题:如果名称不是函数执行上下文中的局部变量,则在模块的全局变量中搜索它(再次,只有其中一个将是可见的.ANd如果名称在全局变量中不是defiend,那么,Python会在globals().__builtins__
中查找它,这是你的最后一次调用。
答案 1 :(得分:3)
如果我理解正确,你会问到Python在不同scopes中创建变量的规则。 Python在函数级别使用lexical scoping。
很难确切地说出你所编写的代码到底是什么,但是,虽然在不同的范围内可能存在与y
相关联的不同值(值为y
在每个递归级别定义),您的代码将始终只能看到一个(在您运行的作用域中定义的值)。
要真正理解Python中的范围规则,我会看一下PEP 227。另外,请查看this Stack Overflow question。
最后,为了能够聪明地谈论Python中的“名称”,我建议您阅读Python是如何使用“Call-By-Object”语言。
此时,我们能够理解,python使用字典来保存给定范围内的可访问内容,而不是“nametable”。有关更多详细信息,请参阅this answer。这意味着你在一个范围内永远不会有两个相同的名称(出于同样的原因,你不能在python字典中拥有两个相同的密钥)。因此,虽然y
可能存在于不同范围的字典中,但您无法访问它,因为您只能访问当前范围字典中的变量。
答案 2 :(得分:0)
关键是:
几个对象(递归函数中的参数名称)。
该段落几乎肯定不是指数组,而只是指在递归函数(或任何函数,但递归函数可能同时具有多个激活)的事实中,参数可能绑定到每次递归调用都有不同的值。
这并不意味着您可以访问每个堆栈帧中的每个此类对象;实际上,该技术的目的是确保每个堆栈帧中只能访问一个这样的值。
答案 3 :(得分:0)
首先,你应该在问题中提到本书中的句子与Python没有明确的关系(正如jsbueno所写,一个名字只与Python中的一个对象绑定)。
无论如何,绑定到无对象的名称有点不准确。通常,名称与变量相关,与悬空指针相关的名称是该指针变量的名称。
当谈到变量范围(即使用变量的代码部分)时,一个变量名一次只能用于一个值。但是,可能存在代码的其他部分,与我们考虑该变量的部分无关。在代码的其他部分,可以使用相同的名称;但是,具有相同名称的两个变量是完全隔离的。在函数体的情况下,这也是局部变量的情况。如果语言允许递归,它必须能够创建另一个局部变量的隔离空间,即使对于同一函数的另一个调用也是如此。
在Python中,每个函数也可以访问外部变量,但更常见的是使用内部局部变量。无论何时为名称指定某个值,都会在本地空间中创建。