美文网首页
python:面向对象

python:面向对象

作者: alan2yang | 来源:发表于2019-02-23 13:37 被阅读10次

    自己以前整理的笔记,不太完整,后续会不断更新。。。。


    • [ ] __new__方法扩展
    • [ ] 魔法方法
    • [ ] 什么情况下使用self,什么情况不用?

    面向过程和面向对象是两种不同的编程方式

    一、面向过程

    过程:是早期的一种编程概念,类似于函数,但只有执行,没有返回值

    面向过程:把能实现某些独立功能的代码封装成一个个函数,然后顺序调用不同的函数

    特点

    • 过程与步骤---怎么做?
    • 若需求复杂,代码也会变复杂

    二、面向对象(Object Oriented Programming)

    具体的事物抽象化,抽象的事物具象化---前者针对实际存在的事物,后者针对抽象的事物

    特点

    • 相比于函数,面向对象是更大的封装,一个对象可根据职责封装多个方法
    • 注重对象和职责---谁来做?
    • 适合复杂项目开发,提供固定的套路

    对象的三大特性

    • 封装:封装属性和方法
    • 继承:实现代码的重用
    • 多态:对封装和继承的功能扩展:对象调用的方法,在子类和父类中都可以有,父类中有,子类可重写,由此不同的子类可实现不同的功能

    三、类

    • 抽象
    • 属性
    • 方法

    类用来创建对象

    对象是类的具象、实例化

    类只有一个,对应的对象有多个:不同对象之间的属性可能不同

    三要素

    1. 类名:大驼峰命名
    2. 属性:特征
    3. 方法:行为

    01.对象

    1. 每一次实例化的对象所保存的地址都不同
    2. 临时为对象添加属性的方法:直接给对象赋值 -----不推荐,未修改类

    dir()内建函数

    使用dir()可传入任意对象,查看对象的所有属性及方法

    显示出的__方法名__格式的方法是python提供的内置属性/方法

    对象初始化-引用

    • 创建对象后,变量保存的是对象在内存中的地址
    • 变量引用(指向)了新建的对象
    • print打印变量,显示该变量引用的对象是由哪一个类创建的对象,及内存中的地址

    对象创建过程-原理

    • 当使用 类名( ) 创建对象时,会自动执行以下操作:
      1. 为对象在内存中 分配空间 —— 创建对象
      2. 为对象的属性 设置初始值 —— 初始化方法 _init_()
    • 这个 初始化方法 就是 __init__ 方法,__init__ 是对象的内置方法,创建对象时自动调用该方法

    __init__ 方法是 专门 用来定义一个类 具有哪些属性的方法

    self

    • 哪一个对象 调用的方法,方法内的self就是 哪一个对象的引用
    • 对象调用方法时,不需要传递self参数
    • 类中定义方法时可通过self.的方式访问属性及调用其他方法

    02.内置方法

    _init_()

    当使用 类名( ) 创建对象时,分配完内存空间后,自动调用该方法

    • 创建对象时类名( )中的实参传入到__init__( )中除self之外的其他形参中
    • 若属性有初始值则不适合作为形参在对象初始化的时候传入,可在该方法内直接赋值
    • 若某属性的初始值不确定,可在该方法内赋值为None

    _del_()与del

    当一个对象被从内存销毁前,会自动调用该方法

    class Cat:
        def __init__(self, new_name):
    
            self.name = new_name
            print('初始化调用')
    
        def __del__(self):
    
            print('销毁前调用')
    
    
    # 整个程序结束后对象才会被销毁
    tom = Cat('Tom')
    print(tom.name)
    
    # del tom   # 使用del,提前调用__del()销毁对象
    
    print('_'*50)
    

    _str_()

    定制化print出的内容

    • 必须要return 一个字符串
    • 用于print()对象时的显示结果
    • 如果不定义该方法,打印对象时返回结果为十六进制内存地址

    __class__属性

    每一个实例对象中都存在一个__class__属性,指向创建该对象的类对象

    03.私有属性和私有方法

    定义

    私有属性/私有方法:在属性名称/方法名称前加__(两个下划线)

    特点

    私有属性和方法无法在类外访问,只能在类中访问

    伪私有:python中不存在真正意义上的私有,私有属性和方法可以通过以下格式访问

    对象._类名.__属性/方法

    实际上是python对私有属性和方法改名了

    class Women:
    
        def __init__(self, name):
    
            self.name = name
            # 不要问女生的年龄
            self.__age = 18
    
        def __secret(self):
            print("我的年龄是 %d" % self.__age)
    
    xiaofang = Women('小芳')
    print(xiaofang._Women.__age)
    xiaofang._Women.__secret()
    
    

    注意:

    # *-* coding:utf-8 *-*
    # 私有属性只能在类中定义
    
    
    class Test(object):
        def __init__(self, name):
            self.__name = name
    
    
    a = Test('老王')
    print(a._Test__name)  # 可访问
    
    print(a.__dict__)  # 查看a对象的所有属性
    # 实际上是__name被解释器名字重整为_Test__name
    
    a.__name='老李'  # 添加一个属性,属性名为__name
    print(a.__name)
    print(a.__dict__)
    
    
    # 结果
    老王
    {'_Test__name': '老王'}
    老李
    {'_Test__name': '老王', '__name': '老李'}
    

    四、继承

    概念:子类拥有父类的所有属性和方法

    子类在自己方法内不能直接访问父类的私有属性和私有方法,但可以通过父类的公有方法间接访问私有属性和方法

    属性

    • 继承的传递性:‘孙类’不仅继承父类的属性和方法,还会继承‘爷类’的属性和方法

    01. 多重继承

    子类方法的重写:

    父类的方法实现无法满足子类的需求

    1. 覆盖父类方法
    2. 对父类方法进行扩展:
    • super( ).方法( ): super( )的主要作用是扩展父类中已有方法的功能

    若父类中都存在某方法,则一直向上找,直到找到为止

    也就是说向上只能找到第一个某方法

    • super(class1,self).方法1():继承class1父类的方法1
    • 父类名.方法(self): 调用父类中的方法,若父类中没有该方法则去父类的父类中查找

    若所有父类中都存在同一名称的方法,那么可以用这种方法调用特定类中的方法

    super().__init__相对于 类名.__init__,在单继承上用法基本无差,但在多继承上有区别,super方法能保证每个父类的方法只会执行一次,而使用类名的方法会导致方法被执行多次,如下的案例:

    http://www.cnblogs.com/dkblog/archive/2011/02/24/1980654.html

    02. 多继承

    class B:
        pass
    class C:
        pass
    
    class A(B, C):
        pass
    

    开发时若多个父类中的属性或方法名称相同时,应尽量避免使用多继承,否则容易混淆

    python中针对提供了内置属性__mro__可以查看子类对多继承的父类的搜索顺序

    print(A.__mro__)
    # 结果
    # (<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class 'object'>)
    
    • 在搜索方法时,是按照 __mro__ 的输出结果 从左至右 的顺序查找的
    • 如果在当前类中 找到方法,就直接执行,不再搜索
    • 如果 没有找到,就查找下一个类 中是否有对应的方法,如果找到,就直接执行,不再搜索
    • 如果找到最后一个类,还没有找到方法,程序报错

    object类是python中所有类的基类,提供一些内置的属性和方法

    新式类与旧式(经典)类

    • 新式类:

    默认以object类为基类

    多继承时,搜索父类时采用广度优先原则

    python3.x中都是新式类

    • 经典类:

    不默认以object类为基类

    多继承时,搜索父类时采用深度优先原则

    python2.x中,若不指定父类,不会以object类作为基类

    建议:为保证代码在2.x和3.x中均能运行,只要没有父类,都写上object作为父类

    当所有父类都有共同的父类时,在到达共有父类之前先按深度优先原则,再按广度优先原则进行继承

    几种多继承方式:

    1534734241591.png 1534735028431.png 1534735159033.png

    一个坑

    # 新式类继承顺序,广度优先原则
    class A:
        pass
    class B(A):
        pass
    # 报错:继承顺序回头,C--->A--->B--->A
    class C(A,B):
        pass
    print(C.__mro__)
    
    # 正常:继承顺序,C--->B--->A--->?
    class C(B,A):
        pass
    print(C.__mro__)
    

    五、多态

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

    特点:

    • 多态可增加代码的灵活度
    • 继承重写父类方法为前提
    • 不影响父类的内部

    多态的好处就是,当我们需要传入Dog、Cat、Tortoise……时,我们只需要接收Animal类型就可以了,因为Dog、Cat、Tortoise……都是Animal类型,然后,按照Animal类型进行操作即可。由于Animal类型有run()方法,因此,传入的任意类型,只要是Animal类或者子类,就会自动调用实际类型的run()方法,这就是多态的意思:

    对于一个变量,我们只需要知道它是Animal类型,无需确切地知道它的子类型,就可以放心地调用run()方法 ,而具体调用的run()方法是作用在Animal、Dog、Cat还是Tortoise对象上,由运行时该对象的确切类型决定,这就是多态真正的威力:调用方只管调用,不管细节,而当我们新增一种Animal的子类时,只要确保run()方法编写正确,不用管原来的代码是如何调用的。这就是著名的“开闭”原则:

    **对扩展开放:允许子类重写父类方法函数 **

    **对修改封闭:不重写,直接继承父类方法函数 **

    六、类属性和类方法

    从类的实例化讲起:

    每次通过 类名( ) 创建对象的动作有两步:

    1. 在内存中为对象 分配空间

    2. 调用初始化方法 __init__对象初始化

    对象创建后,内存 中就有了一个对象的 实实在在 的存在 —— 实例

    对象的属性叫实例属性,对象调用的方法叫实例方法

    01 内存空间分配

    如图,一个类可实例化为多个对象,但

    • 每一个对象 都有自己 独立的内存空间保存各自不同的属性
    • 多个对象的方法,在内存中只有一份,保存在类所在的内存空间,在调用方法时,需要把对象的引用 传递到方法内部即可
    • 在程序运行时,会被加载到内存
    • 每个实例对象内都存在一个内置属性__class__,保存着该属性是由哪个类创建的
    1550899375695.png QQ20171025-204706@2x.png

    02 类是一个特殊的对象

    class A: 定义的类属于类对象

    obj=A( ): 定义的对象属于实例对象

    • 类对象在内存中只有一份
    • 类对象也有自己的属性和方法,分别叫类属性类方法
    • 通过 类名. 的方式可访问类属性和类方法

    类对象与实例对象互相访问权限

    1. 类对象-->实例对象

    类对象不可以访问实例对象的属性和方法

    1. 实例对象-->类对象

    实例对象可以访问类属性(前提:实例对象中无同名属性)和类方法(且实例方法不能与类方法重名,否则无效,只调用类方法)

    实例对象也可访问静态方法

    03 类属性

    在类对象中定义的属性,通常会用来记录与该类有关的特征,而不会用于记录具体对象的特征

    应用场景:通过类创建实例对象时,如果每个对象需要具有相同名字的属性,那么就使用类属性,用一份既可

    python中实例对象属性的获取存在一个向上查找的机制

    1. 通过对象名.属性名方式调用属性时,首先在实例对象内部查找
    2. 没找到就会向上寻找同名的类属性

    所以,实例对象也可以通过对象名.类属性的方式访问类属性(但不推荐)

    注意:

    如果给对象以对象名.类属性=值的方式添加属性,不会影响类属性的值,只会给对象新建一个与类属性同名的实例属性

    实例对象也可以通过self.__class__.类属性给类属性重新赋值

    04 类方法

    类方法 就是针对 类对象 定义的方法

    类方法内部可以直接访问类属性或者调用其他的类方法

    # 定义类方法
    
    @classmethod
    def 类方法名(cls, var1, var2):
        pass
    

    类方法形参第一个参数应该是cls,其效果类似于实例方法的第一个形参self,哪一个类调用该方法,方法的cls就是那个类的引用

    05 静态方法

    在类中既不需要访问实例属性和方法,也不需要访问类属性和方法的方法叫静态方法

    # 定义静态方法
    @staticmethod
    def 静态方法名():
        pass
    

    通过类名.调用静态方法,实例对象也可以调用静态方法

    七、单例

    单例设计模式

    设计模式

    • 前人工作的总结和提炼,通常,被人们广泛流传的设计模式都是针对 某一特定问题 的成熟的解决方案
    • 使用 设计模式 是为了可重用代码、让代码更容易被他人理解、保证代码可靠性

    单例设计模式

    让类创建的对象,在系统内存中只有唯一的一个实例

    即:每次执行新建对象操作所返回对象的内存地址是相同的

    应用:音乐播放器、打印机.....

    01.__new__(cls)

    使用类创建对象时,python解释器先调用__new__( )给对象分配内存空间,然后再调用__init__( )初始化

    __new__( )是object基类提供的内置静态方法,其功能:

    • 在内存中为对象分配空间
    • 返回对象的引用

    python解释器获得其返回的对象引用后,将其作为参数传递给__init__( )方法的第一个参数self

    由以上可见:

    1. 要实现单例设计模式,可通过重写__new__( )方法来控制创建对象时内存空间的分配
    2. 基类objectsuper().__new__(cls)可以帮助实现对象内存的分配,并返回对象的引用,也就是说,此时super().__new__(cls)是一个对象的引用
    3. 重写 __new__ 方法 一定要 return super().__new__(cls),因为它可以帮助实现内存空间分配的功能
    4. 调用时需要主动传递cls参数,传递的是类对象
    5. 由于要识别对象是否是初次调用,所以需要有一个类属性来记录实例对象的实例化次数
    class MusicPlayer:
        count = None
        
        def __init__(self):
            print('初始化播放器对象')
    
        def __new__(cls):
            if MusicPlayer.count is None:
                MusicPlayer.count = super().__new__(cls)       # 基类object中的__new__方法完成了内存的分配并返回了对象的引用
                
            print(MusicPlayer.count)
            return MusicPlayer.count                       # 要返回对象的引用
    
    
    player1 = MusicPlayer()
    player2 = MusicPlayer()
    
    print(player1)
    print(player2)
    

    02.__new__方法扩展

    两个用法:用于重写一些不可变类型数据的类如:str,int,tuple;元类?????

    八、类的魔法方法

    相关文章

      网友评论

          本文标题:python:面向对象

          本文链接:https://www.haomeiwen.com/subject/bmfpyqtx.html