Python - 面向对象(五)
对象可以使用普通的属于对象的变量存储数据。属于一个对象或类的变量被称为域。对象也可以使用属于类的函数来具有功能。这样的函数被称为类的方法。这些术语帮助我们把它们与孤立的函数和变量区分开来。域和方法可以合称为类的属性。
域有两种类型—— 属于每个实例/类的对象或属于类本身。它们分别被称为实例变量和类变量。类使用class 关键字创建。类的域和方法被列在一个缩进块中。
self
类的方法与普通的函数只有一个特别的区别—— 它们必须有一个额外的第一个参数名称,但是在调用这个方法的时候你不为这个参数赋值,Python 会提供这个值。这个特别的变量指对象本身,按照惯例它的名称是self。
虽然你可以给这个参数任何名称,但是强烈建议你使用self 这个名称—— 其他名称都是不赞成你使用的。使用一个标准的名称有很多优点—— 你的程序读者可以迅速识别它,如果使用self 的话,还有些IDE(集成开发环境)也可以帮助你。
假如你有一个类称为MyClass 和这个类的一个实例MyObject。当你调用这个对象的方法MyObject.method(arg1, arg2) 的时候,这会由Python 自动转为MyClass.method(MyObject, arg1, arg2)—— 这就是self 的原理了。
类
一个尽可能简单的类如下面这个例子所示。
class Person:
pass # An empty block
p = Person()
print(p)
对象的方法
我们已经讨论了类/对象可以拥有像函数一样的方法,这些方法与函数的区别只是一个额外的self 变量。
class Person:
def sayHi(self):
print('Hello, how are you?')
p = Person()
p.sayHi()
# This short example can also be written as Person().sayHi()
__init__ 方法
这个方法可以用来对你的对象做一些你希望的初始化。注意,这个名称的开始和结尾都是双下划线。
class Person:
def __init__(self, name):
self.name = name
def sayHi(self):
print('Hello, my name is', self.name)
p = Person('Swaroop')
p.sayHi()
类和对象变量
有两种类型的域—— 类的变量和对象的变量,它们根据是类还是对象拥有这个变量而区分。
类的变量由一个类的所有对象(实例)共享使用。只有一个类变量的拷贝,所以当某个对象对类的变量做了改动的时候,这个改动会反映到所有其他的实例上。对象的变量由类的每个对象/实例拥有。因此每个对象有自己对这个域的一份拷贝,即它们不是共享的,在同一个类的不同实例中,虽然对象的变量有相同的名称,但是是互不相关的。
class Robot:
'''Represents a robot, with a name.'''
#A class variable, counting the number of robots
population = 0
def __init__(self,name):
'''Initializes the data.'''
self.name = name
print('(Initialize {0})'.format(self.name))
#When this person is created, the robot
# adds to the population
Robot.population += 1
def __del__(self):
'''I am dying.'''
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):
'''Greeting by the robot.
Yeah, they can do that.'''
print('Greetings, my master call me {0}.'.format(self.name)
)
def howMany():
'''Prints the current population.'''
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()
一个与类变量有相同名字的对象变量会隐藏类变量!
我们也能用如下的方式来定义静态方法
@staticmethod
def howMany():
'''Prints the current population.'''
print('We have {0:d} robots.'.format(Robot.population))
Python 中所有的类成员(包括数据成员)都是公共的,所有的方法都是有效的。
只有一个例外:如果你使用的数据成员名称以双下划线前缀比如_privatevar,Python 的名称管理体系会有效地把它作为私有变量。
这样就有一个惯例,如果某个变量只想在类或对象中使用,就应该以单下划线前缀。而其他的名称都将作为公共的,可以被其他类/对象使用。记住这只是一个惯例,并不是Python 所要求的(与双下划线前缀不同)。
继承
class SchoolMember:
'''Represent any school member.'''
def __init__(self,name,age):
self.name = name
self.age = age
print('(Initialize SchoolMember:{0})'.format(self.name))
def tell(self):
'''Tell my details.'''
print('Name:"{0}" Age:"{1}"'.format(self.name,self.age),end='')
class Teacher(SchoolMember):
'''Repressent a teacher.'''
def __init__(self,name,age,salary):
SchoolMember.__init__(self,name,age)
self.salary = salary
print('(Initialized Teacher:{0})'.format(self.name))
def tell(self):
SchoolMember.tell(self)
print('Salary:"{0:d}"'.format(self.salary))
class Student(SchoolMember):
'''Represents a student'''
def __init__(self,name,age,marks):
SchoolMember.__init__(self,name,age)
self.marks = marks
print('(Initialized Student:{0})'.format(self.name))
def tell(self):
SchoolMember.tell(self)
print('Marks:"{0:d}"'.format(self.marks))
t = Teacher('Mrs.Shrividya',30,30000)
s = Student('Swaroop',25,75)
print() #pirnts a blank line
members = [t,s]
for member in members:
member.tell() # work for both Teacher and Students