Python模块全局变量与__init__全局变量的区别

4

抱歉,这是一个有些困惑的Python新手问题。假设我有一个名为animals.py的模块……

globvar = 1

class dog: 
   def bark(self):
      print globvar

class cat:
   def miaow(self):
      print globvar

这与什么有区别?
class dog:
   def __init__(self):
      global globvar

   def bark(self):
      print globvar

class cat:
   def miaow(self):
      print globvar

假设我总是先实例化一个狗?
我的问题是,这两种方式有什么区别吗?在第二个例子中,是否像第一个例子一样,初始化dog会创建一个模块级的globvar,并且行为和作用域相同?
2个回答

9

global并不会创建一个新变量,它只是说明这个名称应该引用全局变量而不是本地变量。通常在函数/类等中对变量进行赋值时,都是指向本地变量。例如,考虑以下函数:

def increment(n)
  # this creates a new local m
  m = n+1
  return m

这里创建了一个新的本地变量m,即使可能已经存在全局变量m。这通常是您所希望的,因为某些函数调用不应意外修改周围作用域中的变量。如果您确实想修改全局变量而不是创建新的本地变量,则可以使用global关键字:

def increment(n)
  global increment_calls
  increment_calls += 1
  return n+1

在您的情况下,构造函数中的global不会创建任何变量,进一步尝试访问globvar将失败:

>>> import animals
>>> d = animals.dog()
>>> d.bark()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "animals.py", line 7, in bark
    print globvar
NameError: global name 'globvar' is not defined

但是,如果你在构造函数中实际分配一个值给globvar,那么当你创建一只狗时,将会创建一个模块全局变量:

class dog:
   def __init__(self):
      global globvar
      globvar = 1
...

执行:

>>> import animals
>>> d = animals.dog()
>>> d.bark()
1
>>> print animals.globvar
1

类的东西,谢谢。完美回答了问题。 - Thomas Browne

4
不,global语句只在方法或函数内分配全局变量时才起作用。因此,__init__是无关紧要的——它不会创建全局变量,因为它没有对其进行任何赋值操作。

除非先实例化一只狗,否则猫类将会返回一个错误,对吧Alex?如果我在狗的__init__中没有全局globvar语句,那么猫就会报错。但是除此之外,两者的作用域是相同的。感谢您的帮助。 - Thomas Browne
在你的第二个例子中,你总是会得到一个错误,因为你从未创建globvar。 "global"关键字不会创建全局变量。 global语句所做的是告诉Python你正在引用一个全局变量,而不是创建一个具有相同名称的新的、单独的本地变量。正如Alex所说,只有当你从方法或函数内部给全局变量赋值时才会有影响。 - hbw
@Thomas,@htw说得很对:为了使它按照你的想法工作,__init__需要对globvar进行赋值(然后如果在实例化狗之前实例化猫,则会失败)。 - Alex Martelli
感谢htw和Alex。我想我的旧Pascal / c经验(生疏!)让我相信“global globvar”声明了一个变量。这是新手Pythonista的典型错误,仍然生活在旧范式中。我认为自己已经开悟了。 - Thomas Browne

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接