在Python中的函数定义之后赋值变量

时间:2017-12-29 01:05:05

标签: python scope nested pycharm

我是Python的新手,所以我不确定函数定义之前或之后变量赋值的区别。

具体来说,第一个例子是从Lutz的书中采用的。

   def tester(start):
        print("inside tester")
        def nested(label):
            print("inside nested")
            print(label,nested.state)
            nested.state += 1
            print("done with nested")

        nested.state = start
        print("done with tester")
        return nested

    F = tester(0)
    F('spam')
    F.state
    F.state

代码的目标是在不使用nonlocal的情况下存储状态信息。

我不确定nested.state在这里的含义。我不确定,因为nested.statenested()函数(即nested.state +=1)和nested()函数内部(即nested.state = start)内使用。

我修改了上面的代码,看看Python是否接受nested()函数声明后的赋值变量,看看是否有任何与function.variable调用相关的概念(即nested.state}呼叫)。

def tester(start):
    def nested(label):
        print(label, state)
        state += 1  #replaced 'nested.state' with 'state' here
    state = start   #replaced 'nested.state' with 'state' here
    return nested

F=tester(0)
F('spam')
F('ham')

不幸的是,上面的代码会生成错误local variable 'state' referenced before assignment。这告诉我,我遗漏了一些关于function.variable的概念(即nested.state)。

有人可以帮我理解三件事:

我。为什么nested.state的代码不会生成任何错误但state会产生错误?

II。 nested.state是什么意思?如果nested.state是一种访问函数变量的机制,为什么nested()函数中的调用也使用nested.state而不是state

III。如果nested.state是一种访问函数内部变量的机制,那么当我输入 {时,为什么PyCharm无法在下拉列表中显示state {1}}

我很感激任何帮助。我研究SO,并且无法找到有关此类问题的任何解释。

3 个答案:

答案 0 :(得分:1)

第一个代码示例有效的原因是分配和引用nested函数对象属性。这里要理解的关键概念是, Python允许您将,任意属性分配给对象 - 包括函数

>>> def func(a, b):
        return a + b

>>> func(1, 2)
3
>>> func.attr = 5
>>> func.attr
5

第一个代码示例通过使用nested函数对象来存储必要的状态来利用这一事实。这与使用任何其他对象来存储状态的概念相同。然而,使用功能特别方便,因为它很容易获得。

在第二个示例中,使用了一个普通变量。因此,正常的范围规则适用,这意味着state 中定义的tester变量不是 state中引用的nested变量。因此,引发了错误。

答案 1 :(得分:0)

实际上,我认为您在Python中询问有关范围的问题,忽略了您的代码,请检查:

def scope_level_1():
    variable = 'Scope_level_1'

    def scope_level_2():
        variable = 'Scope_level_2'

        def core():
            nonlocal variable
            variable += '_TOUCHED_AND_MODIFIED_BY_CORE'
            print(variable)

        return core()

    return scope_level_2()


scope_level_1()
# 'Scope_level_2_TOUCHED_AND_MODIFIED_BY_CORE'

不要担心关键字nonlocal,将其视为声明使代码更具可读性。

答案 2 :(得分:0)

首先,请记住a += ba = a + b相同。因此,a必须存在才能进入+=

简单地说,在第一个示例中,函数nested具有一个名为state的属性(由nested.state访问)。这是一个属性,这意味着一旦你告诉nested它有一个名为state的属性(你在nested.state = start时在第9行执行此操作),它就会保留该属性。因此,当您到达nested.state时,在第一个示例中+= 存在

在第二个示例中,您在state中声明了一个名为tester的变量,在state中声明了一个名为nested的变量。 nested中的那个可以被称为potato,因为它不是同一个变量。因此,当您到达+=时,变量state不存在!