25、面向对象的三大特性——封装、继承、多态

一、面向对象的三大特征

  1. 封装
    1. 封装 <–> 整合
  2. 继承
  3. 多态

一、封装

1. 什么是封装

  • 封装指的就是把数据与功能都整合到一起,听起来是不是很熟悉,没错,我们之前所说的”整合“二字其实就是封装的通俗说法。除此之外,针对封装到对象或者类中的属性,我们还可以严格控制对它们的访问,分两步实现:隐藏与开放接口

2. 隐藏属性

  • 将封装的属性隐藏

1. 如何隐藏: 在属性名前加__前缀, 就会实现一个对外隐藏属性的效果

# 如何隐藏
class Foo():
    x = 1

    def f1(self):
        print('from f1')


f = Foo()
print(f.x)
f.f1()


# 隐藏 加__
class Foo():
    __x = 1

    def __f1(self):
        print('from f1')


f = Foo()
print(f.x)  # 报错找不到x
print(f.__x)  # 报错找不到x

2 为何要隐藏

  1. 隐藏数据属性
    - 将数据隐藏起来就限制了类外部对数据的直接操作,然后类内应该提供相应的接口来允许类外部间接地操作数据,接口之上可以附加额外的逻辑来对数据的操作进行严格地控制
# 开发者
class People():
    def __init__(self, name):
        self.__name = name

    def get_name(self):
        # 通过该接口就可以间接的访问到名字属性
        print(self.__name)
        return self.__name

    def set_name(self, val):
        # 通过该接口改变名字属性
        if type(val) is not str:
            print('小垃圾, 必须传入字符串类型')
        self.__name = val


# 使用者
obj = People('ee')
obj.get_name()
obj.set_name('zpp')
obj.set_name(123)
  1. 隐藏函数属性、方法属性
    - 目的的是为了隔离复杂度, 只在内部用, 例如ATM程序的取款功能,该功能有很多其他功能组成,比如插卡、身份认证、输入金额、打印小票、取钱等,而对使用者来说,只需要开发取款这个功能接口即可,其余功能我们都可以隐藏起来
# 隐藏 加__
class Foo():
    __x = 1  # 变形成 _Foo__x

    def __f1(self):
        print('from f1')
	def f2(self):
        print(self.__x)
        print(self.__f1())


f = Foo()
# print(f.x)  # 报错找不到x
# print(f.__x)  # 报错找不到x

print(Foo.__dict__)
print(Foo._Foo__x)  # 不要这么做
print(f._Foo__f1)  # 不要这么做

3 该隐藏需要注意的问题

  1. 在类外部无法直接访问双下滑线开头的属性,但知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如Foo._A__N,所以说这种操作并没有严格意义上地限制外部访问,仅仅只是一种语法意义上的变形。
  2. 这种隐藏对外不对内, 因为__开头的属性会在检查类体语法时统一发生变形
  3. 这种变形操作, 只在检查语法的时候发生一次,

二、继承

1. 什么是继承

  • 继承是一种创建新类的方式, 新建的类可成为子类或者派生类, 父类又可称为基类或超类
# 封装
class Parent1:
    pass


class Parent2:
    pass


class Sub1(Parent1): # 单继承
    pass


class Sub2(Parent1, Parent2):  # 多继承
    pass


# 查看继承谁
print(Sub1.__bases__)
print(Sub2.__bases__)
print(Parent2.__bases__)
print(Parent1.__bases__)
  • 需要注意的是: Python支持多继承, 在Python中, 新建的类可以继承一个或多个父类
  • Python多继承:
    • 优点:子类可以同时遗传多个父类的属性, 最大限度的重用代码
    • 缺点:
      - 违背人的思维习惯: 继承表达的是一种什么“是”什么的关系
      - 代码可读性会变差
      - 不建议使用多继承, 扩展性变差, 有可能给会引发可恶的菱形问题, 扩展性变差
    • 如果真的涉及到一个子类必须要重用多个父类的属性, 应该使用Mixins

2. 为什么要用继承

  • 来解决类与类之间的代码冗余问题

2.1 单继承下的属性查找

class Foo():
    def f1(self):
        print('Foo.f1')

    def f2(self):
        print('Foo.f2')
        self.f1()  # obj.f1()


class Bar(Foo):
    def f1(self):
        print('Bar.f1')


obj = Bar()
obj.f2()  # 打印Foo.f2 Bar.f1


# 需求: 如何让她打印自己的f1
class Foo():
    def __f1(self):
        print('Foo.f1')

    def f2(self):
        print('Foo.f2')
        self.__f1()  # self.__Foo.__f1


class Bar(Foo):
    def f1(self):  # __Bar.__f1
        print('Bar.f1')


obj = Bar()
obj.f2()  # 打印Foo.f2 Bar.f1
print(Bar.__mro__)  # 查找的优先级

2.2 多继承与菱形继承

三、多态

1. 什么是多态?

  • 同一事物的多种形态
class Animal:
    pass


class People(Animal):
    pass


class Dog(Animal):
    pass


class Pig(Animal):
    pass

2. 为什么要有多态=》多态会带来什么样的特性, 多态性

# 多态
class Animal:  # 统一所有子类的方法
    def say(self):
        print('动物基本的发声频率。。。')


class People(Animal):
    def say(self):
        super().say()
        print('嘤嘤嘤')


class Dog(Animal):
    def say(self):
        super().say()
        print('汪汪汪')


class Pig(Animal):
    def say(self):
        super().say()
        print('哼哼哼')


# 正常情况
obj1 = People()
obj2 = Dog()
obj3 = Pig()

obj1.say()
obj2.say()
obj3.say()


# 多态: 定义统一接口, 接收传入动物对象
def animal_say(animal):
    animal.say()


animal_say(obj1)
animal_say(obj2)
animal_say(obj3)

# python内部多态据类
len('字符串, 列表, 字典')
print('hello'.__len__())
print([1, 2, 3].__len__())
print({'a': 1, 'b': 3}.__len__())

print(len('hello'))
print(len([1, 2, 3]))
print(len({'a': 1, 'b': 3}))


# 有了统一标准就能定义一个统一的接口
def my_len(val):
    return val.__len__()

3. Python 的多态玩法

  • 鸭子类型
# 不用继承的方法的好处, 继承是一种耦合思想, 没有继承也能实现, 达到了一个解耦合的思想
# 这就是鸭子类型, 不是什么是什么的关系, 长得像就可以了

class Cpu:
    def read(self):
        print('cpu read')

    def wright(self):
        print('cpu wright')


class Mem:
    def read(self):
        print('mem read')

    def wright(self):
        print('mem wright')


class Txt:
    def read(self):
        print('txt read')

    def wright(self):
        print('txt wright')


obj1 = Cpu()
obj2 = Mem()
obj3 = Txt()


obj1.read()
obj1.wright()

obj2.read()
obj2.wright()

obj3.read()
obj3.wright()

相关连接(笔记来自于视频课程的归类整理):
[1]: https://www.bilibili.com/video/BV1QE41147hU?p=17
[2]: https://www.zhihu.com/column/c_1189883314197168128
[3]: https://www.cnblogs.com/linhaifeng/articles/6384466.html

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值