文章目录本章节的内容常常在面试题中出现,大家根据本文的思路可以很好的掌握。
- 封装浅层次
- 一、使用方法,封装变量
- 二、使用property (读取方法,写入方法),封装变量
- 三、使用property ,封装变量
- 四、@property讲解
- 封装深层次
- 一、封装设计思想
- 课后练习1
- 课后练习2
- 二、__slots__讲解
- 总结
封装浅层次
数据角度讲,将一些基本数据类型复合成一个自定义类型。
封装数据:
敌人(姓名,血量,攻击力,防御力)
二维向量(x,y)
优势:
1、更符合人类的思考方式。
2、将数据与对数据的 *** 作整合在一起。
行为角度讲,向类外提供必要的功能,隐藏实现的细节。
封装行为:
二维列表助手类DoublelListHelper(获取多个元素get_elements
向量(向左╱向右,求模长,求方向等)
优势:以”模块化的方式进行编程,更可以集中精力设计、组织、指挥多个类协同工作。
一、使用方法,封装变量#使用方法,封装变量
class Wife:
def __init__(self,name,age, weight):
self.name = name
# 本质:障眼法
#实质:实际将变量名改为︰_类名__age
# self.__age = age
self.set_age(age)
# self.__weight = weight
self.set_weight(weight)
# 提供公开的读写方法
def get_age(self):
return self.__age
def set_age(self,value):
if 21<= value <= 31:
self.__age =value
else:
raise ValueError("我不要")
# 提供公开的读写方法
def get_weight(self):
return self.__weight
def set_weight(self,value):
if 40<= value <= 80:
self.__weight =value
else:
raise ValueError("我不要")
"""
#不建议下面的做法
w01 = Wife("铁锤公主",87,87)
#重新创建了新实例变量(没有改变类中定义的_age)
# w01.__age = 107
#修改了类中定义的私有变量
w01._Wife__age = 107
#__dict__:python内置变量,存储对象的实例变量
print(w01.__dict__)
"""
w01 = Wife("铁锤公主",30,57)
w01.set_age(25)
w01.set_weight(45)
print(w01.get_age())
print(w01.get_weight())
#25
#45
练习:
定义敌人类(姓名,攻击力10–50,血量100–200)
创建一个敌人对象,可以修改数据,读取数据。
class Enemy:
def __init__(self,name,attack,hp):
self.name = name
self.set_attack(attack)
self.set_hp(hp)
def set_attack(self,value):
if 10 <= value <= 50:
self.__attack = value
else:
raise ValueError("不行")
def get_attack(self):
return self.__attack
def set_hp(self,value):
if 100 <= value <= 200:
self.__hp = value
else:
raise ValueError("不行")
def get_hp(self):
return self.__hp
enemy = Enemy("灭霸",20,100)
enemy.set_attack(30)
print(enemy.get_attack())
#30
进阶:
二、使用property (读取方法,写入方法),封装变量"""
使用property (读取方法,写入方法),封装变量。
"""
class Wife:
def __init__(self,name,age, weight):
self.name = name
# self.set_age(age)
self.age = age
# self.set_weight(weight)
self.weight = weight
# 提供公开的读写方法
def get_age(self):
return self.__age
def set_age(self,value):
if 21<= value <= 31:
self.__age =value
else:
raise ValueError("我不要")
#属性 property对象拦截对age类变量的读写 *** 作
age = property(get_age,set_age)
# 提供公开的读写方法
def get_weight(self):
return self.__weight
def set_weight(self,value):
if 40<= value <= 80:
self.__weight =value
else:
raise ValueError("我不要")
#属性 property对象拦截对weight类变量的读写 *** 作
weight = property(get_weight,set_weight)
w01 = Wife("铁锤公主",30,57)
# w01.set_age(25)
w01.age = 25
print(w01.age)
w01.weight = 45
print(w01.weight)
# 25
# 45
练习:改写上面的敌人类
class Enemy:
def __init__(self,name,attack,hp):
self.name = name
self.attack = attack
self.hp = hp
def set_attack(self,value):
if 10 <= value <= 50:
self.__attack = value
else:
raise ValueError("不行")
def get_attack(self):
return self.__attack
attack = property(get_attack,set_attack)
def set_hp(self,value):
if 100 <= value <= 200:
self.__hp = value
else:
raise ValueError("不行")
def get_hp(self):
return self.__hp
hp = property(get_hp,set_hp)
#hp = property(None,set_hp)#只读属性
enemy = Enemy("灭霸",20,100)
enemy.attack= 30
enemy.hp = 120
print(enemy.attack)
print(enemy.hp)
# 30
# 120
内存图:
"""
使用property ,封装变量。
"""
class Wife:
def __init__(self,name,age, weight):
self.name = name
# self.set_age(age)
self.age = age
# self.set_weight(weight)
self.weight = weight
# 提供公开的读写方法
#创建property对象,只负责拦截读取 *** 作
@property
def age(self):
return self.__age
#只负责拦截写入 *** 作
@age.setter
def age(self,value):
if 21<= value <= 31:
self.__age =value
else:
raise ValueError("我不要")
#属性 property对象拦截对age类变量的读写 *** 作
@property
# 提供公开的读写方法
def weight(self):
return self.__weight
@weight.setter
def weight(self,value):
if 40<= value <= 80:
self.__weight =value
else:
raise ValueError("我不要")
w01 = Wife("铁锤公主",30,57)
# w01.set_age(25)
w01.age = 25
print(w01.age)
w01.weight = 45
print(w01.weight)
# 25
# 45
练习:改写敌人类
class Enemy:
def __init__(self,name,attack,hp):
self.name = name
self.attack = attack
self.hp = hp
@property
def attack(self):
return self.__attack
@attack.setter
def attack(self,value):
if 10 <= value <= 50:
self.__attack = value
else:
raise ValueError("不行")
@property
def hp(self):
return self.__hp
@hp.setter
def hp(self,value):
if 100 <= value <= 200:
self.__hp = value
else:
raise ValueError("不行")
enemy = Enemy("灭霸",20,100)
enemy.attack= 30
enemy.hp = 120
print(enemy.attack)
print(enemy.hp)
# 30
# 120
四、@property讲解
公开的实例变量,缺少逻辑验证。私有的实例变量与两个公开的方法相结合,又使调用者的 *** 作略显复杂。而属性可以将两个方法的使用方式像 *** 作变量一样方便。
- 定义:
@property
def name(self):
return self.__name
@name.setter
def name(self,name):
self.__name = name
- 调用:
对象.属性名 = 数据
变量 = 对象.属性名
- 说明:
1、通常两个公开的属性,保护一个私有的变量。
2、 @property负责读取,@属性名.setter负责写入。
3、只写:属性名= property(None,写入方法名)。
设计角度讲
(1)分而治之
- 将一个大的需求分解为许多类,每个类处理一个独立的功能。
- 拆分好处:便于分工,便于复用,可扩展性强。
(2)变则疏之
- 变化的地方独立封装,避免影响其他类。
(3)高内聚(目标一致)
- 类中各个方法都在完成一项任务(单一职责的类)。
(4)低耦合
- 类与类的关联性与依赖度要低(每个类独立)。
例如:【硬件高度集成化,又要可插拔】
"""
封装设计思想
需求︰老张开车去东北
"""
class Person:
def __init__(self,name):
self.name = name
@property
def name(self):
return self.__name
@name.setter
def name(self,value):
self.__name = value
def go_to(self,str_position,type):
"""
去
:param str_position:位置
:param type:方式
"""
print(self.name,"去",str_position)
type.run(str_position)
class Car:
def run(self,str_position):
"""
行驶
:param str_position: 位置
"""
print("汽车行驶到:"+ str_position)
lz = Person("老张")
car = Car()
lz.go_to("东北",car)
# 老张 去 东北
# 汽车行驶到:东北
练习:请以面向对象的思想,描述下列场景:小明在招商银行取钱。(面试题)
class Person:
def __init__(self,name,money):
self.name = name
self.money = money
@property
def name(self):
return self.__name
@name.setter
def name(self,value):
self.__name = value
@property
def money(self):
return self.__money
@money.setter
def money(self, value):
self.__money = value
class Bank:
def __init__(self,name,money):
self.name = name
self.money = money
@property
def name(self):
return self.__name
@name.setter
def name(self,value):
self.__name = value
@property
def money(self):
return self.__money
@money.setter
def money(self, value):
self.__money = value
def withdraw_money(self,person,value):
"""
取钱
"""
self.money -= value
person.money += value
print(person.name,"取了%d钱"%value)
person = Person("小明",0)
bank = Bank("招商银行",100000)
bank.withdraw_money(person,1000)
#小明 取了1000钱
方法在哪个类写,由谁承担便有谁来做
课后练习1请用面向对象思想,描述以下场景∶
张无忌 教 赵敏 九阳神功
赵敏 教 张无忌 化妆
张无忌 上班 挣了 10000
赵敏 上班 挣了 6000
思考∶变化点是数据的不同还是行为的不同。
class Person:
def __init__(self,name):
self.name = name
@property
def name(self):
return self.__name
@name.setter
def name(self,value):
self.__name = value
def teach(self,other,skill):
print(self.name,"教",other.name,skill)
def work(self, money):
print(self.name,"上班挣了%d钱"%money)
person01 = Person("张无忌")
person02 = Person(" 赵敏 ")
person01.teach(person02,"九阳神功")
person02.teach(person01,"化妆")
person01.work(10000)
person02.work(6000)
# 张无忌 教 赵敏 九阳神功
# 赵敏 教 张无忌 化妆
# 张无忌 上班挣了10000钱
# 赵敏 上班挣了6000钱
上面的例子体会∶对象区分数据的不同
课后练习2请用面向对象思想,描述以下场景∶
玩家(攻击力)攻击敌人(血量),敌人受伤(掉血),还可能死亡((掉装备,加分)。
敌人(攻击力)攻击玩家,玩家(血量)受伤(掉血/碎屏),还可能死亡(游戏结束)。
class Player:
def __init__(self,atk,hp):
self.atk = atk
self.hp = hp
def attack01(self,other):
#打的逻辑
print("玩家攻击敌人")
# 通过敌人对象地址﹐调用实例方法。
other.damage02(self.atk)
def damage01(self,value):
print("玩家受伤了")
self.hp -= value
if self.hp <= 0:
self.__death()
# 私有的死亡方法
def __death(self):
# 死亡的逻辑
print("玩家死喽")
print("游戏结束")
class Enemy:
def __init__(self,atk,hp):
self.atk= atk
self.hp = hp
def damage02(self,value):
print("敌人受伤了")
#受伤的逻辑
self.hp -= value
if self.hp <= 0:
self.__death()
# 私有的死亡方法
def __death(self):
# 死亡的逻辑
print("死亡")
print("掉装备")
print("加分")
def attack02(self,other):
print("敌人攻击玩家")
other.damage01(self.atk)
p01 = Player(100,1000)
e01 = Enemy(10,200)
#第一回合
p01.attack01(e01)
e01.attack02(p01)
#第二回合
p01.attack01(e01)
# 玩家攻击敌人
# 敌人受伤了
# 敌人攻击玩家
# 玩家受伤了
# 玩家攻击敌人
# 敌人受伤了
# 死亡
# 掉装备
# 加分
此题心得:当这两个名称重复时,程序会默认调用Int型对象,但Int对象没有什么调用可言,就爆出了这个错误(TypeError: ‘int’ object is not callable解决办法),解决方法也很简单,要么更改变量名,要么更改方法名。
上面的例子体会∶类区别行为的不同
二、__slots__讲解- 作用:限定一个类创建的实例只能有固定的实例变量。
- 语法:
在类中定义
__slots__=(“变量名1”﹐”变量名2”...)
__slots__=("__age")
- 优点:防止用户因错写属性的名称而发生程序错误。
- 缺点:丧失了动态语言可以在运行时为对象添加变量的灵活性。
总结
封装
- 数据角度: 将多个变量封装到一个自定义类中。(优势:符合人类的思考方式;可以将数据与对数据的 *** 作封装到一起)
- 功能角度: 对外提供必要的功能,隐藏实现的细节。
----私有化∶将名称命名为以双下划线开头,内部修改成员名称
---- 属性:对实例变量的保护(拦截读/写 *** 作)
----记住:通过对象地址调用实例成员
----slots:限定类创建的对象只能有固定的实例变量。 - 设计角度:
----分而治之:将大的需求分解为多个类,每个类负责一个职责。
----变则疏之:遇到变化点单独封装为一个类。
----高内聚∶一个类有且只有一个发生变化的原因。
----低耦合:类与类的关系松散。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)