【python面向对象】封装(面试题常考)

【python面向对象】封装(面试题常考),第1张

本章节的内容常常在面试题中出现,大家根据本文的思路可以很好的掌握。

文章目录
  • 封装浅层次
    • 一、使用方法,封装变量
    • 二、使用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 ,封装变量
"""
    使用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:限定类创建的对象只能有固定的实例变量。
  • 设计角度:
    ----分而治之:将大的需求分解为多个类,每个类负责一个职责。
    ----变则疏之:遇到变化点单独封装为一个类。
    ----高内聚∶一个类有且只有一个发生变化的原因。
    ----低耦合:类与类的关系松散。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/868367.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-13
下一篇 2022-05-13

发表评论

登录后才能评论

评论列表(0条)

保存