Python(二十四)Python的三大特性

一、谈谈你对面向对象的三大特性的理解

说明:要知道专业术语的表述和自己的理解!

二、各个击破

(1)封装

概念:将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象的内部信息,而是通过所提供的方法来实现对内部信息操作和访问

通俗理解:根据职责将属性方法封装到一个抽象的类中,模块化编程

思考为什么封装

封装数据的主要原因是:隐藏类的实现细节,保护隐私(作为男人的你,脸上就写着:我喜欢男人,你害怕么?)

封装方法的主要原因是:隔离复杂度(快门就是傻瓜相机为傻瓜们提供的方法,该方法将内部复杂的照相功能都隐藏起来)

提示:在编程语言里,对外提供的接口,就是函数,称为接口函数,这与接口的概念还不一样,接口代表一组接口函数的集合体。

思考:封装的层面?

         封装其实分为两个层面,但无论哪种层面的封装,都要对外界提供好访问你内部隐藏内容的接口(接口可以理解为入口,有了这个入口,使用者无需且不能够直接访问到内部隐藏的细节,只能走接口,并且我们可以在接口的实现上附加更多的处理逻辑,从而严格控制使用者的访问)

        接口:可以理解为API

        层面1什么都不用做,创建类和对象会分别创建二者的名称空间,我们只能用类名.或者obj.的方式去访问里面的名字,这本身就是一种封装!

        注意:对于这一层面的封装(隐藏),类名.和实例名.就是访问隐藏属性的接口!

########分割线########

        层面2:类中把某些属性和方法隐藏起来(私有),只在类的内部使用(外部无法访问)或者留下少量接口(函数)供外部访问。

私有变量:private

私有变量:可以把属性的名称前加上两个下划线__,如果要让内部属性不被外部访问!

私有方法:可以把实例方法的名称前加上两个下划线__,只能内部访问!

对象的状态:数据和行为!

class Person:
    # (1)定义一个私有的成员类变量-->"__"开头
    __male = 'female'

    # (2)给外部提供接口来访问内部的私有数据
    def getmale(self):
        return self.__male

    # (3)定义一个私有的方法
    def __fun(self):
        print('我是私有的方法')

    # (4)函数的相互调用
    def call(self):
        self.__fun()


# 测试1:访问私有类变量
# 错误的方式
# print(Person.__male)
# 方式1:给外界提供接口的方式
print(Person().getmale())
# 方式2:通过对象直接暴力读取--->Python没有提供真正的隐藏机制
print(Person()._Person__male)
# 实质(上面的底层也是这样调用的): 单下划线+类名+__变量名
# 关于修改省略!
# 明确对于对象赋值的含义!

# 测试2:访问私有方法-->同上!

封装的含义:该隐藏的隐藏,该暴露的暴露,怎么感觉有点污了~~~

封装参考

(2)继承

继承的理解:我的理解就是继承家产,少部分无法继承(没有达到遗嘱的要求)

派生和扩展的理解一般和个性的理解

多继承:区别于Java的单继承

继承目的:继承实现了代码复用,相同的代码不需要重复的编写!

结果:子类继承了父类,继承了父类定义的共有属性和的方法!

细节:python2.x版本,必须显示的继承object,而python3.x默认继承object(超类或者基类)

练习1:继承关于方法的练习

class Parent(object):
    # 类变量
    x = 1

class Child1(Parent):
    pass

class Child2(Parent):
    pass

print(Parent.x, Child1.x, Child2.x)  # 1 1 1
# 说明:给指定对象添加属性,不影响类变量
Child1.x = 2
print(Parent.x, Child1.x, Child2.x)  # 1 2 1
# 说明:修改类变量的数值,在继承的过程中,类变量中没有此变量就使用继承的类变量
Parent.x = 3
print(Parent.x, Child1.x, Child2.x)  # 3 2 3

考点:继承的过程中类变量同名如何抉择

练习2:调用被重写的方法

        方法1:使用未绑定的方法调用(通过类名来调用,需要自己传递对象)

        方式2:使用super函数来调用

构造方法

class Animal:
    def __init__(self,name):
        self.name=name
        print(name)
    def drink(self):
        print('喝水')

    def eat(self):
        print('吃东西')

class Cat(Animal):
    # 原因:自定义之后,就不会采用默认的方法了!
    # def __init__(self):
    #     super().__init__()
    def __init__(self):
        # 默认(先创建父类对象-->利用其父类的构造方法):super
        print('想唱歌')
        # 说明:位置不一定要放到首位置!
        super().__init__('校花')

继承创建对象的过程:先利用父类的构造方法创建父类对象,再创建子类对象!

一般的方法重写

class Animal:
    def drink(self):
        print('喝水')

    def eat(self):
        print('吃东西')

class Cat(Animal):
    def run(self):
        print("跑的块")

class Kitty(Cat):
    def eat(self):
        # 调用基类的方法(不一定是直接基类)-->方法重写!
        # 说明:严格意义说是扩展!
        super().run()
        print('加速')

Kitty().eat()

说明:我们知道子类和父类是共性和个性的关系,子类针对自己特有的需求,此时就需要重写!

练习3:多继承的练习

class A:
    def test(self):
        print('A1')
    def tt(self):
        print('A2')

class B:
    def test(self):
        print('B1')
    def tt(self):
        print('B2')
# 说明:变化顺序!
class C(A,B):
    pass
C().test()
C().tt()

# object(python2.和python3.x的区别)

说明:多继承中是有先后顺序的,只有自己没有,父类1也没有,才会从父类2找!

(3)多态

多态概念不同子类对象调用相同的父类方法,产生不同的执行结果!

说明:具体呈现哪种行为由该变量所引用的对象来确定!

优点:多态可以增加代码的灵活度

前提:以继承和重写父类方法为前提

备注:是调用方法的技巧,不会影响到类的内部设计!

练习

class Dog(object):
    def __init__(self,name):
        self.name = name
    def game(self):
        print('%s 开心的玩~' %(self.name))

class Gaofei(Dog):
    # 父类方法不能满足子类的需求,重写game方法
    def game(self):
        print('%s和米老鼠一起玩~~~' %(self.name))

# 说明:wc变量被赋值为Gaofei对象
wc = Gaofei('高飞')
wc.game()
# 说明:wc变量被赋值为Dog对象!
wc = Dog('大黄')
wc.game()

# 多态:wc指向对象不同,呈现不同的行为特征!

关于多态的两个方法

1)issubclass(cls,class or tuple) -->判断cls是否是某个类的子类或元组中的子类

2)isinstance(obj,class or tuple) -->判断obj是否是某个类的子类或元组中的子类对象

执行逻辑:先检查,再调用方法!

注意:区别于Java的设计模式!

(4)设计模式

   4.1)单例模式

首先探讨下:对象的创建过程

   1)为对象在内存中分配空间                    --->__new__方法是类从object中继承过来的!

   2)调用构造方法为对对象进行初始化  ---->__init__构造方法初始化

练习:单例模式

class MusicPlayer(object):
    instance = None
    def __new__(cls, *args, **kwargs):
        # 判断类属性是否是空对象
        if cls.instance is None:
            # 调用父类方法 为第一个对象分配空间
            cls.instance = object.__new__(cls)
        return cls.instance

player1 = MusicPlayer()
player2 = MusicPlayer()
player3 = MusicPlayer()

print(player1)
print(player2)
print(player3)

说明:数据库的实例就是一个单例对象!

(5)其它概念

新式类默认以object为基类的类,存活于python3.X

经典类:不以object为基类的类,存活于python2.x

object:是Python为所有对象提供的基类,提供有一些内置的属性和方法,可以使用dir函数查看

在python3.X中定义的类时,如果没有指定父类,会默认使用object作为基类--python3.x中定义的类都是新式类

在python2.x中定义类时,如果没有指定父类,则不会以object作为基类

兼容性建议:为保证编写的代码能够同时在python2.x和python3.x运行,今后在定义类时,建议统一继承自object!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值