Python3基础之面向对象的封装,继承,多态

封装

1.定义

1.数据角度来讲,将一些基本数据类型复合成一个自定义类型
  优势:更符合人类的思考方式,将数据与对数据的操作整合在一起
2.行为角度来讲,向类外提供必要的功能,影藏实现的细节
  优势:以“模块化”的方式进行变成,可以集中精力设计组织,指挥多个类协同操作
3.设计角度来来讲
(1.分为治之
      --将一个大的需求分解为许多类,每个类处理一个独立的功能
      --拆分好处:便于分工,便于复用,可扩展性强
(2.变则疏之
      --变化的地方独立封装,避免影响其他类
(3.高内聚
     --类中的各个方法都在完成一项任务(单一职责的类)
(4.低耦合
     --类与类的关联性与依赖度要低   

私有成员

在Python里边,一个类的成员(成员变量、成员方法)是否为私有,完全由这个成员的名字决定。如果一个元成员的名字以两个下划线__开头,但不以两个下划线__结尾,则这个元素为私有的(private);否则,则为公有的(public)。Pyhton里边并没有protected的概念。

为了方便表述,如果一个元素的名字以两个下划线__开头,但不以两个下划线__结尾,我们称这个元素的名字“符合私有定义”。

我们注意到,私有成员不以以两个下划线结尾;所有的运算符重载相关方法,以一些特殊的成员方法如构造函数,都是以两个
下划线开头,两个下划线结尾,而且它们都是公有的。

私有成员,即只能在这个类里边访问;如果你在类外面访问一个私有成员,系统会抛出一个异常,提示你这个成员不存在。

请看如下代码:

class Hugo:
    def __init__(self):
        self.__name = "hugo"

    def Say(self):
        # 在类内部使用私有成员变量__name
        print("my name is:", self.__name)

boy = Hugo()
boy.Say() # OK

# 此处抛出一个异常,提示__name不存在
print("name of boy:", boy.__name)
其它运行结果如下:

my name is: hugo
Traceback (most recent call last):
  File "eg1.py", line 13, in <module>
    print("name of boy:", boy.__name)
AttributeError: 'Hugo' object has no attribute '__name' 

正如这个例如所展示的,我们可以在类的内部(成员方法中)使用私有变量__name。然而,当我们直接在外部访问__name,会收到一个异常,说Hugo类的对象没有__name方法。显然,这个异常的提示具有误导性,因为__name实际上存在,只是不能直接访问。

1、私有成员并非真正私有
其实,我们还是可以类的外面访问私有成员,方法是,在私有成员的名字前面加一个下划线和类名。

如下面例子所示:

class Hugo:
    def __init__(self):
        self.__name = "hugo"

    def Say(self):
        # 在类内部使用私有成员变量__name
        print("my name is:", self.__name)

boy = Hugo()
boy.Say() # OK

# 通过_Hugo__name可以在外部访问私有变量__name
print("name of boy:", boy._Hugo__name) 

我们可以通过_Hugo__name可以在外部访问私有变量__name。然后,在实际开发中,如果没有特殊的需要,请不要这么做。我们将一个成员声明为私有,是有一定的原因的,其中一个最主要的原因,就是不希望使用者直接访问它。虽然我们还是可以这么做,但请务必遵守这个约定,以免出现不必要的问题。

2、私有访问约定
,在一个模块中,如果一个函数的名字符合私有定义,那么这个方法是私有的,只能在这个模块中使用。其实,扩展到模块中定义的类和变量也一样,如果模块中的类或者变量名符合私有定义,那么它就是私有的,只能在这个模块中使用。

但实现上,即便一个元素的名字符合私有定义,依然可以在模块外使用。

不过,在理念上,如果一个函数的名字符合私有定义,那么它就是一种私有访问的约定,或者惯例,没有特殊的原因,你就不应该去直接使用它。

在大型项目开发过程中,为了提高协作的效率,我们会有很多不成文的约定(通常被称为“惯例”)。当我们见到一个东西符合某种约定,那我们最好就遵循这个惯例。

# 使用方法,封装变量
class Wife:
    def __init__(self, name, age, weight):
        self.name = name
        # 本质:障眼法(实际将变量名改为:_类名__age)
        self.__age = age
        self.__weight = weight


w01 = Wife("铁扇公主", 87, 87)
# 从新创建新实例变量
w01._Wife__age = 107 # 修改了类中定义的私有变量
print(w01.name)
print(w01._Wife__age)  #python 内置变量,存储对象的实例变量都在里面

输出结果
铁扇公主
107
{'name': '铁扇公主', '_Wife__age': 107, '_Wife__weight': 87}
class Wife:
    def __init__(self, name, age, weight):
        self.name = name
        # 本质:障眼法(实际将变量名改为:_类名__age)
        self.__age = age
        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("我不要")

w01 = Wife("牛魔王",30,87)
w01.set_age(25)
print(w01.get_age())

创建property对象,只负责拦截读取操作,变量…setter 只负责拦截写入操作

class Wife:
    def __init__(self, name, age, weight):

        self.name = name
        # 本质:障眼法(实际将变量名改为:_类名__age)
        self.age = age
        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
    def weight(self):
        return self.__weight

    @weight.setter
    def weight(self, value):
        if 32<= value <= 60:
            self.__weight = value
        else:
            raise ValueError("我不要")


w01 = Wife("牛魔王", 30, 87)
w01.age = 25
print(w01.age)
w01.weight = 45
print(w01.weight)

练习1:定义敌人类(姓名,攻击力10–50),血量100–200创建一个敌人对象,可以修改数据,读取数据

class Enemy:

    def __init__(self,name,hp, atk):
        self.name = name
        self.__hp = hp
        self.__atk = atk

    def get_hp(self):
        return self.__hp

    def set_hp(self,value):
        if 10 <= value <= 50:
            self.__hp = value
        else:
            raise ValueError("我不要")

    def get_atk(self):
        return self.__atk

    def set_atk(self,value):
        if 100 <= value <= 200:
            self.__atk = value
        else:
            raise ValueError("我不要")


w01 = Enemy("面霸",80,120)
w01.set_hp(25)
print(w01.get_hp())
w01.set_atk(150)
print(w01.get_atk())

输出结果
25
150

继承

多个子类在概念上一致,所以就抽象出一个父类
多个子类的共性,可以提取到父类中
从设计角度讲:先有子再有父
从编码角度讲:先有父,再有子
子类不用写,但是可以用
子类对象可以调用子类成员,也可以调用父类成员
父类对象只可以调用父类成员,不能调用子类成员

# Python 内置函数isinstance
# 1.判断对象是否属于一个类型
# ”老师对象“是 一个老师类型
print(isinstance(t01,Teacher)) # True
# "老师对象" 是 一个学生类型
print(inistance(t01,Student)) # False
# "老师对象" 是 一个人类型
print(isinstance(t01,Person)) # True
class Person:
    def say(self):
        print("说话")
class Student(Person):
    def study(self):
        print("学习")
    
class Teacher(Person):
    def teach(self):
        print("讲课")
    

子类若具有构造函数,则必须先调用父类构造函数

class Person:
    def __init__(self,name)
    self.name = name 
class Student(person):
    def __init__(self,name,score):
    super().__init__(name)
    self.score = score

s01 = Student("张三"100)
print(s01.score)
print(s01.name)    

多态

1.定义
父类的同一种动作或者行为,在不同的子类上有不同的实现
2.作用
1.继承相关概念的共性进行抽象,多态在共性的基础上,提现行为有不同的实现
2.争强可扩展性,提现开闭原则

类与类的关系

泛化:子类与父类的关系,概念的复用,耦合度最高 
     B类泛化A类,意味着B类是A类的一种
     做法:B类继承A类
关联(聚合/组合):部分与整体的关系,功能的复用,变化影响一个
A与B关联,意味着B是A的一部分
做法:在A类中包含B类成员

依赖:合作关系,是一种相对松散的协作,变化影响一个方法
A类依赖B类,意味着A类中方法的参数并不是A的成员

  • 11
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 22
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南城以南1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值