python学习之旅笔记总结:第七章、再谈抽象,自定义对象

1、对象魔法

        在面向对象编程中,术语对象大致意味着一系列数据(属性)以及一套访问和操作这些数据的方法。使用对象而非全局变量和函数的原因有多个,下面列出了使用对象的最重要的好处

      多态:可对不同类型的对象执行相同的操作,而这些操作就像“被施了魔法”一样能够正常运行

      封装:对外部隐藏有关对象工作原理的细节。

      继承:可基于通用类创建出专用类

1.1 多态

           术语多态(polymorphism)源自希腊语,意思是“有多种形态”。这大致意味着即便你不知道变量指向的是哪种对象,也能够对其执行操作,且操作的行为将随对象所属的类型(类)而异

1.2 多态和方法

           对象属性相关联的函数称为方法。

1.3 封装

            封装(encapsulation)指的是向外部隐藏不必要的细节。这听起来有点像多态(无需知道对象的内部细节就可使用它)。这两个概念很像,因为它们都是抽象的原则。它们都像函数一样,可帮助你处理程序的组成部分,让你无需关心不必要的细节

           但封装不同于多态。多态让你无需知道对象所属的类(对象的类型)就能调用其方法,而封装让你无需知道对象的构造就能使用它

2 类

2.1 类到底是什么

             每个对象都属于特定的类,并被称为该类的实例。

2.2 创建自定义类

        

         这个示例包含三个方法定义,它们类似于函数定义,但位于class语句内。std当然是类的名称。class语句创建独立的命名空间,用于在其中定义函数

2.3 属性、函数和方法

          实际上,方法和函数的区别表现在前一节提到的参数self上

2.4 再谈隐藏

            Python没有为私有属性提供直接的支持,而是要求程序员知道在什么情况下从外部修改属性是安全的。毕竟,你必须在知道如何使用对象之后才能使用它。然而,通过玩点小花招,可获得类似于私有属性的效果

           要让方法或属性成为私有的(不能从外部访问),只需让其名称以两个下划线打头即可

           虽然以两个下划线打头有点怪异,但这样的方法类似于其他语言中的标准私有方法。然而,幕后的处理手法并不标准:在类定义中,对所有以两个下划线打头的 名称都进行转换,即在开头加上一个下划线和类名

            总之,你无法禁止别人访问对象的私有方法和属性,但这种名称修改方式发出了强烈的信号,让他们不要这样做

2.5 类的命名空间

        

           它们都创建一个返回参数平方的函数,并将这个函数关联到变量foo。可以在全局(模块)作用域内定义名称foo,也可以在函数或方法内定义。定义类时情况亦如此:在class语句中定义的代码都是在一个特殊的命名空间(类的命名空间)内执行的,而类的所有成员都可访问这个命名空间。类定义其实就是要执行的代码段,并非所有的Python程序员都知道这一点,但知道这一点很有帮助。

                       

                 每个实例都可访问这个类作用域内的变量,就像方法一样。

          注意:类有自己的变量,该变量是所有对象共享,通过类名加点加变量名访问修改;而每个类对象也有自己的变量,该变量每个对象都不一样,通过对象名加点加变量名修改访问

2.6 指定超类

         超类又名父类

         子类扩展了超类的定义。要指定超类,可在class语句中的类名后加上超类名,并将其用圆括号括起

2.7  深入探讨继承

         要确定一个类是否是另一个类的子类,可使用内置方法issubclass。

         如果你有一个类,并想知道它的基类,可访问其特殊属性__bases__

         同样,要确定对象是否是特定类的实例,可使用isinstance。

          如果你要获悉对象属于哪个类,可使用属性__class__。

2.8 多个超类

         

         子类TalkingCalculator本身无所作为,其所有的行为都是从超类那里继承的。关键是通过从Calculator那里继承calculate,并从Talker那里继承talk,它成了会说话的计算器

        这被称为多重继承,是一个功能强大的工具。然而,除非万不得已,否则应避免使用多重继承,因为在有些情况下,它可能带来意外的“并发症”

        使用多重继承时,有一点务必注意:如果多个超类以不同的方式实现了同一个方法(即有多个同名方法),必须在class语句中小心排列这些超类,因为位于前面的类的方法将覆盖位于后面的类的方法。因此,在前面的示例中,如果Calculator类包含方法talk,那么这个方法将覆盖Talker类的方法talk(导致它不可访问)。如果像下面这样反转超类的排列顺序:

               class TalkingCalculator(Talker, Calculator): pass 

          将导致Talker的方法talk是可以访问的。多个超类的超类相同时,查找特定方法或属性时访问超类的顺序称为方法解析顺序(MRO),它使用的算法非常复杂。所幸其效果很好,你可能根本无需担心

2.9 接口和内省

          接口这一概念与多态相关。处理多态对象时,你只关心其接口(协议)——对外暴露的方法和属性。在Python中,不显式地指定对象必须包含哪些方法才能用作参数。例如,你不会像在Java中那样显式编写接口,而是假定对象能够完成你要求它完成的任务。如果不能完成,程序将失败

        通常,你要求对象遵循特定的接口(即实现特定的方法),但如果需要,也可非常灵活地提出要求:不是直接调用方法并期待一切顺利,而是检查所需的方法是否存在;如果不存在,就改弦易辙

         >>> hasattr(tc, 'talk') 
        True 
         >>> hasattr(tc, 'fnord') 
         False 
       在上述代码中,你发现tc(本章前面介绍的TalkingCalculator类的实例)包含属性talk(指向一个方法),但没有属性fnord

       要查看对象中存储的所有值,可检查其__dict__属性

2.10 抽象基类

            最终,Python通过引入模块abc提供了官方解决方案。这个模块为所谓的抽象基类提供了支持。一般而言,抽象类是不能(至少是不应该)实例化的类,其职责是定义子类应实现的一组抽象方法。

           抽象类(即包含抽象方法的类)最重要的特征是不能实例化

            形如@this的东西被称为装饰器,其用法将在第9章详细介绍。这里的要点是你使用@abstractmethod来将方法标记为抽象的——在子类中必须实现的方法

3 小结

          对象:对象由属性和方法组成。属性不过是属于对象的变量,而方法是存储在属性中的函数。相比于其他函数,(关联的)方法有一个不同之处,那就是它总是将其所属的对象作为第一个参数,而这个参数通常被命名为self

          类:类表示一组(或一类)对象,而每个对象都属于特定的类。类的主要任务是定义其实例将包含的方法

          多态:多态指的是能够同样地对待不同类型和类的对象,即无需知道对象属于哪个类就可调用其方法

          封装:对象可能隐藏(封装)其内部状态。在有些语言中,这意味着对象的状态(属性)只能通过其方法来访问。在Python中,所有的属性都是公有的,但直接访问对象的状态时程序员应谨慎行事,因为这可能在不经意间导致状态不一致。

           继承:一个类可以是一个或多个类的子类,在这种情况下,子类将继承超类的所有方法。你可指定多个超类,通过这样做可组合正交(独立且不相关)的功能。为此,一种常见的做法是使用一个核心超类以及一个或多个混合超类。

           接口和内省:一般而言,你无需过于深入地研究对象,而只依赖于多态来调用所需的方法。然而,如果要确定对象包含哪些方法或属性,有一些函数可供你用来完成这种工作。

           抽象基类:使用模块abc可创建抽象基类。抽象基类用于指定子类必须提供哪些功能,却不实现这些功能

           面向对象设计:关于该如何进行面向对象设计以及是否该采用面向对象设计,有很多不同的观点。无论你持什么样的观点,都必须深入 理解问题,进而创建出易于理解的设计

 

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值