1.面向对象: 类(Class):类是抽象的模板 实例(Instance):实例是根据类创建出来的一个个具体的“对象”,每个对象具有相同的方法,但是数据可能不一样
(1)定义类: class className(object): pass 类名通常是大写的字母开头,参数是object,表示该类是从哪一个类上面继承下来的 (2)创建实例:类名+() (3)给实例变量绑定属性:实例名.属性 = 属性值 通过__init__方法,self表示实例本身,调用函数的时候不需要传递进去
class Student(object): def __init__(self,name,score): self.name = name self.score = score
2.数据封装:直接在类的内部定义访问数据的函数,用类的方法去访问这些参数
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 = Student('YJ',100)bart.print_score()
(1)数据封装的另一个好处是可以给类增加新的方法
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)) def get_grade(self): if self.score >= 90: return 'A' elif self.score >= 60: return 'B' else: return 'C'bart = Student('YJ',100)bart.get_grade()
PS:对于两个实例变量,虽然他们都是同一个类的不同实例,但是拥有的变量名称可以不一样
yj = Student('YJ',100)lp = Student('LP',101)yj.age = 24print yj.age # 24print lp.age # 报错
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))
修改之后外部已经不能去访问这两个属性
yj = Student('YJ',100);print yj.__name # 报错
PS:确保外部代码不能随意修改对象内部的代码,通过访问限制的保护,代码更加健壮
给类添加get_name和get_score方法来获取name和score
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)) def get_name(self): return self.__name def get_score(self): return self.__score
在类里面定义方法的好处是可以对参数做检查,避免传入无效的参数 添加设置score的方法
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)) def get_name(self): return self.__name def get_score(self): return self.__score def set_score(self,score): if 0 <= score <= 100: self.__score = score else: raise ValueError('bad score')
PS:在Python中,变量名是__xx__,这种是特殊变量,是可以直接访问的,不是私有变量,所以不能这样去命名 __xx这样的变量外部是可以访问的,但是一般当做私有变量,最好不要这样做
一个错误写法:
lp = Student('LP', 101) print lp.get_name() # LP lp.__name = 'new' print lp.__name # new
PS:表面上看外部代码成功的修改了name,实际上这个__name变量和class内部的__name变量不是一个变量 class内部的变量已经被Python解释器自动改成了_类名_name,而外部代码只是给lp这个实例对象新增加了一个__name变量
print lp.get_name() # LP
4.继承和多态 继承:定义一个class的时候,可以从某个现有的class继承,新的class被称为子类(Subclass),被继承的class被称为基类(Base class)、父类()、超类(Super class) (1).继承的一个好处就是子类获得了父类的全部功能
class Animal(object): def run(self): print('Animal is running...')class Dog(Animal): passclass Cat(Animal): passdog = Dog()dog.run()cat = Cat()cat.run()
(2).继承的第二个好处:多态
class Animal(object): def run(self): print('Animal is running...')class Dog(Animal): def run(self): # 覆盖了父类的run() print('Dog is running...') def eat(self): print('Cat is running...')class Cat(Animal): def run(self): # 覆盖了父类的run() print('Cat is running...')dog = Dog()dog.run()cat = Cat()cat.run()
(3)定义一个class的时候,实际上就定义了一种数据类型 用isinstance()判断一个变量是否是某个类型
a = list() # a是list类型isinstance(a, list)
如果一个实例对象的数据原型是某个子类,那他的数据类型也可以被看做是父类
dog = Dog()isinstance(dog, Animal)
但是反过来不可以
animal = Animal()instance(animal, Dog)
(4)一个函数可以接受animal实例
class Animal(object): def run(self): print('Animal is running...')class Dog(Animal): def run(self): # 覆盖了父类的run() print('Dog is running...') def eat(self): print('Cat is running...')class Cat(Animal): def run(self): # 覆盖了父类的run() print('Cat is running...')class Tortoise(Animal): def run(self): print("Tortoise is running slowly...")def run_twice(insObj): animal.run() animal.run()run_twice(Animal())
PS:多态:传入的任意类型,只要是Animal类或者子类,就会自动调用实际类型的run() "开闭"原则: 对扩展开放:允许新增Animal子类; 对修改封闭:不需要修改依赖Animal类型的run_twice()等函数。
(5).静态语言:如果需要传入Animal类型,则传入的对象必须是Animal类型 动态语言:不一定需要传入Animal类型,只需要保证传入的对象有一个run()