类和对象
1. 类:一个抽象的概念,即生活中的”类别”。
2. 对象:类的具体实例,即归属于某个类别的”个体”。
3. 类是创建对象的”模板”。
– 数据成员:名词类型的状态。
– 方法成员:动词类型的行为。
4. 类与类行为不同,对象与对象数据不同。
语法
定义类
1. 代码
class 类名:
“””文档说明”””
def init(self,参数列表):
self.实例变量 = 参数
方法成员
2. 说明
– 类名所有单词首字母大写.
– init 也叫构造函数,创建对象时被调用,也可以省略。
– self 变量绑定的是被创建的对象,名称可以随意。
创建对象(实例化)
变量 = 构造函数 (参数列表)
实例成员
实例变量
1. 语法
(1) 定义:对象.变量名
(2) 调用:对象.变量名
2. 说明
(1) 首次通过对象赋值为创建,再次赋值为修改.
w01 = Wife()
w01.name = “丽丽”
w01.name = “莉莉”
(2) 通常在构造函数(init)中创建。
w01 = Wife(“丽丽”,24)
print(w01.name)
(3) 每个对象存储一份,通过对象地址访问。
3. 作用:描述某个对象的数据。
4. __dict__:对象的属性,用于存储自身实例变量的字典。
实例方法
1. 语法
(1) 定义: def 方法名称(self, 参数列表):
方法体
(2) 调用: 对象地址.实例方法名(参数列表)
不建议通过类名访问实例方法
2. 说明
(1) 至少有一个形参,第一个参数绑定调用这个方法的对象,一般命名为"self"。
(2) 无论创建多少对象,方法只有一份,并且被所有对象共享。
3. 作用:表示对象行为。
"""
实例成员
实例变量:对象不同的数据
实例方法:对象相同行为
核心逻辑:
对象.?
"""
# 1. 标准写法
class Wife:
def __init__(self, name):
# 创建实例变量:对象.变量名 = 数据
self.name = name
def print_self(self):
print("我叫:", self.name)
def play(self):
print("在玩耍")
# 对象.方法名()
self.print_self()
w01 = Wife("双儿")
w02 = Wife("阿珂")
# 读取实例变量:? = 对象.变量名
print(w01.name)
# 内置实例变量
# -- 获取当前对象所有实例变量
print(w01.__dict__)
w01.play()
w02.play()
# 2. 不建议(实例变量应该由类的定义者决定)
# class Wife:
# pass
#
# w01 = Wife()
# # 创建实例变量:对象.变量名 = 数据
# w01.name = "双儿"
# # 读取实例变量:? = 对象.变量名
# print(w01.name)
# 3. 不建议(实例变量应该直接在init中定义)
# class Wife:
# def __init__(self):
# pass
#
# def func01(self,name):
# # 创建实例变量:对象.变量名 = 数据
# self.name = name
#
# w01 = Wife()
# w01.func01("双儿")
# # 读取实例变量:? = 对象.变量名
# print(w01.name)
dict01 = {}
dict01["name"] = "双儿"
dict01["name"] = "双双"
类成员
类变量
1. 语法
(1) 定义:在类中,方法外定义变量。
class 类名:
变量名 = 表达式
(2) 调用:类名.变量名
不建议通过对象访问类变量
2. 说明
(1) 存储在类中。
(2) 只有一份,被所有对象共享。
3. 作用:描述所有对象的共有数据。
"""
类成员
类变量:大家的数据
类方法:大家的行为
核心逻辑:
类.?
"""
class ICBC:
# 总行的钱
total_money = 1000000
@classmethod
def print_total_money(cls):
print("总行的钱:", cls.total_money)
def __init__(self, name="", money=0):
# 实例变量
self.name = name
# 支行的钱
self.money = money
# 从总行扣除当前支行需要的钱
ICBC.total_money -= money
i01 = ICBC("天坛支行", 100000)
i02 = ICBC("陶然亭支行", 200000)
# print("总行的钱:",ICBC.total_money)
ICBC.print_total_money() # print_total_money(ICBC)
类方法
1. 语法
(1) 定义:
@classmethod
def 方法名称(cls,参数列表):
方法体
(2) 调用:类名.方法名(参数列表)
不建议通过对象访问类方法
2. 说明
(1) 至少有一个形参,第一个形参用于绑定类,一般命名为’cls’
(2) 使用@classmethod修饰的目的是调用类方法时可以隐式传递类。
(3) 类方法中不能访问实例成员,实例方法中可以访问类成员。
3. 作用:操作类变量。
静态方法
1. 语法
(1) 定义:
@staticmethod
def 方法名称(参数列表):
方法体
(2) 调用:类名.方法名(参数列表)
不建议通过对象访问静态方法
2. 说明
(1) 使用@ staticmethod修饰的目的是该方法不需要隐式传参数。
(2) 静态方法不能访问实例成员和类成员
3. 作用:定义常用的工具函数。
"""
静态方法
可以独立存在的工具函数
"""
class Vector2:
"""
二维向量
"""
def __init__(self, x, y):
self.x = x
self.y = y
@staticmethod
def get_right():
return Vector2(0, 1)
@staticmethod
def get_up():
return Vector2(-1, 0)
@staticmethod
def get_left():
return Vector2(0, -1)
list01 = [
["00", "01", "02", "03"],
["10", "11", "12", "13"],
["20", "21", "22", "23"],
["30", "31", "32", "33"],
]
# 位置
pos = Vector2(1, 2)
# 方向
# right = Vector2(0, 1)
right = Vector2.get_right()
# 需求:沿着某个方向移动
pos.x += right.x
pos.y += right.y
print(pos.x,pos.y)
# 练习1:创建向上的静态方法
# 练习2:创建向左的静态方法
# 测试:让某个位置沿着该方向移动
up = Vector2.get_up()
pos.x += up.x
pos.y += up.y
print(pos.x,pos.y)
三大特征
封装
数据角度讲
1. 定义:
将一些基本数据类型复合成一个自定义类型。
2. 优势:
将数据与对数据的操作相关联。
代码可读性更高(类是对象的模板)。
行为角度讲
1. 定义:
类外提供必要的功能,隐藏实现的细节。
2. 优势:
简化编程,使用者不必了解具体的实现细节,只需要调用对外提供的功能。
3. 私有成员:
(1) 作用:无需向类外提供的成员,可以通过私有化进行屏蔽。
(2) 做法:命名使用双下划线开头。
(3) 本质:障眼法,实际也可以访问。
私有成员的名称被修改为:_类名__成员名,可以通过_dict_属性或dir函数查看。
4. 属性@property:
公开的实例变量,缺少逻辑验证。私有的实例变量与两个公开的方法相结合,又使调用者的操作略显复杂。而属性可以将两个方法的使用方式像操作变量一样方便。
(1) 定义:
@property
def 属性名(self):
return self.__属性名
@属性名.setter
def 属性名(self, value):
self.__属性名= value
(2) 调用:
对象.属性名 = 数据
变量 = 对象.属性名
(3) 说明:
通常两个公开的属性,保护一个私有的变量。
@property 负责读取,@属性名.setter 负责写入
只写:属性名= property(None, 写入方法名)
"""
封装
目标:保障数据有效性
原理
1. 私有化数据(不隐藏在类外就可以随意操作,无法进行限制)
2. 提供读取与写入方法(数据验证)
"""
class Wife:
def __init__(self, name="", age=0):
self.name = name
# self.__age = age
self.set_age(age)
def set_age(self, value):
if 22 <= value <= 32:
self.__age = value
else:
raise Exception("我不要")
def get_age(self):
return self.__age
w01 = Wife("双儿", 25)
print(w01.name)
# print(w01.__age) # 不能访问私有变量
print(w01.get_age()) # 通过方法读取数据
"""
封装
目标:保障数据有效性
property 核心逻辑:拦截
1. 创建实例变量
2. 提供读取与写入方法(数据验证)
3. 创建类变量(与实例变量名称相同),存储property对象
"""
class Wife:
def __init__(self, name="", age=0):
self.name = name
# self.set_age(age)
self.age = age
def set_age(self, value):
if 22 <= value <= 32:
self.__age = value
else:
raise Exception("我不要")
def get_age(self):
return self.__age
# property(读取方法,写入方法)
age = property(get_age, set_age)
w01 = Wife("双儿", 25)
print(w01.name)
# print(w01.get_age())
print(w01.age)
"""
封装
目标:保障数据有效性
property 核心逻辑:拦截
1. 创建实例变量
2. 提供读取与写入方法(数据验证)
3. 创建类变量(与实例变量名称相同),存储property对象
"""
class Wife:
def __init__(self, name="", age=0):
self.name = name
self.age = age
@property # age = property(读取方法, None)
def age(self):
return self.__age
@age.setter #
def age(self, value):
if 22 <= value <= 32:
self.__age = value
else:
raise Exception("我不要")
w01 = Wife("双儿", 25)
print(w01.name)
# print(w01.get_age())
print(w01.age)
"""
创建类:敌人类
实例变量:姓名,血量,防御力,攻击力
方法:受伤 - 血量减少
打印自身信息 - 打印所有实例变量
创建敌人列表(3)
-- 定义函数,在敌人列表中找出所有活的敌人
-- 定义函数,在敌人列表中找出攻击力大于50的敌人名称与攻击力
-- 定义函数,在敌人列表中找出防御力最小的敌人
-- 定义函数,在敌人列表中删除血量大于50的所有敌人
-- 定义函数,根据攻击力进行降序排列
体会:
对象.?
"""
class Enemy:
def __init__(self, name="", hp=0, defense=0, atk=0):
self.name = name
self.hp = hp
self.defense = defense
self.atk = atk
def damage(self):
self.hp -= 10
print(self.name, "被攻击,血量减少10", )
def print_self(self):
print("我是%s血量%d防御力%d攻击力%d" % (self.name, self.hp, self.defense, self.atk))
list_enemys = [
Enemy("成昆", 0, 10, 90),
Enemy("玄冥一老", 90, 8, 80),
Enemy("玄冥二老", 95, 9, 95),
]
# 练习1
def find01():
list_result = []
for item in list_enemys:
if item.hp > 0:
list_result.append(item)
return list_result
# 测试
# for item in find01():
# item.print_self()
for item in find01():
item.damage()
# 练习2
def find02():
list_result = []
for item in list_enemys:
if item.atk > 50:
list_result.append((item.name, item.atk))
return list_result
# 测试 11:30
for item in find02():
print(item)
# 练习3
def get_min_by_defense():
min_value = list_enemys[0]
for i in range(1, len(list_enemys)):
if min_value.defense > list_enemys[i].defense:
min_value = list_enemys[i]
return min_value
# 测试
result = get_min_by_defense()
result.damage()
# 练习3 -- 定义函数,在敌人列表中删除血量大于50的所有敌人
def delete_all_by_hp():
count = 0
for i in range(len(list_enemys) - 1, -1, -1):
if list_enemys[i].hp > 50:
del list_enemys[i]
count += 1
return count
# print(delete_all_by_hp())
# 定义函数,根据攻击力进行降序排列
def sort():
for r in range(len(list_enemys) - 1):
for c in range(r + 1, len(list_enemys)):
if list_enemys[r].atk < list_enemys[c].atk:
list_enemys[r], list_enemys[c] = list_enemys[c], list_enemys[r]
sort()
for item in list_enemys:
item.print_self()
"""
创建对象计数器
提示:统计__init__被调用的次数
画出内存图
"""
class Wife:
count = 0
@classmethod
def print_count(cls):
print("总共娶了%d个老婆" % cls.count)
def __init__(self, name=""):
self.name = name
Wife.count += 1
w01 = Wife("")
w02 = Wife("")
w03 = Wife("")
w04 = Wife("")
w05 = Wife("")
w06 = Wife("")
Wife.print_count()
"""
属性练习
创建敌人类
数据:姓名,血量(0--500),攻击力(10,--100)
创建敌人对象,体会拦截的核心逻辑.
"""
class Enemy:
def __init__(self, name="", hp=0, atk=0):
self.name = name
self.hp = hp
self.atk = atk
def set_hp(self, value):
if 0 <= value <= 500:
self.__hp = value
else:
raise Exception("血量超过范围")
def get_hp(self):
return self.__hp
hp = property(get_hp, set_hp)
def set_atk(self, data):
if 10 <= data <= 100:
self.__atk = data
else:
raise Exception("攻击力超过范围")
def get_atk(self):
return self.__atk
atk = property(get_atk, set_atk)
e01 = Enemy("灭霸", 500, 100)
print(e01.name)
print(e01.hp)
print(e01.atk)
e01.a = 9999999