解释Python变量作用域
我正在自学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 个回答
所有的实例变量都应该用self来调用。
有几个原因,但最主要的一个来自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
。同样,这不是我经常做的事情,但当我这样做时,它非常有用。
变量名(比如 a
、b
、c
)总是分为局部和全局两种作用域(除了嵌套函数,这里不讨论)。这样做的原因是,如果再增加更多的作用域,会让事情变得复杂。例如,在你的 self.a = a
这行代码中,如果变量名 a
被解释为你想要的意思(也就是 self.a
),那么这个赋值操作就没有意义了(相当于把自己赋值给自己),这样就需要更多复杂的规则来处理。
所以,当你想要的东西和变量名的简单、直接、优化的行为不同时,使用带有前缀的名称(比如 self.a
)是最简单的方法——这样做完全可行,没有复杂的规则,而且可以让编译器有效地优化代码(因为变量名的作用域总是由代码的结构决定,而不是依赖于环境中动态变化的特性)。所以,除了可能对其他语言中更复杂的作用域规则有些怀念,实际上没有理由去复杂化变量名的语义。