面向对象介绍
面向对象(oop)是一种编程方法,编程思想(即指导如何写代码),适用于中大型项目
面向过程也是一种编程思想,适用于小型项目
面向过程和面向对象 都可以实现某个编程的目的
面向过程考虑的是 实现的细节
面向对象 考虑的是 结果(谁能做这件事)
类和对象
类和对象是面向对象编程中 最重要的两个概念
- 类是对具有相同特征或者行为的事物的一个统称,是抽象的,不能直接使用
- 指代多个事物
- 代码中 类是由关键字class定义
- 对象是由类创建出来的一个具体存在的事物,可以直接使用
- 指代 一个具体事物
- 代码中 使用 类去创建(实例化)
苹果 ---->类
红苹果 ---->类
小明手里的那个红苹果 ---->对象
狗 ---->类
大黄狗 ---->类
李四家的那条大黄狗 ---->对象
类的构成
类的构成,类的三要素
1.类名(多个事物 起一个名字,标识符规则,见名知意,类名用例满足大驼峰命名法(所有单词的首字母大写))
2.属性(事物的特征)
3.方法(事物的行为)
面向对象代码的步骤
1.设计类(找类的三要素)
2.定义类
3.创建对象(实例化对象)
4.由对象调用类中的方法
类的设计
类的设计 就是找三要素 属性和方法 可以会有很多 我们只需要找到关注的即可
类名的提取:使用名词提炼法 分析整个业务流程,得出的名词,通常就是类名
需求:
-
小明 今年18岁,身高1.75,每天早上 跑完步,会去吃东西
-
小美 今年17岁,身高1.65,小美不跑步,小美喜欢 吃东西
类名:人类Person,People,Human
属性:姓名(name),年龄(age),身高(height)
方法:跑(run)/吃(eat)
需求:
- 一只黄颜色的狗狗 叫大黄
- 看见生人 汪汪叫
- 看见家人 摇尾巴
类名:狗类(Dog)
属性:颜色(color),名字(name)
方法:叫(bark),摇尾巴(shake)
需求:
- 进入某Web项目登录页面,输入用户名、密码、验证码之后,点击登录按钮可以登录系统。
类名:LoginPage
属性:用户名(username),密码(password),验证码(verify_code),登录按钮(login_btn)
方法:登录方法(login)
面向对象基本语法
类的基本使用
1、定义类
在Python中定义类使用关键字 class.
class 类名:
#在class的缩进中定义类的属性和方法
def 方法名(self): #方法的本质是函数
pass
2、创建对象(实例化对象)
在代码中,对象是由类对象
类名() #就是创建对象
#一般使用变量将创建的对象保存起来
变量=类名() # 一般将这个变量称为是对象,本质,变量中保存的对象的引用地址
3、调用类中的方法
由类创建的对象,可以调用类中的方法
- 语法
对象.方法名()
案例
需求:小猫 爱 吃鱼,小猫 要喝水
类的设计:
类名:猫(Cat)
属性:暂无
方法:吃鱼(eat),喝水(drink)
class Cat:
def eat(self):#self 暂时不管
"""吃鱼的方法"""
print('小猫爱吃鱼...')
def drink(self):
"""喝水的方法"""
print('小猫要喝水')
#创建对象
tom = Cat()
# 通过对象 调用类中的方法
tom.eat()
tom.drink()
self 参数
1.从函数的语法上来看,self是形参,名字可以任意的变量名,只是我们习惯性叫self
2.特殊点:self是一个普通的参数,按照函数的语法,在调用的时候,我们必须传递实参值,
原因是Python解释器自动的将调用这个方法的对象作为参数传递给self
所以self就是调用这个方法对象
class Cat:
def eat(self):#self 是调用这个方法的对象
"""吃鱼的方法"""
print(f"self:{id(self)}")
print('小猫爱吃鱼...')
#创建对象
tom = Cat()
# 通过对象 调用类中的方法
print(f"tom:{id(tom)}")
tom.eat() #tom 调用,self就是tom
blue_cat=Cat()
print(f"blue:{id(blue_cat)}")
blue_cat.eat()# blue_cat调用,self就是blue_cat
属性
属性表示事物的特征
可以给对象添加属性 或者获取对象的属性值
给对象添加属性:
对象.属性名=属性值 #添加或者修改
获取对象的属性值
对象.属性名
在方法中操作属性(self是对象):
self.属性名=属性值
self.属性名
class Cat:
def eat(self):#self 是调用这个方法的对象
"""吃鱼的方法"""
print(f"self:{id(self)}")
print(f'小猫{self.name}爱吃鱼...')
#创建对象
tom = Cat()
# 通过对象 调用类中的方法
print(f"tom:{id(tom)}")
#给Tom 对象添加name 属性
tom.name ='汤姆'
print(tom.name)
tom.eat() #tom 调用,self就是tom
blue_cat=Cat()
print(f"blue:{id(blue_cat)}")
blue_cat.name='蓝猫'
print(blue_cat.name)
blue_cat.eat()# blue_cat调用,self就是blue_cat
- 练习
Cat 添加属性 姓名,年龄
eat 方法中打印输出,小猫xx xx 岁 爱吃鱼
魔法方法
在Python中存在一类方法,以两个下划线开头,两个下划线结尾,在满足某个条件的情况下,会自动调用
这一类方法 称为是 魔法方法
怎么学习:
1.什么情况下会自动调用(自动调用的时机)
2.应用场景
3.注意事项
初始化方法 __init__
1.调用时机
在创建对象之后,会自动调用
2.应用场景
初始化对象,给对象添加属性
3.注意事项
-不要写错
- 如果属性是会变化的,则可以将这个属性的值作为参数传递,在创建对象的时候,必须传递实参值
class Cat:
def __init__(self,name):
print('我是init方法,我被调用了')#验证使用,正式代码不要
self.name=name
def eat(self):
print(f'小猫{self.name}爱吃鱼')
#init方法 创建对象之后 会自动调用
blue_cat=Cat('蓝猫')
blue_cat.eat()
black_cat=Cat('黑猫')
black_cat.eat()
__str__
方法
1.调用时机
使用print(对象) 打印对象的时候,会自动调用
1.如果没有定义__str__方法,默认打印的是 对象的引用地址
2.如果定义__str__方法,打印的是 方法的返回值
2.应用场景
使用print(对象) 打印输出对象的属性信息
3.注意事项
必须返回一个字符串
"""
定义Cat类,包含属性 name和age,打印对象的时候,可以
输出对象的姓名和年龄
类名:Cat
属性:name,age
方法:__str__,__init__
"""
class Cat:
def __init__(self,name,age):
self.name=name # 添加name属性
self.age=age #添加age 属性
def __str__(self):#一般不使用print 直接返回
return f"姓名:{self.name},年龄:{self.age}"
#创建对象
tom = Cat('汤姆',3)
print(tom)
封装案例
封装:根据要求将属性和方法 定义到类中(定义类)
案例一 小明爱跑步
需求:
- 小明 体重75.0公斤
- 小明每次跑步 会减肥 0.5公斤
- 小明每次吃东西 体重增加 1 公斤
类名:人类(Person)
属性:体重(weight) 姓名(name)
方法:跑步(run) --->修改属性值
吃东西(eat) --->修改属性值
__init__定义属性
__str__打印属性信息使用
class Person:
def __init__(self,name,weight):
self.name=name #姓名
self.weight=weight #体重
def __str__(self):
return f"{self.name}目前的体重为{self.weight}kg"
def run(self):
"""跑步的方法"""
#体重减少0.5kg
#self.weight=self.weight-0.5
self.weight-=0.5
print(f"{self.name}跑步了,体重减少0.5kg")
def eat(self):
"""吃东西的方法"""
#体重增加1kg
self.weight+=1
print(f"{self.name}大餐一顿,体重增加了1kg")
if __name__ == '__main__':
#创建对象
xming=Person('小明',75.0)
print(xming)
xming.run()
print(xming)
xming.eat()
print(xming)
print('_'*30)
xmei=Person('小美',45.0)
print(xmei)
xmei.run()
print(xmei)
xmei.eat()
print(xmei)
案例二 登录
- 需求
进入某Web项目登录页面,输入用户名,密码,验证码之后登录系统
- 类的设计
类名:LoginPage
属性:用户名(username),密码(password),验证码(verify_code)
方法:login
- 代码实现
class LoginPage:
"""登录页面"""
def __init__(self,username,password,veriff_code):
self.username=username #用户名
self.password=password # 密码
self.verify_code=veriff_code #验证码
def login(self):
print(f"1.输入用户名:{self.username}")
print(f"2.输入密码:{self.password}")
print(f"3.输入验证码:{self.verify_code}")
print(f"4.点击登录")
if __name__ == '__main__':
admin=LoginPage('admin','123456','8888')
admin.login()
案例三 摆放家具
- 需求
1.房子(House)有 户姓、总面积和家具名称列表 -新房子没有任何的家具
2.家具(HouseItem)有名字和占地面积,其中
- 席梦思(bed)占地4平米
- 衣柜(chest)占地2平米
- 餐桌(table)占地1.5平米
3.将以上三件家具添加到房子中
4.打印房子时,要求输出:户型、总面积、剩余面积、家具名称列表
剩余面积
1.在创建房子对象时,定义一个剩余面积的属性,初始值和总面积相等
2.当调用 add_item方法,向房间 添加家具时,让剩余面积 -=家具面积
- 类的设计
类名:房子类(House)
属性:户型(h_type),
总面积 total_area
剩余面积 free_area =total_area
家具名称列表 item_list = [ ]
方法:__init__ ,__str__
添加家具的方法 add_item(1.修改剩余面积2.判断剩余面积和家具面积的关系
3.向家具列表中添加家具的名字)
---------------------------
类名: 家具类(HouseItem)
属性: 名字 name
占地面积 area
方法: __str__ , __init__
三个家具对象
– 席梦思(bed) 占地 4 平米
– 衣柜(chest) 占地 2 平米
– 餐桌(table) 占地 1.5 平米
class HouseItem:
"""家具类"""
def __init__(self,name,area):
self.name = name # 名字
self.area = area # 占地面积
def __str__(self):
return f"{self.name}占地面积{self.area}平米"
class House:
"""房子类"""
def __init__(self,h_type,area):
self.h_type = h_type #户型
self.total_area = area #总面积
self.free_area = area #剩余面积和总面积一样
self.item_list=[]#刚开始没有家具
def __str__(self):
return f"户型:{self.h_type}、总面积: {self.total_area}平米、剩余面积:{self.free_area}平米、家具名称列表:{self.item_list}"
def add_item(self,item):#1.房子对象(self)2.家具对象(传参)
"""添加家具,item家具对象"""
#1.先判断房子的剩余面积和家具的占地面积的关系
if self.free_area > item.area: # 对象.属性 获取属性值
print(f"添加家具:{item.name}")
self.item_list.append(item.name)
#修改剩余面积
self.free_area -= item.area
else:
print(f"房子剩余面积不足,换个大房子吧..")
if __name__ == '__main__':
#创建家具对象
bed=HouseItem('席梦思',4)
chest= HouseItem('衣柜',2)
table = HouseItem('餐桌',1.5)
print(bed)
print(chest)
print(table)
#创建房子
house =House('三室一厅',100)
print(house)
house.add_item(bed)
print(house)
house.add_item(chest)
print(house)
house.add_item(table)
print(house)
继承
1.继承描述的是类与类之间的关系 is ...a
2.继承的好处:减少代码冗余,重复代码不需要多次书写,提高编程效率
语法
#class 类A(object):
#class 类A():
class 类A: # 默认继承object类,object类Python中最原始的类
pass
class 类B(类A):就是继承,类B继承类A
pass
#类A:父类 或 基类
#类B: 子类 或 派生类
子类继承父类之后,子类对象可以直接使用父类中的属性和方法
# 1.定义动物类,动物类有姓名和年龄属性,具有吃和睡的行为
class Animal:
"""动物类"""
def __init__(self,name,age):
self.name = name
self.age = age
def eat(self):
"""吃"""
print(f"{self.name}吃东西")
def sleep(self):
"""睡"""
print(f"{self.name} 睡觉")
# 2.定义猫类,猫类具有动物类的所有属性和方法,并且具有抓老鼠的特殊行为
class Cat(Animal):
"""猫类"""
def catch(self):
print(f"{self.name}会抓老鼠..")
# 3.定义狗类,狗类具有动物类的所有属性和方法,并且具有看门的特殊行为
class Dog(Animal):
"""狗类"""
def look_the_door(self):
"""看门"""
print(f"{self.name}正在看家...")
#4.定义哮天犬,哮天犬具有狗类的所有属性和方法,并且具有飞的特殊行为
class XTQ(Dog):
"""哮天犬类"""
def fly(self):
"""飞"""
print(f"{self.name} 在天上飞..")
if __name__ == '__main__':
ani = Animal('佩奇',2)
ani.eat()
ani.sleep()
cat =Cat('黑猫警长',10)
cat.eat() #调用父类animal中的方法
cat.sleep()# 调用父类animal中的方法
cat.catch()#调用自己类的方法
dog=Dog('旺财',3)
dog.eat()
dog.sleep()
dog.look_the_door()
xtq=XTQ('哮天犬',100)
xtq.eat()
xtq.sleep()
xtq.look_the_door()
xtq.fly()
继承具有传递性:C继承B,B继承A,C可以使用A类中的属性和方法
对象调用方法的顺序:对象.方法名()
1.会先在自己的类中查找,找到直接使用
2.没有找到 去父类中查找,找到直接使用
3.没有找到 在父类的父类中查找,找到直接使用
4.没有找到..
5.直到object类,找到直接使用,没有找到 报错
重写(override)
1.什么是重写?
重写是在子类中定义了和父类中名字一样的方法
2.重写的原因?为什么重写?
父类中的代码不能满足子类对象的需要
3.重写的方式
3.1 覆盖式重写
3.2 扩展式重写
覆盖式重写
父类中的功能全部不要
直接在子类中定义和父类中方法名字一样的方法接口,直接书写新的代码
class Dog:
def bark(self):
print('汪汪的叫...')
class XTQ(Dog):
#需要哮天犬 嗷嗷叫 父类中bark方法 不能满足子类对象的需要,覆盖式重写
def bark(self):
print("嗷嗷嗷叫")
if __name__ == '__main__':
xtq = XTQ()
xtq.bark()
扩展式重写
父类中的功能还需要,只是添加了新的功能
方法:
1.先在子类中定义和父类中名字相同的方法
2.在子类的代码中 使用super().方法名() 调用父类中的功能
3.书写新的功能
class Dog:
def bark(self):
print('汪汪的叫...')
print('汪汪的叫...')
class XTQ(Dog):
#需要哮天犬 嗷嗷叫 父类中bark方法 不能满足子类对象的需要,覆盖式重写
def bark(self):
#调用父类中的功能
super().bark()
print("嗷嗷嗷叫")
print("嗷嗷嗷叫")
if __name__ == '__main__':
xtq = XTQ()
xtq.bark()
多态
多态:调用代码的技巧
多态:不同的子类对象调用相同的方法,产生不同的执行结果
class Dog:
def game(self):
print("普通狗简单的玩耍..")
class XTQ(Dog):
def game(self):
print("哮天犬在天上玩耍..")
class Person:
def play_with_dog(self,dog):
"""dog是狗类或者其子类的对象"""
print("人和狗在玩耍..",end = '')
dog.game()
if __name__ == '__main__':
dog1=Dog()
xtq = XTQ()
xw=Person()
xw.play_with_dog(dog1)
xw.play_with_dog(xtq)
私有和公有
在Python中,定义类的时候,可以给属性和方法 设置访问权限,即规定在什么地方可以使用
权限一般分为两种:公有权限 私有权限
公有权限
-
定义
直接定义的属性和方法就是公有的
-
特点
可以在任何地方访问和使用,只要有对象就可以访问和使用
私有权限
- 定义
1.只能在类内部定义(class关键字的缩进中)
2.只需要在 属性名或者方法名前边加上两个下划线,这个方法或者属性就变为私有的
- 特点
私有 只能在当前类的内部使用,不能在类外部和子类直接使用
- 应用场景
一般来说,定义的属性和方法 都为公有的
某个属性 不想在外部直接使用 定义为私有
某个方法 是内部的方法(不想在外部使用),定义为私有
"""定义人类 name属性 age属性(私有)"""
class Person:
def __init__(self,name,age):
self.name = name #公有
self.__age = age #公有 --->私有 ,在属性名前加上两个下划线
def __str__(self): #公有方法
return f"{self.name},{self.__age}"
def set_age(self,age):# 定义公有方法,修改私有属性
if age < 0 or age>120:
print('提供的年龄信息不对')
return
self.__age= age
if __name__ == '__main__':
xw=Person('小王',18)
print(xw)
xw.__age =10000 #添加一个公有属性__age
print(xw)
xw.set_age(10000)
print(xw)
对象 属性 方法
对象分类
- python 中一切皆对象
类对象
类对象 就是类 就是使用class定义的类
在代码执行的时候,解释器会自动的创建
作用:
1.使用类对象创建 实例对象
2.存储一些类的特征值 (类属性)
实例对象
1.创建对象也称为实例化 所有由类对象(类)创建的对象 称为是实例对象,简称实例
2.一般来说,没有特殊强调,我们所说的对象都是指 实例对象(实例)
3.实例对象 可以保存实例的特征值(实例属性)
4.就是使用 类名() 创建的对象
属性的划分
使用实例对象.属性 访问属性的时候,会先在实例属性中查找,如果找不到,就去类属性中查找
找到就使用,找不到就报错
即:每个实例对象 都有可能访问类属性值(前提 实例属性和类属性不重名)
实例属性
- 概念
是每个实例对象 具有的特征(属性),每个实例对象的特征
- 定义
一般都是在init方法中,使用self.属性名 = 属性值 来定义
- 特征(内存)
每个实例对象 都会保存自己的 实例属性 即内存中存在多份
- 访问和修改
# 可以认为是通过self
实例对象.属性 = 属性值 #修改
实例对象.属性 #访问
类属性
- 概念
是类对象具有的 特征,是整个类的特征
- 定义
一般在类的内部(class缩进中),方法的外部(def的缩进外部)定义的变量
- 特征(内存)
只有类对象保存一份,即在内存中只有一个
- 访问和修改
# 即通过类名
类对象.属性 = 属性值
类对象.属性
什么时候 定义类属性?
代码中 使用的属性 基本上都是实例属性,即都通过self定义
当某个属性值描述的信息是整个类的特征(这个值变动,所有的这个类的对象这个特征都会发生变化)
案例
1.定义一个 工具类
2.每件工具都有自己的 name
3.需求 知道使用这个类 创建了多少个工具对象?
类名:Tool
属性: name(实例属性) count(类属性)
方法: init方法
class Tool:
#定义类属性count,记录创建对象的个数
count = 0
def __init__(self,name):
self.name = name #实例属性,工具的名字
# 修改类属性的值
Tool.count +=1
if __name__ == '__main__':
#查看创建对象的个数
print(Tool.count)#查看类属性
tool1=Tool('锤子')
print(Tool.count)
tool2=Tool('扳手')
print(Tool.count)
print(tool2.count)#先找实例属性count,找不到,找类属性count 找到 使用
方法的划分
实例方法
- 定义时机
如果方法中需要使用 实例属性,则这个方法 必须定义为实例方法
- 定义
#直接定义的方法就是实例方法
class 类名:
def 方法名(self):
pass
- 参数
参数一般写作self,表示的是实例对象
- 调用
实例对象.方法名()
类方法
- 定义时机
如果方法中 不需要使用 实例属性,但需要使用类属性,则这个方法可以定义为类方法(建议)
- 定义
#定义类方法,需要在方法名上方 书写@classmethod,即使用@classmethod装饰器装饰
class 类名:
@classmethod
def 方法名(cls):
pass
- 参数
参数一般写作 cls 表示类对象,即类名 同样不需要手动传递 python解释器会自动传递
- 调用
方法一
类名.方法名()
方法二
实例对象.方法名()
静态方法
- 定义时机
方法中既不需要使用实例属性,也不需要使用 类属性,可以 将这个方法定义为静态方法
- 定义
# 定义静态方法,需要使用装饰器@staticmethod装饰方法
class 类名:
@staticmethod
def 方法名():
pass
- 参数
静态方法 对参数没有要求 一般没有
- 调用
方法一
类名.方法名()
方法二
实例对象.方法名()
class Tool:
#定义类属性count,记录创建对象的个数
count = 0
def __init__(self,name):
self.name = name #实例属性,工具的名字
# 修改类属性的值
Tool.count +=1
@classmethod
def show_tool_count(cls):#cls 就是类对象 类名
return cls.count
if __name__ == '__main__':
#查看创建对象的个数
print(Tool.show_tool_count())#查看类属性
tool1=Tool('锤子')
print(Tool.show_tool_count())
tool2=Tool('扳手')
print(Tool.show_tool_count())
案例
需求:
1. 设计一个 Game 类
2. 属性:
• 定义一个 top_score 类属性 -> 记录游戏的历史最高分
• 定义一个 player_name 实例属性 -> 记录当前游戏的玩家姓名
3. 方法:
• 静态方法 show_help() -> 显示游戏帮助信息
• 类方法 show_top_score() -> 显示历史最高分
• 实例方法 start_game() -> 开始当前玩家的游戏
- ① 使用随机数 生成 10-100 之间数字 作为本次游戏的得分
- ② 打印本次游戏等分 : 玩家 xxx 本次游戏得分 ooo
- ② 和历史最高分进行比较, 如果比历史最高分高, 修改历史最高分
4. 主程序步骤: main
1 查看帮助信息
2 查看历史最高分
3 创建游戏对象,开始游戏
4 再一次游戏
类名:Game
属性:
top_score = 0 类属性
player_name 实例属性 init
import random
class Game:
#定义类属性,保存历史最高分
top_score = 0
def __init__(self,name):
self.player_name = name #实例属性
#静态方法
@staticmethod
def show_help():
print('这是游戏的帮助信息')
#类方法
@classmethod
def show_top_score(cls):
print(f'历史最高分为:{cls.top_score}')
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
if __name__ == '__main__':
Game.show_help()
Game.show_top_score()
player =Game('小王')
player.start_game()
Game.show_top_score()
player.start_game()
Game.show_top_score()