黑马程序员python网课笔记(接上一篇)
2021/10/31 12:39:54
本文主要是介绍黑马程序员python网课笔记(接上一篇),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
面向对象封装案例
01. 小明爱跑步
- 需求
- 体重75公斤
- 每次跑步减0.5公斤
- 吃东西体重增加1公斤
class Person: def __init__(self,name,weight): # self.属性 = 形参 self.name = name self.weight = weight def __str__(self): return "我的名字是%s 体重是%.2f 公斤" % (self.name,self.weight) def run(self): print("%s 爱跑步 , 跑步锻炼身体" % self.name) self.weight -= 0.5 def eat(self): print("%s 爱吃饭 , 吃饭增长体重" % self.name) self.weight += 1 xiaoming = Person("小明",75.0) xiaoming.run() xiaoming.eat() print(xiaoming) xiaomei = Person("小美",45.0) xiaomei.run() xiaomei.eat() print(xiaomei) # 多个对象之间互不影响 小明 爱跑步 , 跑步锻炼身体 小明 爱吃饭 , 吃饭增长体重 我的名字是小明 体重是75.50 公斤 小美 爱跑步 , 跑步锻炼身体 小美 爱吃饭 , 吃饭增长体重 我的名字是小美 体重是45.50 公斤
02.摆放家具
- 需求
- 房子有户型,总面积和家具名称列表
- 新房子无家具
- 家具:名字和占地面积
- 席梦思:4
- 衣柜:2
- 餐桌:1.5
- 将家具添加到房子
- 打印房子输出:户型,总面积,剩余面积,家具名称列表
- 剩余面积
- 创建对象时定义
- 调用add_item方法添加家具
- 先开发哪个类?
家具类:家具类简单,房子要使用到家具,在开发中被使用的类先开发
class HouseItem: def __init__(self, name, area): self.name = name self.area = area def __str__(self): return "%s 占地 %.2f" % (self.name, self.area) bed = HouseItem("席梦思", 4) chest = HouseItem("衣柜", 2) table = HouseItem("餐桌", 1.5) print(bed) print(chest) print(table) 席梦思 占地 4.00 衣柜 占地 2.00 餐桌 占地 1.50
定义房子类
class HouseItem: def __init__(self, name, area): self.name = name self.area = area def __str__(self): return "%s 占地 %.2f" % (self.name, self.area) class House: def __init__(self, house_type, area): self.house_type = house_type self.area = area self.free_area = area self.item_list = [] def __str__(self): return ("户型:%s\\n总面积: %.2f\\n剩余面积:%.2f\\n家具: %s" % (self.house_type, self.area, self.free_area, self.item_list)) # python能自动将括号里的代码连接到一起 def add_item(self,item): print("要添加%s" % item) bed = HouseItem("席梦思", 4) chest = HouseItem("衣柜", 2) table = HouseItem("餐桌", 1.5) print(bed) print(chest) print(table) my_house = House("两室一厅", 60) my_house.add_item(bed) my_house.add_item(chest) my_house.add_item(table) 席梦思 占地 4.00 衣柜 占地 2.00 餐桌 占地 1.50 要添加席梦思 占地 4.00 要添加衣柜 占地 2.00 要添加餐桌 占地 1.50
完成摆放家具:
class HouseItem: def __init__(self, name, area): self.name = name self.area = area def __str__(self): return "%s 占地 %.2f" % (self.name, self.area) class House: def __init__(self, house_type, area): self.house_type = house_type self.area = area self.free_area = area self.item_list = [] def __str__(self): return ("户型:%s\\n总面积: %.2f\\n剩余面积:%.2f\\n家具: %s" % (self.house_type, self.area, self.free_area, self.item_list)) # python能自动将括号里的代码连接到一起 def add_item(self,item): print("要添加%s" % item) if item.area > self.free_area: print("%s面积太大" % item.area) return self.item_list.append(item.name) self.free_area -= item.area bed = HouseItem("席梦思", 4) chest = HouseItem("衣柜", 2) table = HouseItem("餐桌", 1.5) print(bed) print(chest) print(table) my_house = House("两室一厅", 60) my_house.add_item(bed) my_house.add_item(chest) my_house.add_item(table) print(my_house) 席梦思 占地 4.00 衣柜 占地 2.00 餐桌 占地 1.50 要添加席梦思 占地 4.00 要添加衣柜 占地 2.00 要添加餐桌 占地 1.50 户型:两室一厅 总面积: 60.00 剩余面积:52.50 家具: ['席梦思', '衣柜', '餐桌']
03.士兵突击
一个对象的属性可以是另一个类创建的对象
- 需求:
- 士兵 许三多 有一把ak47
- 士兵可以开火
- 枪可以发射子弹
- 枪装填子弹
枪类:
class Gun: def __init__(self, model): self.model = model self.bullet_count = 0 def add_bullet(self, count): self.bullet_count += count def shoot(self): if self.bullet_count <= 0: print("%s没有子弹了" % self.model) return self.bullet_count -= 1 print("%s突突突%d" % (self.model, self.bullet_count)) ak47 = Gun("ak47") ak47.add_bullet(50) ak47.shoot() ak47突突突49
士兵类:
class Gun: def __init__(self, model): self.model = model self.bullet_count = 0 def add_bullet(self, count): self.bullet_count += count def shoot(self): if self.bullet_count <= 0: print("%s没有子弹了" % self.model) return self.bullet_count -= 1 print("%s突突突%d" % (self.model, self.bullet_count)) class Soldier: def __init__(self, name): self.name = name self.gun = None def fire(self): if self.gun == None: print("%s还没有枪" % self.name) return print("冲啊...%s" % self.name) self.gun.add_bullet(50) self.gun.shoot() ak47 = Gun("ak47") xusanduo = Soldier("许三多") xusanduo.gun = ak47 xusanduo.fire() 冲啊...许三多 ak47突突突49
身份运算符(补充)
用于比较两个对象的内存地址是否相同—是否为对同一个对象的引用
- 在python中针对None的比较建议使用is
- ==用于判断两个引用变量的值是否相等
私有属性和私有方法
01.应用场景及定义方法
应用场景
- 对象的某些属性和方法不需要对外界公开,只在内部使用
定义方式
- 在属性名或方法名前加两个下划线
class Women: def __init__(self, name): self.name = name self.__age = 18 def secret(self): # 在对象的方法内部可以访问私有属性 print("%s的年龄是%d" % (self.name, self.__age)) xiaofan = Women("小芳") # print(xiaofan.age) xiaofan.secert() 小芳的年龄是18
02.伪私有属性和私有方法(了解)
python中不存在真正的私有属性和私有方法
- 在给出的属性、方法命名时对名称做特殊处理导致外界访问不到
- 处理方式:在名称前加上_类名 ⇒ _类名__名称
class Women: def __init__(self, name): self.name = name self.__age = 18 def secret(self): # 在对象的方法内部可以访问私有属性 print("%s的年龄是%d" % (self.name, self.__age)) xiaofan = Women("小芳") print(xiaofan._Women__age) xiaofan.secret()
- 子类对象不能在自己的方法内部直接访问父类的私有方法和属性
- 子类可以通过父类的公有方法访问到私有方法和私有属性
继承
面向对象三大特性:
- 封装
- 继承 子类拥有父类所以的方法
- 多态
- 语法:
class Animal: def eat(self): print("吃") **class dog(Animal):**# 继承 def bark(self): print("叫") dog = dog() dog.bark() dog.eat()
-
术语: 子类,父类,继承
派生类,基类,派生
-
继承的传递性
- c继承b,b继承a
- c类拥有b和a所以属性和方法
- 方法的重写
-
父类的方法不能满足子类的需求,就需要子类对方法进行重写
- 覆盖父类的方法:在子类中重新编写父类 的方法实现(定义一个同名方法)
- 对父类方法进行扩展:子类方法实现存在父类方法。在子类中重写父类方法,在需要的位置通过 super().父类方法 实现对父类方法的执行
class Animal: def eat(self): print("吃") class dog(Animal):# 继承 def bark(self): print("叫") def eat(self): print("吃骨头") super().eat() dog = dog() dog.bark() dog.eat() 叫 吃骨头 吃
- 另一种调用父类方法:父类名.方法(self),不推荐这种方式(了解)
多继承
概念:子类可以拥有多个父类,拥有所有父类的属性和方法
语法:class 子类名(父类名1,父类名2)
- 开发时如果不同的父类中会有同名的方法,应该避免多继承
- python中的MRO—方法搜索顺序:
- python中提供内置对象__mro__可以查看方法搜索顺序
- mro主要用于多继承时判断方法、属性的调用路径
- 输出时是按照__mro__的输出结果从左向右的顺序查找
- 在当前类中找到方法就不再执行
- 如果在Object类中也没有找到就会报错
当前类→父类1→父类2→object类
新式类和旧式类
object是python为所有对象提供的基类,提供一些内置方法和属性,可以使用dir方法函数查看
- 新式类:以object为基类的类
- 旧式类:不以object为基类的类
class A(object): pass class B: pass a = A() b = B() print(dir(a)) print(dir(b)) # 新版本python中默认为新式类 ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__'] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
多态
特性:不同子类对象调用相同的方法,产生不同执行结果
- 可以增加代码灵活度
- 以继承和重写父类方法 为前提
- 不会影响类的内部设计
案例演练
需求
- 在dog类中封装game方法
- 定义xiaotianquan继承dog类,重写game方法
- 定义person类,封装和狗玩的方法
class Dog(): def __init__(self, name): self.name = name def game(self): print("%s蹦蹦跳跳的玩耍" % self.name) class xiaotianquan(Dog): def game(self): print("%s飞到天上去玩耍" % self.name) class person(): def __init__(self, name): self.name = name def game_with_dog(self, dog): print("%s和%s快乐的玩耍" % (self.name, dog.name)) dog.game() wangcai = Dog("旺财") huahua = xiaotianquan("飞天花花") xiaoming = person("小明") xiaoming.game_with_dog(wangcai) xiaoming.game_with_dog(huahua) 小明和旺财快乐的玩耍 旺财蹦蹦跳跳的玩耍 小明和飞天花花快乐的玩耍 飞天花花飞到天上去玩
类属性
01. 类的结构
- 使用类名()创建对象,分为两部:
- 在内存中分配空间
- 调用初始化方法__init__为对象初始化
- 对象创建后,内存中就存在实例
- 对象叫做类的实例
- 创建对象叫做实例化
- 对象的属性为实例属性
- 对象调用的方法叫做实例方法
- 多个对象的方法在内存中只有一份,在调用方法时,需要把对象的引用传递到方法内部
02. 类是一个特殊的对象
- class AAA:定义的类属于类对象
- obj1 = AAA()属于实例对象
- 类对象在内存中只有一份,一个类可以创建出多个实例对象
- 除封装实例的属性和方法外,类对象还可以拥有自己的属性和方法
- 类属性
- 类方法
- 通过 类名.的方法访问类的属性和方法
03. 类属性和实例属性
概念:
- 类属性为类对象中定义的属性
- 记录类的相关特征
- 类属性不会用于记录具体对象特征
示例需求:
- 定义一个工具类
- 每件工具都有自己的name
- 需求——知道使用这个类,创建了多少个工具对象?
class Tool(object): count = 0 def __init__(self,name): self.name = name Tool.count +=1 tool1 = Tool("斧头") tool2 = Tool("榔头") tool3 = Tool("水桶") print(Tool.count) 3
属性获取机制(了解):
-
在python中获取属性存在向上查找机制
- 首先在对象内部查找对象属性
- 没有找到就会向上寻找类属性
class Tool(object): count = 0 def __init__(self,name): self.name = name Tool.count +=1 tool1 = Tool("斧头") tool2 = Tool("榔头") tool3 = Tool("水桶") print(tool3.count) # 不建议使用,因为会给对象添加count属性 3
类方法
类方法的创建:
- 语法:
@classmethod def 类方法名(cls): pass
- cls告诉解释器这是一个类方法
- 由哪一个类调用的方法,方法内的cls就是哪一个类的引用
- 类似于self
- 使用其他名称也可(不推荐)
- 在方法内可以通过cls.访问类属性,也可以调用其他类方法
实力需求:
- 定义一个工具类
- 每件工具都有自己的name
- 需求——在类中封装一个show_tool_count的类方法,输出使用当前这个类,创建的对象个数
class Tool(object): count = 0 @classmethod def show_tool_count(cls): print("工具对象的数量 %d" % cls.count) def __init__(self,name): self.name = name Tool.count +=1 tool1 = Tool("斧头") tool2 = Tool("榔头") tool3 = Tool("水桶") Tool.show_tool_count() 工具对象的数量 3
静态方法
- 在开发中,需要封装一个方法:
- 不需要访问实例属性或者实例方法
- 也不需要访问类属性和类方法
- 这个时候可以封装成静态方法
- 通过 类名. 调用
- 语法
@staticmethod def 静态方法名(): pass简单的示例:
class Dog(object): @staticmethod def run(): print("小狗要跑") Dog.run() # 通过类名访问不需要实例化 小狗要跑
方法综合案例
需求:
- 设计一个Game类
- 属性:
- 定义一个类属性 top_score记录游戏的历史最高得分
- 定义一个示例属性 player_name记录当前游戏的玩家姓名
- 方法:
- 静态方法 show_help显示游戏的帮助信息
- 类方法 show_top_score 显示历史最高分
- 实例方法 start_game开始当前玩家的游戏
- 主程序步骤
- 查看帮助信息
- 查看历史最高分
- 创建游戏对象,开始游戏
class Game(object): top_score = 0 def __init__(self, player_name): self.player_name = player_name @staticmethod def show_help(): print("帮助信息:") @classmethod def show_top_score(cls): print("历史记录%d" % cls.top_score) def start_game(self): print("%s开始游戏啦" % self.player_name) Game.show_help() Game.show_top_score() game = Game("小明") game.start_game() 帮助信息: 历史记录0 小明开始游戏啦
单例
01. 单例设计模式
设计模式:
- 设计模式是前人工作的总结,针对某一个特定问题的成熟的解方案
- 为了可重用代码,让代码更容易理解
单例设计模式:
- 目的——让 类 创建的对象,在系统中只有一个实例
- 每一次执行 类名() 返回的对象,内存地址相同
**new 方法:**
- 使用类名()创建对象时,会首先调用__new__()方法为对象分配空间
- new()方法是内置的静态方法
- 为对象分配空间
- 返回对象引用
- 解释器获得对象引用后,将引用作为第一个参数,传递给__init__方法
- 重写__new__()方法一定要return super().new(cls)
class MusicPlayer(object): def __new__(cls, *args, **kwargs): print("创建对象,分配空间") return super().__new__(cls) def __init__(self): print("播放器初始化") player1 = MusicPlayer() player2 = MusicPlayer() print(player1) print(player2) 创建对象,分配空间 播放器初始化 创建对象,分配空间 播放器初始化 <__main__.MusicPlayer object at 0x0000028CFCFB3E50> <__main__.MusicPlayer object at 0x0000028CFCFB3E20>
- 单例设计模式代码实现
class MusicPlayer(object): # 记录第一个被创建对象的引用 instance = None def __new__(cls, *args, **kwargs): # 判断类属性是否为空对象 if cls.instance is None: # 调用父类方法,为第一个对象分配空间 cls.instance = super().__new__(cls) return cls.instance player1 = MusicPlayer() player2 = MusicPlayer() print(player1) print(player2) <__main__.MusicPlayer object at 0x0000024C8E613EE0> <__main__.MusicPlayer object at 0x0000024C8E613EE0>
扩展:
-
每次创建对象时,python会自动调用两个方法:
- __new__分配空间
- __init__对象初始化
-
创建对象时还会调用初始化方法
-
需求:让初始化方法只执行一次
-
解决方法:
- 定义类属性init_flag标记是否执行初始化动作
- 在__init__中判断init_flag
class MusicPlayer(object): # 记录第一个被创建对象的引用 instance = None # 记录是否执行过初始化方法 init_flag = False def __new__(cls, *args, **kwargs): # 判断类属性是否为空对象 if cls.instance is None: # 调用父类方法,为第一个对象分配空间 cls.instance = super().__new__(cls) return cls.instance def __init__(self): # 判断是否执行初始化动作 if MusicPlayer.init_flag: return # 执行初始化动作 print("初始化播放器") # 修改标记值 MusicPlayer.init_flag = True player1 = MusicPlayer() player2 = MusicPlayer() print(player1) print(player2) 初始化播放器 <__main__.MusicPlayer object at 0x0000022EE6713E80> <__main__.MusicPlayer object at 0x0000022EE6713E80>
这篇关于黑马程序员python网课笔记(接上一篇)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-30Python中''') 是什么?-icode9专业技术文章分享
- 2024-11-26Python基础编程
- 2024-11-25Python编程基础:变量与类型
- 2024-11-25Python编程基础与实践
- 2024-11-24Python编程基础详解
- 2024-11-21Python编程基础教程
- 2024-11-20Python编程基础与实践
- 2024-11-20Python编程基础与高级应用
- 2024-11-19Python 基础编程教程
- 2024-11-19Python基础入门教程