Python面向对象-封装

前言

在 Python入门基础中,可能有些知识点没听懂。听,你不一定能完全听懂,但是还是那件事,不放弃,不抛弃,一个点听不动,好,就是那一个点听不懂。从战略上要蔑视那一个点,继续往下走......最后,总体上的胜利就是成功了。
知识不要纠结一个点,人生亦是如此。认真对待每一个过程,但是不要纠结过不去。

面向过程

关注过程(细节) “干”

面向对象

关心解决问题的人 “找”
(1)识别对象,找人
(2)分配职责,干活 (行为 => 数据)
(3)建立交换,调用

面向对象设计过程例子:

面向对象设计过程例子

理解图

面向对象设计:先有具体对象,再从具体对象抽象出类。

面向对象设计
  • OOA: 面向对象分析
  • OOD: 面向对象设计
  • OOP: 面向对象编程
类与对象
  • 类: 抽象的概念
    数据成员:
    行为成员:
    如何划分“类”?
    两个字“行为”, 干的事情不同 (函数/方法 不同)
  • 对象: 具体的事物
    数据成员:
    行为成员:
    对象与对象有什么不同?
    数据不同,我们都知道“对象”内存空间只存储了“数据成员”
"""
练习1: 面向对象基础语法

"""


class Wifi:
    # 数据成员
    def __init__(self, name, sex):
        # self 是调用当前方法的对象地址
        self.name = name  # 创建实例变量
        self.sex = sex

    # 行为成员
    def play(self):
        print(self.name + "玩耍") # 调用实例变量


# 创建对象,实际在调用 __init__ 方法
w01 = Wifi("莉莉", "女")  # 自动将对象地址传入方法
w01.play()  # 自动将对象地址传入方法


创建实例内存图
实例成员与类成员

也称为实例变量与类变量

  • 实例变量
    练习对象的数据成员修改:
    实例成员也就是对象成员,实例成员包括两种:实例变量 + 实例方法
  • 实例变量语法
    定义:只要遵循 对象.变量名 就是在定义实例变量:
#(1)首次通过对象创建后赋值。(不鼓励)
w01 = Wife()
w01.name = "小张"   # 这种语法可以,但是不鼓励!!!
#(2)通常做法是构造函数(__init__)中创建。
def __init__(self, name)
      self.name = name
#  (3) 每个对象存储一份,通过对象地址调用
  • 实例方法
    实例方法表示对象的行为。同一个方法,操作不同的数据。
    无论创建多少个对象,方法都只有一份,并且被所有对象共享
类对象数据成员修改内存图
  • 类成员
    类成员包括: 类变量 + 类方法
    重点,类变量在方法区共用,对象变量独自开辟一个变量内存

    类变量成员内存图

  • 语法
    定义:在类中,方法外定义的变量都叫做“类变量”。
    class 类名:
    变量名 = 表达式
    调用:类名.变量名
    不建议通过对象访问类变量

  • 作用
    只存储一份在类中,被所有对象共享。

  • 类方法
    定义:
    @classmethod
    def 方法名称(cls, 参数列表)

"""
练习4: 实例变量与类变量

"""
class ICBC:
    # 定义“类变量”,类共用的变量
    total_money = 1200000

    # 定义类方法
    @classmethod
    def get_total_money(cls):
        print("总行还剩余:%d 元" % cls.total_money)

    # 定义类实例构造函数
    def __init__(self, name, money):
        self.name = name  # 定义“实例变量”
        self.money = money
        ICBC.total_money -= money  # 调用“类变量”,直接用类名

    # 定义实例方法
    def print(self):
        print("%s银行存款为:%d" % (self.name, self.money))  # 调用“实例变量”


bank01 = ICBC('曹操分行', 100000)
bank01.print()
bank02 = ICBC('刘备分行', 20000)
bank02.print()
bank03 = ICBC('孙权分行', 80000)
bank03.print()

ICBC.get_total_money()

  • 类静态方法
    定义:
    class 类名
    @staticmethod
    def 静态方法名
    方法体
    作用:将函数移入类中,函数既不属于类方法,又不属于对象方法,即可以定义为类静态方法。
class Vector:
    """
        二维向量
        可以表示位置/方向
    """

    def __init__(self, x, y):
        self.x = x
        self.y = y

    # 静态方法:表示左边方向
    @staticmethod
    def left():
        return Vector(0, -1)

    # 静态方法:表示右边方向
    @staticmethod
    def right():
        return Vector(0, 1)
封装
  • 从数据角度讲,将一些基本数据类型复合成一个自定义类型
    或者说:“将多个变量封装到一个自定义类中”
    封装数据():
    例如: 老婆(姓名,年龄,性别)
    敌人(姓名,血量,攻击力,防御力)
    二维向量 (x, y)
    面向方法,只能就叫“存储数据”,例如,字典、列表。
    封装数据(类)好处:可以用一个类名来表示你封装后的产物,代码结果清晰,事务更加明确。
    优势:更符合人类的思考方式。
    将数据与对数据的操作整合在一起。

  • 从行为角度讲,类向外提供必要(public)的功能,隐藏(private)实现的细节。

封装行为:例如,二维列表助手类(获取多个元素)
向量(向左,向右.....)
好处:以“模块化”的方式进行编程(类似一个函数只做一件事情),一个大的需求,需要分而治之。我们可以不用理会一个“模块”内部是怎么做的,只需要知道怎么用就可以,把模块串联起来即可。可以集中精力设计、组织、指挥多个类协调工作。

  • 私有成员
    做法: 命名使用双下划线开头。只是一种规定,实际还是可以访问到。
    def __私有方法
    __私有变量

重点:这里因为外层已经把 y 定义为类变量了,self.y = property 对象, 9999 赋值给 property 对象
8假如没有类变量 y (或者 类变量 y = 1000),这时 self.y 就属于 init 方法内部变量
self.y 关键在于看看它本身是什么

"""
练习10:封装练习 - 私有成员 - property
"""
class MyClass:

    def __init__(self):
        # 重点:这里因为外层已经把 y 定义为类变量了,self.y = property 对象, 9999 赋值给 property 对象
        # 假如没有类变量 y (或者 类变量 y = 1000),这时 self.y 就属于 __init__ 方法内部变量
        # self.y 关键在于看看它本身是什么
        self.y = 9999

    def get_y(self):
        return self.__y

    def set_y(self, value):
        self.__y = value

    y = property(get_y, set_y)


my01 = MyClass()
print(my01.__dict__)
property内存图
  • 封装 - 只读,只写属性


    封装 - 只写属性

    封装 - 只读属性
  • property 私有属性
    property 私有属性可以让对象可以像操作“公开的实例变量”一样处理“私有属性” (2 个方法), 即是两个公开的属性,保护一个私有的变量
    --@property 负责读取,@属性名.setter 负责写入
    --只写:属性名=property(None, 写入方法名)
  • property 私有属性定义:
    @property
    def name(self):
    return self.__name

@name.setter
def name(self, value)
self.__name = value

  • 使用 @property 封装私有变量
class Enemy:

    def __init__(self, name, attack, blood):
        self.name = name
        self.attack = attack
        self.blood = blood

    @property
    def attack(self, value):
        self.__attack = value

    @attack.setter
    def attack(self, value):
        if 10 <= value <= 50:
            self.__attack = value
        else:
            raise ValueError("攻击力范围错误")

    @property
    def blood(self):
        return self.__blood

    @blood.setter
    def blood(self, value):
        if 100 <= value <= 200:
            self.__blood = value
        else:
            raise ValueError("血量范围错误")


enemy01 = Enemy('骷髅头', 50, 100)
enemy01.blood = 120
print(enemy01.__dict__)
从设计角度讲封装的思想(重点)

(1)分而治之(总思想:分
---将一个大的需求分解为许多类,每一个类处理一个独立的功能。
---拆分的好处:便于分工,便于复用,可扩展性强。
---思想指导:活字印刷术
(2)变则疏之(对第一点补充,“分”的“度”,“点”在哪?
---分而治之,分得有一个“度”,什么时候该拆分成一个小的分类,就看它会不会变化,会变化就拆分成一个小的分类。
---变化的地方独立封装,避免影响其他的类
---分得精髓在乎一个“变”
(3) 高内聚(审查评价评价上面两步骤做得好吗?)
---内聚:一个类的内部干了多少件事
---高:一个类干的事情都能凝聚到一个点,叫“高”
---高内聚:类中的各个方法都在完成一项任务(单一职责)
---高内聚:评价一个类的内部是否都只做“一件事情”
---若不是,重构,提出去!!!

(4)低耦合 (讲的是类与类之间的关系,十有八九在说设计模式
---类与类的关联性与依赖度要低

例如:硬件高度集成化,又要可插拔
最高的内聚莫过于类中只有1个方法,将会导致高内聚高耦合。
最低的耦合莫过于类中包含所有的方法,将会导致低耦合低内聚。
所有高内聚,低耦合讲究一个平衡

  • slots: 限制类创建的对象只能有固定的类实例变量

体会: 对象区分数据的不同

"""
练习12:封装练习 - 体会变化点是数据的不同还是行为的不同

张无忌   教    赵敏   九阳神功
赵敏     教    张无忌  化妆
张无忌   上班  挣了    10000
赵敏    上班   挣了    8000

体会: 对象区分数据的不同
"""


class Person:
    def __init__(self, name):
        self.name = name

    def teach(self, other, action):
        print("%s 教 %s %s" % (self.name, other.name, action))

    def work(self, money):
        print("%s 上班,挣了 %d 元" % (self.name, money))


p1 = Person('张无忌')
p2 = Person('赵敏')
p1.teach(p2, '九阳神功')
p2.teach(p1, '化妆')
p1.work(10000)
p2.work(8000)

体会: 类区别行为的不同

"""
练习13:封装练习 - 体会变化点是数据的不同还是行为的不同
玩家(攻击力) 攻击 敌人(血量), 受伤(掉血),还可能死亡(掉装备)
敌人(攻击力) 攻击 玩家(血量), 受伤(掉血/碎屏),还可能死亡
体会: 类区别行为的不同
"""


class Player:

    def __init__(self, atk, hp):
        self.atk = atk
        self.hp = hp

    def attack(self, other):
        print("玩家攻打敌人:")
        other.damage(self.atk)

    def damage(self, atk):
        self.hp -= atk
        if self.hp <= 0:
            self.__death()

    @staticmethod
    def __death(self):
        print("玩家死亡")
        print("游戏结束")


class Enemy:

    def __init__(self, atk, hp):
        self.atk = atk
        self.hp = hp

    def damage(self, atk):
        self.hp -= atk
        print("敌人受伤了:")
        if self.hp <= 0:
            self.__die()

    @staticmethod
    def __die():
        print("敌人死亡")
        print("掉装备")

    def attack(self, other):
        print("敌人攻打玩家:")
        other.damage(self.atk)


player = Player(100, 1000)
enemy = Enemy(10, 200)
player.attack(enemy)
enemy.attack(player)
player.attack(enemy)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,047评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,807评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,501评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,839评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,951评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,117评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,188评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,929评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,372评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,679评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,837评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,536评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,168评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,886评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,129评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,665评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,739评论 2 351

推荐阅读更多精彩内容

  • 面向对象——封装 一、概述 Python面向对象的三大特性:封装、继承和多态。 封装:在类中对数据的赋值、内部调用...
    冬日里的月光阅读 273评论 0 0
  • Python面对对象封装 1.1 面向过程和面向对象 根据操作数据的函数或语句块来设计程序的过程,叫做面向过程编程...
    Newthan阅读 198评论 0 0
  • 封装:将一堆零碎的东西封箱装起来! 为什么需要封装?封装的作用和含义? 比如:①我要看电视,只需要按一下开关和换台...
    云Shen不知处阅读 298评论 3 0
  • 所谓封装就是对外部世界隐藏对象的工作细节 今天老师讲了四个例子,由简入繁,由浅入深详细分析了封装的意义及用法 例1...
    恶人未满阅读 216评论 0 0
  • 封装演示01 前面两种封装方法对于数据的安全保护不够强烈,应为对象可以直接通过objeect.name='like...
    maxlike阅读 318评论 0 0