- What(是什么)
- Why(为什么)
- How(怎么用)
- 定义类
- 创建对象
- 类的成员
- 实例变量
- 构造方法
- 实例方法
- 类变量
- 类方法
- 封装性
- 私有变量
- 私有方法
- 使用属性
- 继承性
- 继承
- 多继承
- 方法重写
- 多态性
- 继承与多态
- 鸭子类型测试
- 类是什么?对象又是什么?
- 首先了解下封装的概念:把乱七八糟的数据扔进列表里面,这是一种封装;把常用的代码打包成一个函数,这也是一种封装。
- 对象就是这种封装思想的进一步,把数据和代码封装在一块。它源于真实世界。
- 比如,乌龟是真实世界的一个对象,那么怎么来描述这个对象呢(乌龟)?分成两部分:
- 从静态的特征:黑色的,四条腿,5kg重,有外壳等等。
- 从动态的行为:会爬,会咬人,吃东西,睡觉等等。
- 再举个例子:
- 如在真实世界中的校园有学生和老师,学生有学号、姓名、班级等(属性),还有学习、吃饭、走路等行为(方法)。
- 如果开发一个校园管理系统,那么在构建的时候,有老师和学生等“类”;也有张三、李四作为学生类里面的个体,这就是“对象”。
- 如下图的汽车
- 这种思想,有哲学方面的考究,如柏拉图的理念论,现实世界的个体(对象)是理念(模型)的投影(类)。
- 简单来说,类是一种高级抽象,就是一种高级的数据类型,是对象的蓝图,就是用来定义你要用的对象的属性和行为的。
- 为什么要用到类与对象呢?
- 先说作用:类里面可以写实现一些功能的代码,可以减少代码的复用。
- 这种编程思想的精髓就在:封装、继承、多态,这个我们后面会说怎么应用。
- 类与对象是同时出现的,光有类,只有模型,没有对其实际操作的对象,是什么都干不了的。
- 知道了是什么,为什么,接下来就是怎么用呢?
- 语法:
- 如上面的小汽车:
- 类是模板,根据模板创建的实例,也就是“对象”。
- 如图
- 在类体中可以包含类的成员。
- 成员变量:保存类或对象的属性。(变量)
- 构造方法:一种特殊的函数,初始化类的成员变量。
- 成员方法:类中定义的函数。(方法/行动)
- 属性:对类进行封装而提供的特殊方法。
- 实例变量/方法与类变量/方法的区别:实例变量/方法属于对象,通过对象调用;类变量/方法属于类,通过类调用。
- 对象个体特有的“数据”。
- 类中的self表示当前对象,构造方法中的self参数说明了这个方法属于实例,self.age表示age属于实例,即实例成员变量。
- 用来创建和初始化实例变量。
- 第1个参数是self,后面的参数用来初始化实例变量。调用构造方法就不用传入self参数了。
- 某个实例(对象)个体特有的方法。
- 第一个参数self,绑定实例与方法,调用是不需要传入self。
- 属于类的变量,不属于单个对象。
- 如,一个银行账户的类,三个变量:账户金额、利率、账户名。利率是相同的,账户金额跟账户名是不同的。 所以利率是类变量(所有实例成员共享的),其余两个是实例变量。
- 属于类,不属于个体对象。
- 第1个参数不是self,而是类本身。
- 注意:类方法不能访问实例方法和实例变量。
- 面向对象的基本特性之一。
- 封装隐藏对象内部细节,保留有限的对外接口,使操作对象格外简单。
- 内部数据(成员变量)会被封装为“私有变量”,外部调用者只能通过方法调用。
- python默认变量是公有的,前面加__(双下划线),即变成私有变量。
- 同理,在定义方法时加上__(双下划线),即变成私有方法。
-
为了实现对象的封装,一个类中,不该有公有的成员变量,这些成员变量都应该设为私有的,然后通过公有的set和get方法访问。
class Dog(): def __init__(self, name, age, sex="雄性"): self.name = name self.__age = age self.sex = sex def run(self): print("{}在跑...".format(self.name)) # 定义get()方法,返回私有实例变量__age def get_age(self): return self.__age # 定义set()方法,通过age参数更新私有实例变量__age def set_age(self, age): self.__age = age d = Dog("球球",3) print("我们家狗{}岁了".format(d.get_age())) d.set_age(4) print("我们家狗{}岁了".format(d.get_age())) -
返回结果
-
以上,是定义了两个公有方法,访问被封装的私有成员变量的。另外一种方法如下
class Dog(): def __init__(self, name, age, sex="雄性"): self.name = name self.__age = age self.sex = sex def run(self): print("{}在跑...".format(self.name)) # # 定义get()方法,返回私有实例变量__age # def get_age(self): # return self.__age @property def age(self): return self.__age # # 定义set()方法,通过age参数更新私有实例变量__age # def set_age(self, age): # self.__age = age @age.setter def age(self, age): self.__age = age d = Dog("球球",3) print("我们家狗{}岁了".format(d.age)) d.age = 4 print("我们家狗{}岁了".format(d.age)) -
运行结果
-
本质上就是,在方法前面加上装饰器,使其成为属性,用起来类似公有变量。
- 面向对象的特征之一。
- 在现实世界里,继承关系无处不在。如猫和动物之间关系:猫是一种特殊动物,具有动物的全部特性与行为,即数据和操作。这种关系中,动物是一般类,称为“父类”,猫是特殊类,称为“子类”。
- 特殊类拥有一般类的全部数据与操作,可以称为子类继承父类。
- 在python中声明子类继承父类,只需要在定义类时,在类的后面使用一对小括号指定父类即可。
class Animal: def __init__(self, name): self.name = name def show_info(self): return "动物名字:{0}".format(self.name) def move(self): print("移动ing") # 子类定义 class Cat(Animal): def __init__(self, name, age): # 使用super()方法调用父类构造方法,初始化父类成员变量 super().__init__(name) self.age = age cat = Cat("tom",4) cat.move() print(cat.show_info()) - 显示结果
- 子类继承父类,只有那些公有的成员变量和方法,才可以继承。
- 子类调用父类构造方法,流程如下图:
- python支持一个子类继承多个父类,如果子类继承多个父类,父类中有相同的成员变量或方法,则子类优先继承左边(这个左边指的是类定义时括号中,父类参数的位置),从左到右,级别从高到低。
class Horse: def __init__(self, name): self.name = name def show_info(self): return "马的名字:{0}".format(self.name) def move(self): print("马在跑...") class Donkey: def __init__(self, name): self.name = name def show_info(self): return "驴的名字:{0}".format(self.name) def move(self): print("驴在跑...") def roll(self): print("驴在滚...") class Mule(Horse, Donkey): def __init__(self, name, age): super().__init__(name) self.age = age m = Mule("tom",10) # 继承马的run(继承时马在左边) m.move() # 继承驴的roll m.roll() # 同理,继承马的show_info print(m.show_info()) - 运行结果
- 如果子类的方法名与父类的方法名相同,子类的方法会重写父类的同名方法(也可以认为是覆盖)。
class Horse: def __init__(self, name): self.name = name def show_info(self): return "马的名字:{0}".format(self.name) def move(self): print("马在跑...") class Donkey: def __init__(self, name): self.name = name def show_info(self): return "驴的名字:{0}".format(self.name) def move(self): print("驴在跑...") def roll(self): print("驴在滚...") class Mule(Horse, Donkey): def __init__(self, name, age): super().__init__(name) self.age = age def show_info(self): return "骡的名字是:{0},{1}岁".format(self.name, self.age) m = Mule("tom",10) # 继承马的run(继承时马在左边) m.move() # 继承驴的roll m.roll() # 子类自身定义的方法 print(m.show_info()) - 运行结果
- 面向对象的基本特征之一。
- 多态指的是:对象可以表现出多种形态。如,猫,鸭,狗都属于动物,都有“叫”和“动”等行为,但是叫的方式不同,动的方式也不同。
- 在多个子类继承父类,并重写父类方法后,这些子类所创建的对象之间就是多态的。
class Animal: def speak(self): print("叫起来,啥玩意叫?") class Dog(Animal): def speak(self): print("小狗,旺。。。") class Cat(Animal): def speak(self): print("小猫咪,喵。。。") ca = Cat() do = Dog() ca.speak() do.speak() - 运行结果
- 鸭子类型测试:若看到一只鸟走路像鸭子,游泳像鸭子,叫起来也像鸭子,那么这只鸟可以被称为鸭子。
- python解释器不检查发生多态的对象是否继承了一个父类,只要它们有相同的行为(方法),它们之间就是多态的。
- 如,我们可以定义一个函数,专门用来做相同行为处理。
# 定义函数,接收所有的speak()方法对象 def start(obj): obj.speak() class Animal: def speak(self): print("叫起来,啥玩意叫?") class Dog(Animal): def speak(self): print("小狗,今年旺不旺,旺。。。") class Cat(Animal): def speak(self): print("小猫咪,别骂人呀,喵。。。") def strat(obj): obj.speak() start(Dog()) start(Cat()) - 运行结果



