《python基础教程(第三版)》第七章 抽象

2019-08-07  本文已影响0人  Colleen_oh

7.1 封装

封装(encapsulation)指的是向外部隐藏不必要的细节。假设你有一个名为OpenObject的类:

>>> o = OpenObject() # 对象就是这样创建的
>>> o.set_name('Sir Lancelot')
>>> o.get_name()
'Sir Lancelot'

你(通过像调用函数一样调用类)创建一个对象,并将其关联到变量o,然后就可以使用方法set_name和get_name了(假设OpenObject支持这些方法)。

7.2 类

每个对象都属于特定的类,并被称为该类的实例。
例如,如果你在窗外看到一只鸟,这只鸟就是“鸟类”的一个实例。鸟类是一个非常通用(抽象)的类,它有多个子类:你看到的那只鸟可能属于子类“云雀”。你可将“鸟类”视为由所有鸟组成的集合,而“云雀”是其一个子集。一个类的对象为另一个类的对象的子集时,前者就是后者的子类。因此“云雀”为“鸟类”的子类,而“鸟类”为“云雀”的超类。

7.2.1 创建自定义类

下面是一个简单的示例:

class Person:
     def set_name(self, name):
           self.name = name
     def get_name(self):
           return self.name
     def greet(self):
           print("Hello, world! I'm {}.".format(self.name))

Person当然是类的名称。class语句创建独立的命名空间,用于在其中定义函数。self是什么。它指向对象本身。那么是哪个对象呢?下面通过创建两个实例来说明这一点。

>>> foo = Person()
>>> bar = Person()
>>> foo.set_name('Luke Skywalker')
>>> bar.set_name('Anakin Skywalker')
>>> foo.greet()
Hello, world! I'm Luke Skywalker.
>>> bar.greet()
Hello, world! I'm Anakin Skywalker. 

7.2.2 深入探讨继承

要确定一个类是否是另一个类的子类,可使用内置方法issubclass。
如果你有一个类,并想知道它的基类,可访问其特殊属性bases

>>> SPAMFilter.__bases__
(<class __main__.Filter at 0x171e40>,)
>>> Filter.__bases__
(<class 'object'>,) 

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

>>> s = SPAMFilter()
>>> isinstance(s, SPAMFilter)
True
>>> isinstance(s, Filter) 
True
>>> isinstance(s, str)
False 

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

>>> s.__class__
<class __main__.SPAMFilter at 0x1707c0>

7.2.3 多个超类

你可使用它来获悉类的基类,而基类可能有多个。为说明如何继承多个类,下面来创建几个类。

class Calculator:
    def calculate(self, expression):
          self.value = eval(expression)
class Talker:
    def talk(self):
          print('Hi, my value is', self.value)
class TalkingCalculator(Calculator, Talker):
    pass 

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

>>> tc = TalkingCalculator()
>>> tc.calculate('1 + 2 * 3')
>>> tc.talk()
Hi, my value is 7 

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

7.2.4 接口和内省

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

>>> hasattr(tc, 'talk')
True
>>> hasattr(tc, 'fnord')
False 

在上述代码中,你发现tc(本章前面介绍的TalkingCalculator类的实例)包含属性talk(指向一个方法),但没有属性fnord。如果你愿意,还可以检查属性talk是否是可调用的。

>>> callable(getattr(tc, 'talk', None))
True
>>> callable(getattr(tc, 'fnord', None))
False 

请注意,这里没有在if语句中使用hasattr并直接访问属性,而是使用了getattr(它让我能够指定属性不存在时使用的默认值,这里为None),然后对返回的对象调用callable。

上一篇下一篇

猜你喜欢

热点阅读