何为面向对象: 就是一种编程思维.
面向对象(ObjectOriented)的三个基本特征是: 封装(Encapsulation),继承(Inheritance)和多态(Polymorphism)
Retrospection
类: 类是对一系列具有相同特征
和行为
的事物的统称,是一个抽象的概念
,不是真实存在的事物.
定义方式是class 类名(Object)
- 特征即是属性
- 行为即是方法
对象: 对象是类创建出来的真实存在的事物,对象又名实例, 创建对象的过程也叫实例化对象。
Q:为什么定义(父)类需要在括号中写Object
A: 因为Python中,所有类默认继承object类(顶级类或者基类),其他子类叫做派生类
Q:定义类中的方法比如: def wash(self)其中的self是什么意思呢?
A: self指的是调用该函数的对象
Tips
Demo
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Washer(): def wash(self): print("我会洗衣服") print(self)
haier1 = Washer()
print(haier1)
haier1.wash()
|
添加和获取对象属性
添加和获取对象的属性
- 添加对象的属性
- 可以在类外面添加属性,要先实例化(创建)对象后再添加属性
- 可以在类外面获取对象的属性
- 获取方式为: print(f”{对象名.属性}”)
- 可以在类里面获取对象属性
- 获取方式为: print(f”{对象名.属性}”)
Demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Waher(object): def print_info(self): print(f"宽度{self.width},高度{self.height}")
haier = Waher()
haier.height = 100 haier.width = 50
print(f'haier洗衣机的宽度是{haier.width}') print(f'haier洗衣机的高度是{haier.height}')
haier.print_info()
|
类外面添加对象属性
在类外边创建(实例化)对象, 然后给对象的属性赋值,
1 2 3
| haier.height = 100 haier.width = 50
|
类外面获取对象属性
在类外边创建(实例化)对象, 然后给对象的属性赋值,最后在类外面获取对象的属性,详见上面的Demo
1 2 3
| print(f'haier洗衣机的宽度是{haier.width}') print(f'haier洗衣机的高度是{haier.height}')
|
类里面获取对象属性
1 2
| print(f"宽度{self.width},高度{self.height}")
|
魔法方法
__xx__()
的函数叫做魔法方法,指的是具有特殊功能的函数
这里介绍的方法是: __init__()方法
,带参数的__init__()方法
,__str__()方法
,__del__()方法
Init方法
这个方法就是说,在实例化对象之后,不需要对每一个具体的对象赋予不同的参数(高,宽),可以定义一个通用的参数.
就向工厂那样,生产的产品的规格都是一样的(对,我没在说设计模式)
Demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Washer(): def __init__(self): self.width = 50 self.height = 100
def print_info(self): print(f"洗衣机的高度是{self.height},洗衣机的宽度是{self.width}")
haier = Washer() print(haier.height,haier.width) haier.print_info()
|
带参数的__init__()方法
一个类可以创建多个对象,需要对不同的对象设置不同的初始化属性
就可以在实例化(创建)对象的时候指定对象的参数.
Demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Washer(): def __init__(self, width, height): self.width = width self.height = height def print_info(self): print(f"洗衣机的高度是{self.height}宽度是{self.width}")
haier = Washer(50, 100)
haier.print_info()
|
str()方法
Demo
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Washer(): def __init__(self, width, height): self.width = width self.height = height def __str__(self): return f"这是haier洗衣机的说明书: 高度{self.height} 宽度{self.width}"
haier = Washer(50, 100)
print(haier)
|
del()方法
当删除对象时,python解释器也会默认调用__del__()
方法
1 2 3 4 5 6 7 8 9 10
| class Washer(): def __init__(self, width, height): self.width = width self.height = height def __del__(self): print(f"{self}方法已经删除")
haier = Washer(50, 100)
del haier
|
两个案例
案例一: 烤地瓜
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| class SweetPotato(): def __init__(self): self.cook_time = 0 self.cook_static = '生的' self.condiments = []
def cook(self, time): self.cook_time += time if 0 <= self.cook_time < 3: self.cook_static = '生的' elif 3 <= self.cook_time < 5: self.cook_static = '半生不熟' elif 5 <= self.cook_time < 8: self.cook_static = '熟了' elif self.cook_time >= 8: self.cook_static = '烤糊了'
def __str__(self): return f"这个地瓜烤了{self.cook_time}分钟,状态是{self.cook_static},添加的调料有{self.condiments}"
def add_condiment(self,condiments1,condiments2): self.condiments.append(condiments1) self.condiments.append(condiments2)
potato = SweetPotato()
potato.cook(2) potato.add_condiment("酱油", "辣椒面") print(potato)
|
案例二: 搬家具
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| class Furniture(): def __init__(self, name, area): self.name = name self.area = area
class House(): def __init__(self, location, area): self.location = location self.area = area self.free_area = area self.furniture = [] def __str__(self): return f"房子的地理位置为{self.location},占地面积为{self.area},剩余面积为{self.free_area},家具列表为{self.furniture}"
def add_furniture(self, item): if self.free_area > item.area: self.furniture.append(item.name) self.free_area -= item.area else: print("家具太大,剩余面积不足,无法容纳!")
bed = Furniture('双人床', 6) home = House('北京', 1200)
print(home)
home.add_furniture(bed)
print(home)
|
继承
继承: 即子类默认继承父类的所有属性和方法.
继承的作用: 提高代码的复用率, 减少重复代码的书写
.
Demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class A(object): def __init__(self): self.num = 1 def info_print(self): print(self.num)
class B(A): pass
result = B()
result.info_print()
|
单继承
简单来说, 就是一个子类继承一个父类.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Master(object): def __init__(self): self.kongfu = '古法煎饼果子配方' def make_cake(self): print(f"使用{self.kongfu}制作煎饼果子!")
class Prentice(Master): pass
Prentice1 = Prentice()
print(Prentice1.kongfu)
Prentice1.make_cake()
|
多继承
简单来说: 就是一个子类同时继承多个父类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class Master(object): def __init__(self): self.kongfu = '古法煎饼果子配方'
def make_cake(self): print(f"运用{self.kongfu}制作煎饼果子!")
class School(object): def __init__(self): self.kongfu = "黑马煎饼果子配方"
def make_cake(self): print(f"使用{self.kongfu}制作煎饼果子!")
class Prentice(School,Master): pass
xiaowei = Prentice()
xiaowei.make_cake()
|
子类重写父类同名方法和属性
就是子类继承了父类的所有方法,此时父类具有某种方法,子类自然也具有某种方法.
但是如果子类在调用该方法时,不想执行结果和父类方法同样的效果就需要重写父类中的成员方法.
Tips: 子类和父类具有同名属性和方法,默认使用子类的同名属性和方法。
重写的方式:
- def make_cake(self): 这里是跟父类同样的方法名.
- 后续写跟父类的方法不同的代码逻辑
子类重写父类方法后还想调用父类的方法
当在子类中重写父类方法后还想使用父类同名的方法时, 可以使用 父类名.父类方法()
来执行.
但是由于父类名.父类方法() 这种方式会导致一个问题: 就是当父类名改变的时候会出现大量的代码需要修改.
在下面的标题中会用super来解决这个问题.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| class Master(object): def __init__(self): self.kongfu = '古法煎饼果子配方' def make_cake(self): print(f"使用{self.kongfu}制作煎饼果子!")
class School(object): def __init__(self): self.kongfu = '黑马煎饼果子配方' def make_cake(self): print(f"使用{self.kongfu}制作煎饼果子!")
class Prentice(School, Master): def __init__(self): self.kongfu = '独创煎饼果子配方' def make_cake(self): print(f"运用{self.kongfu}制作煎饼果子!") def make_master_cake(self): Master.__init__(self) Master.make_cake(self) def make_school_cake(self): School.__init__(self) School.make_cake(self)
prentice = Prentice() prentice.make_cake()
prentice.make_master_cake() prentice.make_school_cake()
|
super 调用父类的方法
调用父类的方法可以使用父类.父类方法名这种方式,但是父类名可能会变,可以通过super()方法来解决.
下面代码的逻辑就是: School子类继承Master父类,然后通过super方法调用父类中的同名方法(当然已经重写过父类中的方法), 写super的好处是: 如果父类修改名称的话则会更改很多东西.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| class Master(object): def __init__(self): self.kongfu = '古法煎饼果子配方' def make_cake(self): print(f"运用{self.kongfu}制作煎饼果子!")
class School(Master): def __init__(self): super().__init__() self.kongfu = "黑马煎饼果子配方" def make_cake(self): print(f"运用{self.kongfu}制作煎饼果子!") super().__init__() super().make_cake()
class Prentice(School): def __init__(self): self.kongfu = '独创煎饼果子配方' def make_cake(self): print(f"运用{self.kongfu}制作煎饼果子!") def make_master_cake(self): Master.__init__(self) Master.make_cake(self) def make_school_cake(self): School.__init__(self) School.make_cake(self) def make_old_cake(self):
super().__init__() super().make_cake()
prentice = Prentice()
prentice.make_old_cake()
|
多层继承
直接继承到父类的孙子辈,甚至更往后
有两个父类A,B,同时C继承了A,B,然后D又继承了C这样的关系就叫做多层继承
当有多层继承发生时,无法确定具体的执行方法时,可以使用__mro__来确
越往后的类越是父类.(辈分更大)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| class Master(object): def __init__(self): self.kongfu = '古法煎饼果子配方'
def make_cake(self): print(f"运用{self.kongfu}制作煎饼果子")
class School(object): def __init__(self): self.kongfu = '黑马煎饼果子配方' def make_cake(self): print(f"运用{self.kongfu}制作煎饼果子")
class Prentice(School, Master): def __init__(self): self.kongfu = '独创煎饼果子配方' def make_cake(self): print(f"运用{self.kongfu}制作煎饼果子") def make_master_cake(self): Master.__init__(self) Master.make_cake(self) def make_school_cake(self): School.__init__(self) School.make_cake(self)
class GrandChild(Prentice): pass
print(GrandChild.__mro__)
grandchild = GrandChild()
grandchild.make_cake()
grandchild.make_master_cake() grandchild.make_school_cake()
|
多层继承 – 私有权限
类中的某些私有成员属性和成员方法是不能被继承的
- 子类无法访问继承父类的私有属性和私有方法
- 对象不能访问私有属性和私有方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| class Master(object): def __init__(self): self.kongfu = '古法煎饼果子配方' def make_cake(self): print(f"运用{self.kongfu}制作煎饼果子!")
class School(object): def __init__(self): self.kongfu = '黑马煎饼果子配方' def make_cake(self): print(f"使用{self.kongfu}制作煎饼果子")
class Prentice(School, Master): def __init__(self): self.kongfu = '独创煎饼果子配方' self.__money = 200000 def __info_print(self): print(self.kongfu) print(self.__money) def make_cake(self): self.__init__() print(f"运用{self.kongfu}制作煎饼果子") def make_master_cake(self): Master.__init__(self) Master.make_cake(self) def make_school_cake(self): School.__init__(self) School.make_cake(self)
class GrandChild(): pass
tusun = Prentice()
|
获取和修改私有属性值
既然类创建的对象不能被调用(访问)私有属性和私有方法,而且子类无法访问继承父类的私有成员属性和成员方法.
那么该怎么获取或(修改)这些私有的属性和方法呢?
- 一般定义函数名get_xx用来获取私有属性
- 定义set_xx用来修改私有属性值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| class Master(object): def __init__(self): self.kongfu = '古法煎饼果子配方' def make_cake(self): print(f"运用{self.kongfu}制作煎饼果子") class School(object): def __init__(self): self.kongfu = '黑马煎饼果子配方' def make_cake(self): print(f"运用{self.kongfu}制作煎饼果子") class Prentice(School, Master): def __init__(self): self.kongfu = '独创煎饼果子配方' self.__money = 200000 def get_money(self): return self.__money def set_money(self): self.__money = 500 def info_print(self): print(self.kongfu) print(self.__money) def make_cake(self): self.__init__() print(f"运用{self.kongfu}制作煎饼果子") def make_master_cake(self): Master.__init__(self) Master.make_cake(self)
|
多态
什么事多态: 个人理解, 多态的外在体现, 同一句代码却执行出不同的结果
多态的前提:
1,有继承关系
2,有方法重写
3,父类引用指向子类对象
理解多态最重要的一点就是: 定义的函数参数为一个大范围的类(比如Animal类对象),
1
| def feed_animal(animal: Animal):
|
但是由于多态,你可以传递一个小范围的类对象.(比如Cat c猫类对象, Dog d狗类对象)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| """ 多态的前提: 1,有继承关系 2,有方法重写 3,父类引用指向子类对象 """
class Animal(object): def eat(self): print("动物吃饭")
class Cat(Animal): def eat(self): print("猫吃鱼")
class Dog(Animal): def eat(self): print("狗吃肉")
def feed_animal(animal: Animal): animal.eat()
if __name__ == '__main__': c = Cat() feed_animal(c) d = Dog() feed_animal(d)
|
类属性和类方法
首先说一下:
- 通过类名不能直接调用实例方法
Student.study()是不正确的
- 类名可以直接调用类属性
Student.school_name
- 类名可以直接调用类方法.
Student.show_school_name()
解释:
由于类是第一个进入内存的, 伴随着类进入内存,类属性和类方法也会进入内存.
当创建对象(实例)的时候对象也会进入内存.
先进入内存的不能调用后进入内存的方法还有属性, 比如李白的诗句, 我们可以调用李白的诗句,但是李白使用不了我们的代码
类属性定义的位置在类中,函数外.它属于类对象.它同时被所有实例对象共享.
类方法在类中定义, 前面有@classmethod
1 2 3 4
| class Student: school_name = "湖之利耶尼亚" if __name__ == '__main__': Student.school_name = "魔法学院"
|
因为类属性属于类.因此只有类对象才可以修改这个属性.比如Student.school_name = “魔法学院”
Demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class Student(): school_name = '湖之利耶尼亚' @classmethod def show_school_name(cls): print(f"学校名称是{cls.school_name}") def __init__(self, name): self.name = name def __str__(self): return f"我的名字是{self.name},我来自{self.school_name}"
if __name__ == '__main__': stu1 = Student('张三') print(stu1)
stu2 = Student('李四') print(stu2)
Student.school_name = '魔法学院' print(stu1) print(stu2) Student.show_school_name()
|
静态方法
我的理解: 静态方法(只是安静的做事, 不需要传递类对象,也不需要传递实例对象)
定义方法
1 2 3
| @staticmethod def show_help(): print("这是游戏帮助信息!")
|
面向对象Demo
一个综合案例吧~
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| """ 1. 设计一个 Game 类 (类名) 2. 属性: • 定义一个 top_score 类属性 -> 记录游戏的历史最高分 • 定义一个 player_name 实例属性 -> 记录当前游戏的玩家姓名 3. 方法: • 静态方法 show_help() -> 直接打印 这是游戏帮助信息 • 类方法 show_top_score() -> 显示历史最高分 • 实例方法 start_game() -> 开始当前玩家的游戏 - 3.1 输出 玩家 xxx 开始游戏 - 3.2 使用随机数,生成 10 - 100 之间的随机数字作为本次游戏的得分 - 3.3 打印 玩家 xxx 本次游戏得分 xxx - 3.4 判断本次游戏得分和最高分之间的关系 4. 主程序步骤: __main__ 1 查看帮助信息 2 查看历史最高分 3 创建游戏对象,开始游戏 """ import random class Game(object): top_score = 0 @staticmethod def show_help(): print("这是游戏帮助信息!") @classmethod def show_top_score(cls): print(f"当前历史最高分为{cls.top_score}") def __init__(self, player_name): self.player_name = player_name def start_game(self): print(f"玩家{self.player_name}开始游戏!") score = random.randint(10, 100) print(f"玩家{self.player_name}本次游戏得分{score}") if score > Game.top_score: Game.top_score = score print(f"本次游戏最高分为{score},创建者为{self.player_name}") if __name__ == '__main__': g = Game('小明') g.start_game() g = Game('小华') g.start_game() g = Game('小威') g.start_game()
|