面向对象编程
补充知识点
#循环.... else 语法
for 变量 in xxx:
if xx:
break #如果循环执行了break ,就不再执行else中的代码
else:
#循环不是被break 终止的,可以执行
一、面向对象介绍
1.1 面向对象基本概念
1、面向对象编程: Object Oriented Programming简写00P
2、面向对象(oop)是一种编程方法,编程思想(即指导如何写代码),适用于中大型项目(一个对象封装多个方法)
3、面向过程也是一种编程思想,适用于小型项目(根据需求,将某些独立功能封装成一个又一个函数。最后完成的代码,就是顺序地调用不同的函数)
4、面向过程 和 面向对象都可以实现某个编程的目的
5、面向过程 考虑的是 实现的细节
6、面向对象 考虑的是 结果( 谁能做这件事)
1.2 类 和 对象【重要】
类和对象是面对对象编程中最重要的两个概念
-
类:是对具有相同特征或者行为的事物的一个统称,是抽象的,不能直接使用
- 指代多个事物
- 代码中类是由关键字 class 定义
- 类包含的主要内容:
特征(静态)->属性
行为(动态)->方法
-
对象:是由类创建出来的一个具体存在的事物,可以直接使用
- 指代一个具体事物
- 代码中使用类去创建(实例化),拥有类中定义的 属性和方法
梨 ---》 类
黄色的梨 ----》 类
张三手里的苹果 ----》对象
重点:
类 :就是模具。拥有一-定的整体特征。
对象:符合模具的要求,有具体的实现。
当我们把一大堆拥有共同特征的对象的静态特征(属性)和动态特征(行为)都抽取出来后,就可以定义出一个叫做“类的东西。
1.3 类的构成(三要素)【重点】
- 类名: 同类事物 的名字,命名要满足大驼峰命名法
- 属性: 同类事物 具备的特征
- 方法: 同类事物 具备的行为
大驼峰命名法:所有单词第一个字母大写,单词之间没有下划线!
1.4 面向对象代码的步骤
1, 设计类(找类的三要素)
2, 定义类
3, 创建对象(实例化对象)
4, 由对象调用类中的方法
1.5 类的设计
类的设计 就是找三要素,属性和方法可能会有很多,我们只需要找到关注的即可
类名的提取:使用名词提炼法分析整个业务流程,得出的名词,通常就是类名
提示:对于需求中没有提到的属性和方法,在设计类的时候不要添加进来!
需求:
●小明今年18岁,身高1.75,每天早上跑完步,会去吃东西
●小美今年17岁,身高1.65,小美不跑步,小美喜欢吃东西
类名: 人类 Person,People,Human
属性: 姓名(name),年龄(age),身高(height)
方法: 跑(run)/吃(eat)
需求:
●一只黄颜色的狗狗叫大黄
●看见生人汪汪叫
●看见家人摇尾巴
类名: 狗(Dog)
属性: 名字(name),yans(color)
方法: 叫(bark),摇尾巴(shake)
需求:
●进入某Web项目登录页面,输入用户名、密码、验证码之后,点击登录按钮可以登录系统
类名: LoginPage
属性: 用户名(username),密码( password),验证码(verify_code),登录按钮(login_btn)
方法: 登录方法(login)
需求:进入某APP项目的下订单页面,输入用户收货地址后,点击提交订单按钮,可以实现下单操作
类名: OrderPage
属性:用户地址(useraddress),提交订单按钮(order_btn)
方法:下单(order)
二、面向对象的基本语法【重要】
2.1 类的基本使用
2.1.1 类的定义(只含方法)
# 在Python中定义类使用关键字class
class 类名:
#在class 的缩进中定义类的属性和方法,
#方法:定义方式与函数基本相同,区别是方法的第一个参数必须为self
def 方法名(self): # 方法的本质是函数
pass
2.1.2 创建对象(实例化对象)
在代码中,对象是由类对象
类名() #就是创建对象
#一般使用变量将创建的对象保存起来
变量 = 类名() #一般将这个变量称为是对象,本质,变量中保存的是对象的引用地址
2.1.3 调用类中的方法
由类创建的对象,可以调用类中的方法
语法:
对象.方法名()
案例:
需求:小猫爱吃鱼,小猫要喝水
类的设计:
类名:猫(Cat)
属性:暂无
方法:吃鱼(eat),喝水( drink )
####简单类 不带属性的类
class Cat:
def eat(self): # self 暂时不管
print("小猫爱吃鱼")
def drink(self):
print("小猫要喝水")
# 创建对象
Tom = Cat()
# 通过对象 调用类中的方法
Tom.eat() #小猫爱吃鱼
Tom.drink() #小猫要喝水
2.2 self参数
1,参函数的语法上来看,self 是形参,名字可以任意的变量名,只是我们习惯性叫self
2,特殊点: self是一个普通的参数,按照函数的语法,在调用的时候,必须传递实参值,(没有给实参是什么原因)原因,是Python解释器自动的将调用这个方法的对象作为参数传递给self
所以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 就是谁
2.3 属性
- 属性表示事物的特征
- 可以给对象添加属性 或者获取对象的属性值.
- 给对象添加属性:
对象.属性名=属性值 #添加或者修改 - 获取对象的属性值:
对象.属性名 - 在方法中操作属性(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()
blue_cat=Cat()
print(f"blue:{id(blue_cat)}")
blue_cat.name='蓝猫'
blue_cat.eat() # blue_cat 调用 self 就是 blue_cat
练习:
Cat添加属性姓名,年龄
eat方法中打印输出小猫xx, Xx岁爱吃鱼
class Cat:
def eat(self): # self 调用这个方法的对象
print(f"self:{id(self)}")
print(f"小猫{self.name},{self.age}岁 爱吃鱼")
# 创建对象
Tom = Cat()
# 给 Tom 对象提添加 name 属性
Tom.name = '汤姆'
Tom.age = 10
print(Tom.name)
Tom.eat()
魔法方法
在Python中存在一类方法,以两个下划线开头,两个下划线结尾,在满足某个条件的情况下,会自动调用,这一类方法称为是魔法方法
怎么学习:
1,什么情况下会自动调用(自动调用的时机)
2,应用场景
3,注意事项
2.4 初始化方法 __init__
【重点】
1,调用时机
在创建对象(为对象在内存中 分配空间)之后,会自动调用。
2,应用场景
初始化对象,给对象添加属性
3,注意事项
— 不要写错
— 如果属性是会变化的,则可以将这个属性的值作为参数传递,在创建对象的时候,必须传递实参值
-
这个初始化方法就是
__init__
方法,__init__
是对象的内置方法 -
这个方法是专门用来定义一个类具有哪些属性的方法!
-
注意:初始化方法就是指的
__ init__
()方法,创建对象的时候会自动调用,用来定义类具有哪些属性 -
在初始化方法中增加对象属性
-
如果希望在创建对象的同时,就设置对象的属性:
1、把希望设置的属性值,定义成_ jinit_ 方法的参数
2、在方法内部使用self.属性=形参接收外部传递的参数
3、在创建对象时,使用类名(属性1,属性2…) 调用
-
class Cat:
def __init__(self,name): #
print("我是init方法,我被调用了") # 验证使用,正式代码不需要
self.name= name
def eat(self):
print(f"{self.name} 爱吃鱼")
# init方法创建对象之后会自动调用
# 1会 2不会
# Cat # 2不是创建对象
# Cat() # 1因为是创建对象
# tom = Cat #2.不是创建对象,即tom也是类
# blue = Cat() # 1创建对象
# b = blue # 2.不是创建对象。只是引用的传递
# t = tom() # 1, tom 已经是类,类名() 就是创建对象
### 当属性是动态变化的时候,可以使用传参
blue_cat=Cat('蓝猫')
blue_cat.eat()
pink_cat=Cat('粉猫')
pink_cat.eat()
总结:
作用:初始化对象。
注意:
1.__init__()方法,在创建一个对象时默认被调用,不需要手动调用。
2.__init__(self) 中的self参数,不需要开发者传递,python解释器会自动把当前的对象引用传递过去。
2.5 内置函数和方法
序号 | 方法名 | 类型 | 作用 |
---|---|---|---|
1 | dir | 函数 | 可以查看对象内的所有属性及方法 |
2 | __str__ | 方法 | 返回对象的描述信息,print 函数输出使用 |
2.5.1 __str__
方法【重点】
1,调用时机
使用print(对象) 打印对象的时候,会自动调用;如果想要自定义打印对象变量时的信息,则可以使用__str__
方法。
- 如果没有定义
__str__
方法, 默认打印的是 对象的引用地址 - 如果定义
__str__
方法 ,打印的是 方法的返回值
2,应用场景
使用print(对象) 打印输出对象的属性信息
3,注意事项
必须返回一个字符串!
"""
定义Cat类,包含属性name 和oge, 打印对象的时候,可以输出对象的姓名和年龄
类型:Cat
属性:name、age
方法:__str__,__init__
"""
class Cat:
def __init__(self,name,age):
self.name=name # 添加 name 属性
self.age=age # 添加 age 属性
def __str__(self):
return f"姓名:{self.name},年龄:{self.age}"
# 创建对象
tom = Cat('汤姆',3)
print(tom)
# 不定义 __str__ 方法时,输出的结果 <__main__.Cat object at 0x00000135479265E0> 是无效的
# 定义 __str__ 后的输出结果 姓名:汤姆,年龄:3
2.5.2 dir()函数【了解】
dir(对象变量)
作用:可以查看对象内的所有属性及方法
注意:dir()函数不具备输出功能,需要和print()函数配合使用
三、面向对象的三大封装
3.1 封装
根据需求将属性和方法封装到一个抽象的类中【二学习的就是封装】
概念:
- 根据需求将属性和方法封装到一个抽象的类中的过程即为封装
- 外界使用类创建 对象,然后让对象调用方法
- 对象方法的细节都被 封装 在类的内部
3.1.1 封装案例
封装:根据要求将属性和方法定义到类中(定义类)
案例一 :小明爱跑步
需求:
●小明体重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):
self.weight -=0.5
print(f"{self.name} 跑步,体重减少 0.5kg")
def eat(self):
self.weight +=1
print(f"{self.name} 吃东西,体重增加 1kg")
if __name__ == '__main__':
# 创建对象
xm=Person('小明',56.0)
print(xm)
xm.run()
print(xm)
xm.eat()
print(xm)
zs=Person('张三',67.0)
print(zs)
zs.run()
print(zs)
zs.eat()
print(zs)
案例二 :登录
需求:进入某Web项目登录页面,输入用户名、密码、验证码之后登录系统
要求:模拟实现登录操作,输出每一步的登录信息
类名:LoginPage
属性:username,password,verify_code
方法:login
# 代码实现
class LoginPage:
def __init__(self,username,password,verify_code):
self.username=username
self.password=password
self.verify_code=verify_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
方法:
三个家具对象 类设计的时候不用管
席梦思(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 家具对象(传参)
# 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)
3.2 继承【重要】
说明:如果多个类中存在相同的代码逻辑,则可以考虑将相同逻辑的代码抽取封装到父类中,再通过继承关系,直接实例化子类对象并调用父类中的方法使用即可,进而可以避免反复编写相同逻辑的代码
1,继承描述的是类与类之间的关系 is … a,不能盲目使用继承。
2,继承的好处:减少代码冗余,重复代码不需要多次书写,提高编程效率
注意:在继承关系中, 子类可以拥有父类的所有方法和属性
语法:
# class 类A(object):
# class 类A():
class类A: # 默认继承object类,object 类Python中最原始的类
pass
class类B(类A): # 就是继承,类B 继承类A
pass
#类A:父类 或 基类(超类)
#类B:子类 或 派生类
#子类继承父类之后,子类对象 可以直接使用 父类中的属性和方法,不需要再次开发
#子类中应该根据职责,封装 子类特有的 属性和方法
继承的专业术语:
- A类是 B 类的子类, B类是 A 类的父类, A类从B 类继承
- A类是 B 类的派生类,B类是 A 类的基类,A类从B 类派生
继承的传递性
说明:
-
C 类从 B 类继承, B类又从 A 类继承
-
那么 C 类就拥有 B 类和 A 类的所有属性和方法
结论:子类拥有父类以及父类的父类中封装的所有属性和方法
继承案例一:
# 1.定义动物类,动物有姓名和年龄属性,具有吃和睡的行为
class Animal:
def __init__(self,name,age):
self.name=name
self.age=age
def __str__(self):
return
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(self):
print(f"{self.name} 看门")
# 4.定义哮天犬类,哮天犬类具有狗类的所有属性和方法,并且具有飞的特殊行为
class Xdog(Dog):
def fly(self):
print(f"{self.name} 会飞")
if __name__ == '__main__':
pig=Animal('佩奇',10)
pig.eat()
pig.sleep()
cat=Cat('黑猫',9)
cat.eat() # 调用父类animal中的方法
cat.sleep() # 调用父类animal中的方法
cat.catch() # 调用自己类的方法
dog = Dog('狗',6)
dog.eat()
dog.sleep()
dog.look()
xdog = Xdog('哮天犬', 3)
xdog.eat()
xdog.sleep()
xdog.look()
xdog.fly()
继承具有传递性: C 继承 B , B 继承 A,C 可以使用 A 类中的属性和方法
对象调用方法的顺序: 对象.方法名()
1,会现在自己的类中查找,找到直接使用
2, 没有找到去父类中查找,找到直接使用
3,没有找到,在父类的父类中查找,找到直接使用
4,没有找到,...
5,直到object类,找到直接使用,没有找到,报错
3.3 方法的重写(override)
说明:当父类中的方法实现不能满足子类需求时,可以对父类中的方法进行重写
1,什么是重写?
重写是在子类中定义了和父类中名字一样的方法,
2,重写的原因?为什么重写?
父类中的代码不能满足子类对象的需要
3,重写的方式
3.1覆盖式重写
3.2 扩展式重写
3.3.1 覆盖式重写
父类中的功能全部不要,直接在子类中定义和父类中方法名字一样的方法接口,直接书写新的代码。
应用场景:
- 如果在开发中,父类的方法实现和子类的方法实现,完全不同
- 就可以使用覆盖的方式,在子类中重新编写父类的方法实现
实现方式:相当于在子类中 定义了一个 和父类同名的方法并且实现
注意:
- 重写之后,在运行时, 只会调用子类中
- 重写的方法,而不再会调用父类封装的方法
class Dog:
def brak(self):
print("汪汪叫。。。。")
class Xdog(Dog):
# 需要哮天犬 嗷嗷叫,父类中的bark 方法,不能满足子类对象的需要,覆盖式重写
def brak(self):
print("嗷嗷叫...")
pass
if __name__ == '__main__':
xdog=Xdog()
xdog.brak()
3.3.2 扩展式重写
父类中的功能还需要,只是添加了新的功能
方法:
1、先在 子类中定义 和 父类中名字相同的方法
2、在子类的代码中 使用 super().父类方法名() 调用父类中的功能
3、书写新的功能
应用场景:如果子类中重写父类的方法时,需要包含父类中方法的实现,则可以考虑使用扩展式
关于super:
● 在Python 中 super 是一个 特殊的类
● super() 就是使用 super 类创建出来的对象
● 最常使用的场景就是在 重写父类方法时,调用 在父类中封装的方法实现,
class Dog:
def brak(self):
print("汪汪叫。。。。")
class Xdog(Dog):
# 需要哮天犬 嗷嗷叫,父类中的bark 方法,不能满足子类对象的需要,覆盖式重写
def brak(self):
# 调用父类中的功能
super().brak()
print("嗷嗷叫...")
pass
if __name__ == '__main__':
xdog=Xdog()
xdog.brak()
3.4 多态【了解】
多态:不同的子类对象调用相同的父类方法,产生不同的执行结果
-
多态可以增加代码的灵活度
-
以 继承和 **重写父类方法 **为前提
-
是调用方法的技巧,不会影响到类的内部设计
-
注意:
●在Python中 可以为一个变量赋值为不同类型的对象,所以在代码中多态体现不够明显
●在自动化测试脚本几乎应用不到,了解多态即可
案例:
1.在Dog类中封装方法game
普通狗只是简单的玩耍
2.定义XiaoTianDog继承自Dog,并且重写game方法
哮天犬需要在天.上玩耍
3.定义Person类,并且封装一个和狗玩的方法
在方法内部,直接让狗对象调用game方法
class Dog:
def game(self):
print("狗在玩耍。。。")
class XTQ(Dog):
def game(self):
print("哮天犬在天上玩耍....")
class Person:
def play_with_dog(self,dog):
"""dog 是狗类或者其子类的对象 """
print('人和狗在玩耍....',end='') #end=''可以去除换行
dog.game()
if __name__ == '__main__':
dog1 = Dog()
xtq=XTQ()
xw = Person()
xw.play_with_dog(dog1)
xw.play_with_dog(xtq)
#人和狗在玩耍....狗在玩耍。。。
#人和狗在玩耍....哮天犬在天上玩耍....
四、面向对象其他语法
在Python中,定义类的时候,可以给 属性和方法设置 访问权限,即规定在什么地方可以使用.
权限一般分为两种:公有权限、私有权限
说明:当属性和方法只需要在类定义内部使用时,就可以使用私有属性和私有方法
特点:在类定义外部,无论是通过类对象还是实例对象均无法获取私有属性和调用私有方法
4.1 私有权限和公有权限
4.1.1 公有属性
- 定义:直接定义的属性和方法就是公有的
- **特点:**可以在任何地方访问和使用,只要有对象就可以访问和使用
4.1.2 私有属性
-
定义:
1,只能在类内部定义(class 关键字的缩进中)
2,只需要在 属性名 或者 方法名 前边 加上两个 下划线,这个方法或者属性就变为私有的
-
特点:私有 只能在当前类的内部使用.不能在类外部和子类直接使用
-
语法:
- 1>私有属性:_ 属性名
- 2>私有方法: _方法名()
-
应用场景
一般来说, 定义的 属性 和 方法 都为公有的.
某个属性,不想在外部直接使用,定义为私有
某个方法,是内部的方法(不想在外部使用),定义为私有 -
注意:在继承关系中,父类中.的私有属性和私有方法,子类同样无法获取和调用
""" 定义人类,name 属性 age 属性(私有) """
class Person:
def __init__(self,name,age):
self.name=name # 公有
self.__age=age # 公有 --》 私有 在属性名前加上两个下划线
def __str__(self): # 公有方法
return f"{self.name} \t {self.__age}"
# 想要修改私有属性,就定义一个公有方法 调用私有属性
def set_age(self,age): # 定义公有方法,修改私有属性
if age<0 or age>100:
print("提供的年龄信息不对")
return
self.__age=age
if __name__ == '__main__':
xw = Person('小王',19)
print(xw)
xw.__age=1000 # 添加一个公有属性 __age
print(xw)
xw.set_age(45)
print(xw)
4.2 对象的划分
Python 中一切皆对象
4.2.1 类对象
类对象 就是 类,就是使用 class 定义的类
在代码执行的时候,解释期会自动的创建.
作用:
1,使用类对象创建实例对象
2, 存储一些类的特征值(类属性)
特点:
1.在内存中,类对象只有一份,类对象可以拥有自己的属性和方法,分别为类属性和类方法
2.可以使用:类名.类属性和类名.类方法()方式获取类属性和调用类方法
4.2.2 实例对象
1,创建对象也称为实例化,所以 由类对象(类) 建的对象 称为是实例对象,简称实例
2,一般来说,没有特殊强调,我们所说的对象 都是指 实例对象(实例)
3,实例对象 可以保存实例的特征值 (实例属性)
4,就是使用 类名() 创建的对象
4.3 属性的划分
使用 实例对象.属性 访问 属性的时候,会先在 实例属性中查找,如果找不到,去类属性中查找,找到就使用,找不到,就报错
即:每个实例对象都有可能访问类属性值(前提,实例属性和类属性不重名)
4.3.1 实例属性
-
概念:是每个实例对象 具有的特征(属性),每个实例对象的特征
-
定义:般都是在 init 方法中,使用 self.属性名 = 属性值 来定义
-
特征(内存):每个实例对象 都会保存自己的 实例属性,即内存中存在多份
-
访问和修改
#可以认为是通过self
实例对象.属性 = 属性值 # 修改
实例对象.属性 # 访问
4.3.2 类属性
-
概念:是类对象具有的 特征,是整个类的特征,不会用于记录 具体对象的特征
-
定义:一般 在类的内部(class 缩进中),方法的外部(def 的缩进外部)定义的变量
-
特征(内存):只有类对象保存一份,即在内存中只有一个
-
访问和修改
#即通过类名
类对象.属性 = 属性值
类对象.属性
-
注意:类属性被该类的所有对象所共享!
-
什么时候定义类属性?
1、代码中使用的属性基本.上都是实例属性即都通过self定义.2、当某个属性值描述的信息是整个类的特征(这个值变动,所有的这个类的对象这个特征都会发生变化)
案例:
1.定义一个工具类
2.每件工具都有自己的name
3.需求一知道使用这个类,创建了多少个工具对象?
#类名: Tools
#属性: name(实例属性) count(类属性)
#方法: init 方法
class Tools:
# 定义类属性 count,记录创建对象的个数
count =0
def __init__(self,name):
self.name=name # 实例属性,工具的名字
# 修改类属性的值
Tools.count+=1
if __name__ == '__main__':
# 查看 创建对象的个数
print(Tools.count) # 查看类属性
tool1 = Tools('锤子')
print(Tools.count)
tool2 = Tools('扳手')
print(tool1.count)
print(tool2.count)
4.4 方法的划分
4.4.1 实例方法 【知道】
- 定义时机:如果方法中需要使用实例属性,则这个方法必须 定义为实例方法
- 定义
#直接定义的方法就是实例方法
class 类名:
def 方法名(self):
pass
- 参数:参数一般写作self, 表示的是实例对象
- 调用:实例对象.方法名()
4.4.2 类方法【重要】
- 定义时机:如果方法中不需要使用实例属性,但需要使用类属性,则这个方法可以 定义为类方法(建议)
- 定义
#定义类方法,需要在方法名上方书写@classmethod , 即使用@classmethod 装饰器装饰
class 类名:
@clas smethod
def 方法名(cls):
pass
- 参数:一般写作 cls, 表示类对象,即类名,同样不需要手动传递, Python解释器会自动传递
- 调用
#方法一
类名.方法名()
#方法二
实例对象.方法名()
4.4.3 静态方法【了解】
- 定义时机:方法中即不需要使用实例属性,也不需要使用类属性,可以 将这个方法定义为静态方法
- 定义
# 定义静态方法,需要使用装饰器@staticmethod 装饰方法
class 类名:
@staticmethod
def 方法名():
pass
- 参数:静态方法,对参数没有要求,一般没有
- 调用
#方法一
类名.方法名()
#方法二
实例对象.方法名()
class Tools:
# 定义类属性 count,记录创建对象的个数
count =0
def __init__(self,name):
self.name=name # 实例属性,工具的名字
# 修改类属性的值
Tools.count+=1
@classmethod
def show_tool_count(cls): # cls 就是类对象,类名
return cls.count
if __name__ == '__main__':
# 查看 创建对象的个数
print(Tools.show_tool_count())
tool1 = Tools('锤子')
print(tool1.show_tool_count()
应用场景:
说明:在后期的自动化测试过程中,在某些些业务场景下,需要保证生成的对象始终只有一一个时,就可以使用类对象及类属性和类方法
好处:简化方法的调用步骤(无需实例化对象,直接通过类名.方法名即可调用)
方法综合案例:
需求:
1.设计一个Game类
2.属性:
●定义一个top_score类属性->记录游戏的历史最高分
●定义一个player_name实例属性->记录当前游戏的玩家姓名
3.方法:
●静态方法show_help() ->显示游戏帮助信息
●类方法show__top_score()-> 显示历史最高分
●实例方法start_game() ->开始当前玩家的游戏
步骤:
使用随机数生成 10-100 之间数字 作为本次游戏的得分
由打印本次游戏等分:玩家 xxx 本次游戏得分000
和历史最高分进行比较,如果比历史最高分高,修改历史最高分
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):
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('小明')
Game.show_help()
player.start_game()
Game.show_top_score()