番茄五 -面向对象编程
问题,类的 init 方法是必须的吗?
类和实例
类名通常是大写开头的单词, 紧接着是(object),表示该类是从哪个类继承下来的
class Student(object):
pass
bart = Student()
定义一个特殊的init方法,在创建实例的时候,就把name,score等属性绑上去:
class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
数据封装--这些函数,就是类的方法!
类的实例--就是 对象,通过函数来访问这些数据,比如打印一个学生的成绩
def print_score(std):
print('%s: %s' % (std.name, std.score))
print_score(bart)
类是创建实例的模板,而实例则是一个一个具体的对象
方法就是与实例绑定的函数,和普通函数不同,方法可以直接访问实例的数据;
访问限制
如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线,在Python中,实例的变量名如果以开头,就变成了一个私有变量(private)
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))
完整的get和set方法:
class Student(object):
def get_name(self):
return self.__name
def get_score(self):
return self.__score
def set_score(self, score):
self.__score = score
特殊命名 xxx
变量名类似xxx的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以,不能用name、score这样的变量名。
看起来是私有变量 _name
看到以一个下划线开头的实例变量名,比如_name,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”。
最后需要注意的是:__name
bart = Student('Bart Simpson', 98)
bart.get_name()
bart.__name = 'New Name'
bart.__name
表面上看,外部代码“成功”地设置了__name变量,但实际上这个__name变量和class内部的__name变量不是一个变量!内部的__name变量已经被Python解释器自动改成了_Student__name,而外部代码给bart新增了一个__name变量.
继承和多态
你会发现,新增一个Animal的子类,不必对run_twice()做任何修改,实际上,任何依赖Animal作为参数的函数或者方法都可以不加修改地正常运行,原因就在于多态。
多态的好处就是,当我们需要传入Dog、Cat、Tortoise……时,我们只需要接收Animal类型就可以了,因为Dog、Cat、Tortoise……都是Animal类型,然后,按照Animal类型进行操作即可。由于Animal类型有run()方法,因此,传入的任意类型,只要是Animal类或者子类,就会自动调用实际类型的run()方法,这就是多态的意思:
以下用一个完整里的例子来说明:(一定要注意空格啊!!!)
class Animal(object):
def run(self):
print('Animal is running...')
class Dog(Animal):
def run(self):
print('Dog is running...')
def eat(self):
print('Eating meat...')
class Cat(Animal):
def run(self):
print('Cat is running...')
dog = Dog()
dog.run()
cat = Cat()
cat.run()
单独定义一个独立的函数:
def run_twice(animal):
animal.run()
animal.run()
这就是多态啊!!
下面就是动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。
class Timer(object):
def run(self):
print('Start...')
tim=Timer()
run_twice(tim)
继承可以把父类的所有功能都直接拿过来,这样就不必重零做起,子类只需要新增自己特有的方法,也可以把父类不适合的方法覆盖重写。
震惊啊!
def run2(d):
d.run()
d.run()
然后run2(d) 也是可以的!!!
注意object是小写!
再测试 了一次。
isinstance()判断的是一个对象是否是该类型本身,或者位于该类型的父继承链上。
isinstance(cat,object)
True
isinstance(cat,Animal)
True
isinstance(cat,Cat)
True