美文网首页
《Python基础教程》第7章 更加抽象

《Python基础教程》第7章 更加抽象

作者: tangyefei | 来源:发表于2015-01-14 11:25 被阅读196次

第7章 更加抽象

本章将会介绍如何创建对象,以及多态、封装、方法、特性、超类以及继承等概念。

对象的魔力

多态

多态字面意思为有多种形态,在编程语言中意味着即使不知道对象的具体类型,也可以进行某些操作,并且根据对象类型的不同而表现出不同的行为。

为什么会需要多态呢?如下尝试用一个例子来说明多态的好处(原书例子有点不好理解,这里新举一个例子)。假定某购物网站的商品对应程序类Product, 现在要求计算某个顾客购物车内的所有物品,计算每个物品的价格可能会有如下方法:

def getPrice(p):
    if p.type == 'type1':
        return p.price
    elif p.type == 'type2':
        return p.price - discountCalculate(p) #促销商品
    elif p.type == 'type3':
        return p.price + taxCalculate(p) #附加税商品

当出现一种价格计算方式的时候我们要修改代码,增加新的分支,分支多的时候会变得难于管理。如果项目已经被集成使用修改会更加麻烦。这时候多态的好处就体现出来了,每种商品都有自己的价格,那么只要调用product.getPrice就能调用具体每种商品的价格计算方法。

在Python中我们已经接触过的多态的运用,比如:

>>> o = 'abc'
>>> o.count('a')
1
>>> o = ['a', 'b', 'c']
>>> o.count('a')
1

其实不只是方法,很多内建的运算符都实现了多态:

>>> 'a' + 'b'
'ab'
>>> 1+2
3
封装

封装能对外部作用域隐藏内部实现细节只知道如何调用即可。

继承

继承是想要扩展功能,有不想写重复的做法。

类和类型

类到底是什么

类即类型或者种类,所有的对象都属于某一个类,称为类的实例。比如,鸟是鸟类的实例,鸟类有可能有很多子类(subclass)如“百灵鸟”;反过来,鸟类是“百灵鸟”的超类(superclass)。

在面向对象程序设计中,所有实例都包含类的方法,所有子类都必须继承或者重载超类的方法,并且子类中可以新增自己特有的方法。

创建自己的类
__metaclass__ =  type

class Person:
    def setName(self, name):
        self.name = name
    def getName(self):
        return self.name
    def greet(self):
        print 'Hello, I am %s' % self.name

foo =  Person()
bar =  Person()
foo.setName('foo')
print foo.getName()

bar.name = 'bar'
print bar.name

foo.greet()


$ python class.py
foo
bar
Hello, I am foo

如上为类的创建和使用,注意第一行代码:声明新式类需要在模块或者脚本开始地方放置该行(不细究)。

特性、函数和方法
class Bird:
    song = 'Squaawk'
    def sing(self):
        print self.song
        
bird = Bird()
bird.sing()
singsong = bird.sing
singsong()

$ python class.py
Squaawk
Squaawk

某些编程语言觉得直接通过'对象.属性'的方式访问破坏了封装性,但Python并不支持私有形式(尽管有一些小技巧可以达到私有特性的效果,不是目前学习的重点先跳过)。

类的命名空间

所有位于class中间的代码都在类命名空间中,这个命名空间可以由所有的类的实例访问。需要注意类的定义就是执行代码块,因此如下定义方式虽然傻但是是可以的:

class C:
    print 'Class C is defined...'

$ python class.py
Class C is defined...

在类中可以定义供所有成员访问的变量,如下是一个例子(在Java中叫类变量,通常在定义指明MemberCounter.members;而在Python中定义是直接写在members类中。两者调用的时候同样使用MemberCounter.members):

class MemberCounter:
    members = 0
    def init(self):
        MemberCounter.members += 1

m1 = MemberCounter()
m1.init()
print m1.members

m2 = MemberCounter()
m2.init()
print m2.members


$ python class.py
1
2
调用超类

子类可以扩展超类的定义,既可以覆写超类的方法,也可以直接使用超类方法而不用自己再定义:

class Filter():
    def init(self):
        self.blocked = []
    def filter(self, sequence):
        return [x for x in sequence if x not in self.blocked]

class SPAMFilter(Filter):
    def init(self):
        self.blocked = ['SPAM']

filter = Filter()
filter.init()
print filter.filter([1,2,3])

spamFilter = SPAMFilter()
spamFilter.init()
print spamFilter.filter(['SPAM','SPAM', 'zip','lotus','SPAM']);

$ python class.py
[1, 2, 3]
['zip', 'lotus']

Filter类的blocked为[]因此不会对任何内容进行过滤;而在子类SPAMFilter中,我们覆写了init方法,仍旧使用超类的filter方法,因此所有'SPAM'的字符串都被过滤掉了。

介绍几个和类相关的常用方法
s = SPAMFilter()

#想要知道一个类是否是另一个类的子类:
print issubclass(SPAMFilter, Filter) #True
print issubclass(Filter, SPAMFilter) #False

#想要知道一个类已知基类(们):
print SPAMFilter.__bases__ # (<class __main__.Filter at 0x1004b8c18>,)

#想要知道一个对象是否是一个类的实例:
print isinstance(s, SPAMFilter) #True
print isinstance(s, Filter) #True

#想要知道一个对象属于哪个类
print s.__class__ #__main__.SPAMFilter

多个超类

类可以继承自多个超类,除非非常熟悉否则应该尽量避免使用,如下是一个多重继承的例子:

class Calculator:
    def calculate(self, expression):
        self.value = eval(expression)
        
class Talk():
    def talk(self):
        print 'My value is: %s' % self.value
        
class CalculatorTalk(Calculator, Talk):
    pass
    
ct = CalculatorTalk()
ct.calculate('2+3')
ct.talk()

$ python class.py
My value is: 5

接口和内省

接口的概念和多态有关,即处理多态对象时候只需要关系公开的方法和特性,因此需要检测对象是否真正实现了方法和特性。如下介绍两个检测的方法,第一个是所需方法是否存在,第二个是是所需方法否可调用。

hasattr(ct, 'talk') # True
hasattr(ct, 'test') # False
callable(getattr(ct, 'talk', None)) # True
callable(getattr(ct, 'test', None)) # False


相关文章

网友评论

      本文标题:《Python基础教程》第7章 更加抽象

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