有两种类型的域—— 类的变量和对象的变量,它们根据是类还是对象拥有这个变量而区分。
类的变量由一个类的所有对象(实例)共享使用。只有一个类变量的拷贝,所以当某个对象对类的变量做了改动的时候,这个改动会反映到所有其他的实例上。 对象的变量由类的每个对象/实例拥有。因此每个对象有自己对这个域的一份拷贝,即它们不是共享的,在同一个类的不同实例中,虽然对象的变量有相同的名称,但是是互不相关的。通过一个例子会使这个易于理解。

class Robot: 

     population = 0 

     def __init__(self,name): 

         self.name = name 

         print('(Initialize {0})'.format(self.name)) 

         Robot.population += 1 

     def __del__(self): 

         print('{0} is being destroyed!'.format(self.name)) 

         Robot.population -= 1 

         if Robot.population == 0: 

              print('{0} was the last one.'.format(self.name)) 

         else: 

              print('There are still {0:d} robots working.'.format(Robot.population)) 

     def sayHi(self): 

         print('Greetings, my master call me {0}.'.format(self.name)) 

     def howMany(): 

         print('We have {0:d} robots.'.format(Robot.population)) 

     howMany = staticmethod(howMany) 

 droid1 = Robot('R2-D2') 

 droid1.sayHi() 

 Robot.howMany() 

 droid2 = Robot('C-3P0') 

 droid2.sayHi() 

 Robot.howMany() 

 print("\nRobots can do some work here.\n") 

 print("Robots have finished their work. So let's destroy them.") 


 del droid1 

 del droid2 
Robot.howMany()

输出:


(Initialize R2-D2)


Greetings, my master call me R2-D2.


We have 1 robots.


(Initialize C-3P0)


Greetings, my master call me C-3P0.


We have 2 robots.


Robots can do some work here.


Robots have finished their work. So let's destroy them.


R2-D2 is being destroyed!


There are still 1 robots working.


C-3P0 is being destroyed!


C-3P0 was the last one.


We have 0 robots.




这是一个很长的例子,但有助于说明类和对象变量的本质。这儿,population 属于Robot 类,因此是一个类变量。name 变量属于对象(用self 给其赋值),因此是一个对象变量。因此,我们使用Robot.population 来引用population 类变量,而不是用self.population来引用。我们在该对象的方法中用self.name 来引用对象变量name。记住类和对象变量之间这个简单的差别。也要注意一个与类变量有相同名字的对象变量会隐藏类变量!


howMany 实际上是属于类而不是对象的方法。这意味着我们或者可以定义类方法或者可以定义静态方法,这取决于我们是否需要知道我们是那个类的部分。既然我们不需要这样的信息,就需要将其定义为静态方法。


我们也能用如下的方式来实现。


@staticmethod 

 def howMany(): 

    print('We have {0:d} robots.'.format(Robot.population))



这种方法可以想成是调用显式方法的简便方法,正像这个例子中看到的那样。注意到__init__ 方法用一个名字来初始化Robot 实例。在该方法中,给population自增1 来表明又添加了一个robot。也主要到self.name 的值对每个对象而言是不同的,这也说明了对象变量的本质。


记住,你必须仅用self 来引用同一对象的变量和方法。这叫属性参考。在这个程序中,也看到了和方法一样在类中使用docstrings。我们可以在运行的时候使用Robot.__doc__ 来获得类的docstring,用Robot.sayHi.__doc__ 来获得方法的docstring。就如同__init__ 方法一样,还有一个特殊的方法__del__,它在对象消逝的时候被调用。对象消逝即对象不再被使用,它所占用的内存将返回给系统作它用。在这个方法里面,我们只是简单地把Person.population 减1。当对象不再被使用时,__del__ 方法运行,但是很难保证这个方法究竟在什么时候运行。如果你想要指明它的运行,你就得使用del 语句,就如同我们在以前的例子中使用的那样。