本章讲的比较好的是廖雪峰的博客 [面向对象编程] (https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431864715651c99511036d884cf1b399e65ae0d27f7e000)
对象(类)包括属性和方法,属性即对象的特征,而方法是对象的行为或者动作,但方法和属性并不是一个完整的对象,这些定义为类(class),需要使用类来创建一个真正的对象,这个对象就叫作这个类的一个实例(Instance), 也叫实例对象(Instance Objects)。
class Student(object):
def __init__(self, name, score):
self.name=name
self.score=score
def print_score(self):
print('%s:%s' %(self.name, self.score))
`#类名约定用大写字母开头,函数用小写字母开头,这样容易区分;调用对象里的方法,使用点操作符(.)即可.`
`#这里Student这种数据类型应该被视为一个对象,这个对象拥有name和score这两个属性(Property).如果要打印一个学生的成绩,首先必须创建出这个学生对应的对象,然后,给对象发一个print_score消息,让对象自己把自己的数据打印出来。`
给对象发消息实际上就是调用对象对应的关联函数,即对象的方法
bart=Student(‘Bart Simpson’, 59)
lisa=Student(‘Lisa Simpson’, 87)
bart.print_score()
lisa.print_score()
**1. 对象创建过程详解**
` class Student(object):
pass`
class后面紧接着是类名,即Student,类名通常是大写开头的单词,紧接着是(object),表示该类是从哪个类继承下来的,如果没有继承类,就使用object类。
定义好Student类,就可以根据Student类创建Student的实例,创建实例是通过类名加()实现:
bart=Student()
bart-> <main.Student object at 0x10a67a590>
Student-> <class’main.Student’>
可见,变量bart指向的就是Student的实例,后面的0x10a67a59是内存地址,每个object的地址都不一样,而Student本身则是一个类。
可以自由地给一个实例变量绑定属性,比如,给实例bart绑定一个name属性:
bart.name=‘Bart Simpson’
bart.name->‘Bart Simpson’
由于类可以起到模板的作用,因此,可以创建实例的时候,把一些我们认为必须绑定的属性强制填写进去。通过定义一个特殊的__init__方法,在创建实例的时候,就把name, score等属性绑上去:
class Student(object):
def init(self, name, score):
self.name=name
self.score=score
#特殊方法"init"前后分别有两个下划线!!
`__init__`方法的第一个参数永远是self,表示创建的实例本身,因此,在`__init__`方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。
有了`__init__`方法,在创建实例的时候,就不能传入空的参数,必须传入与`__init__`方法匹配 的参数,但self不需要传,Python解释器自己会把实例变量传进去:
bart=Student(‘Bart Simpson’, 59)
bart.name->‘Bart Simpson’
bart.score-> 59
#与普通函数相比,在类中定义的函数主要不同就是第一个参数永远是实例变量self,并且,调用时不用传递该参数。
2. 数据封装
面向对象编程的一个重要的特点就是数据封装。如上面Student类中,每个实例就拥有了各自的name和score这些数据,我们除了可以通过函数访问这些数据,还可以再Student内部直接定义访问数据函数,这样就可以将“数据”封装起来了。这些封装数据的函数是和Student类本身是关联的,我们称之为方法:
class Student(object):
def init(self, name, score):
self.name=name
self.score=score
def print_score(self):
print('%s: %s' %(self.name, self.score))
同时,封装还可用于给Student类增加新的方法:如get_grade:
class Student(object):
…
def get_grade(self):
if self.score>=90:
return ‘A’
elif self.score>=60:
return ‘B’
else:
return ‘C’
3. 访问限制
如果要让内部的属性不让外部访问,可在属性名称前加两个下划线___,即在实例变量中,如果以两个下划线开头,表示其变为一个私有变量,只有内部可以访问,外部不能访问:
class Student(object):
def init(self, name, score):
self.__name=name
self.__score=score
def print_score(self):
print(’%s: %s’ %(self.__name, self__score))
#此时如果再外部环境之间输入bart.__name()显示报错,没有权限访问。如果又要使得外部可以访问私有变量,则可以增加get_name和get_score方法:
class Student(object):
…
def get_name(self):
return self.__name
def get_score(self):
return self._score
值得注意的是:在Python中,变量名类似__xxx__的,即以双下划线开头和结尾的,这些是特殊变量,是可以直接访问的,并不是private变量。
4. 继承
当定义一个class时,可以从某个现有的class继承,新的class称为子类(subclass),而被继承的class称为基类、父类或超类。
class Animal (object):
def run(self):
print(‘Animal is running’)
当我们需要编写dog和cat类时,就可以直接从Animal类继承
class Dog (Animal):
pass
class Cat(Animal):
pass
继承可以使子类获得父类的全部功能。
dog=Dog( )
dog.run( )->Animal is running
但继承的子类也可以自己添加其他方法,如Dog类:
class Dog (Animal):
def run(self):
print(‘Dog is running…’)
def eat(self):
print('Eating meat...')
此外,Python还支持多重继承,即可同时继承多个父类的属性和方法:
语法: class类名(父类1, 父类2, 父类3,...)
class Base1:
def foo1(self):
print(‘我是foo1,我在Base1中…’)
clase Base2:
def foo2(self):
print(‘我是foo2,我在Base2中…’)
class C(Base1, Base2):
pass
4. 多态 :当子类和父类都存在相同的run( )方法时,我们说,子类的run( )覆盖了父类的run( ),在代码运行的时候,总会调用子类的run().这样我们就获得了继承的另一个好处:多态。
isinstance( )可以判断一个变量是否是某个类型 ,返回值为布尔值。 isinstance(a, list) ->True
类型可以随着多次继承而传递,就如家系图谱一样
`多态的好处就是,当我们需要传入Dog、Cat、Tortoise……时,我们只需要接收Animal类型就可以了,因为Dog、Cat、Tortoise……都是Animal类型,然后,按照Animal类型进行操作即可。由于Animal类型有run()方法,因此,传入的任意类型,只要是Animal类或者子类,就会自动调用实际类型的run()方法,这就是多态的意思:
对于一个变量,我们只需要知道它是Animal类型,无需确切地知道它的子类型,就可以放心地调用run()方法,而具体调用的run()方法是作用在Animal、Dog、Cat还是Tortoise对象上,由运行时该对象的确切类型决定,这就是多态真正的威力:调用方只管调用,不管细节,而当我们新增一种Animal的子类时,只要确保run()方法编写正确,不用管原来的代码是如何调用的。这就是著名的“开闭”原则:`
5. 获取对象信息
6. 组合机制:当使用继承不能解决的问题,可以考虑用组合更为方便:
class Turtle:
def init(self, x):
self.num=x
class Fish:
def init(self, y):
self.num=y
class Pool:
def init(self, x, y):
self.turtle=Turtle(x)
self.fish=Fish(y)
def print_num(self):
print(‘水池里总共有乌龟%d只,小鱼%d条!’ %(self.turtle.num, self.fish.num))