解释Python变量作用域

8 投票
3 回答
1235 浏览
提问于 2025-04-15 21:50

我正在自学Python,并把一些示例代码翻译成这样:

class Student(object):
    def __init__( self, name, a,b,c ):
        self.name = name
        self.a = a
        self.b = b
        self.c = c

    def average(self):
        return ( a+b+c ) / 3.0 

这基本上就是我想要的类定义。

然后在主方法里,我创建了一个实例,并把它叫做 a

if __name__ == "__main__" :
    a = Student( "Oscar", 10, 10, 10 )

这让我发现,在 main 中声明的变量 a 可以在 average 方法里使用,但为了让这个方法正常工作,我必须输入 self.a + self.b + self.c

这样做的原因是什么呢?

3 个回答

-1

所有的实例变量都应该用self来调用。

2

有几个原因,但最主要的一个来自Python的哲学:“显式优于隐式。” 在像C++这样的语言中,类的方法总是有一个隐含的参数this,每次调用这个方法时都会被放到栈上。在这种情况下,如果一个实例变量b和一个全局变量b同时存在,用户可能会只提到b,却不知道自己指的是哪个。这就是为什么Python要求你明确你的作用域,以避免混淆。

当然,还有其他原因。例如,我可以在类外定义一个函数,然后在运行时把它附加到一个类上。比如:

def log(self):
    print "some library function requires all objects to have a log method"
    print "unfortunately we're using the Student class, which doesn't have one"
    print "this class is defined in a separate library, so we can't add the method"
    print "fortunately, we can just add the method dynamically at runtime"

Student.log = log

在这里,self是显式的,这让我们可以很简单地在类外定义一个函数,然后把它附加到那个类上。我并不是经常这样做,但当我需要的时候,这非常有用。

这里还有一个更复杂的例子;假设我们想在一个类里面定义另一个类,比如为了单元测试的目的:

class SomeUnitTests(TestCase):
    def test_something(self):
        class SomeMockObject(SomeActualObject):
            def foo(self2):
                self.assertEqual(self2.x, SOME_CONSTANT)

        some_lib.do_something_with(SomeMockObject)

在这里,显式的self(我们可以叫它任何名字,不一定非得是self)让我们能够区分内外两个类的self。同样,这不是我经常做的事情,但当我这样做时,它非常有用。

10

变量名(比如 abc)总是分为局部和全局两种作用域(除了嵌套函数,这里不讨论)。这样做的原因是,如果再增加更多的作用域,会让事情变得复杂。例如,在你的 self.a = a 这行代码中,如果变量名 a 被解释为你想要的意思(也就是 self.a),那么这个赋值操作就没有意义了(相当于把自己赋值给自己),这样就需要更多复杂的规则来处理。

所以,当你想要的东西和变量名的简单、直接、优化的行为不同时,使用带有前缀的名称(比如 self.a)是最简单的方法——这样做完全可行,没有复杂的规则,而且可以让编译器有效地优化代码(因为变量名的作用域总是由代码的结构决定,而不是依赖于环境中动态变化的特性)。所以,除了可能对其他语言中更复杂的作用域规则有些怀念,实际上没有理由去复杂化变量名的语义。

撰写回答