Python 设计模式—用模式改善软件设计

表1特殊的类属性

 

4.2 实例

定义类的目的是为了创建它的实例,从面向对象的角度看,类是对数据及其相关操作的封装,而类实例则是对现实生活中某个实体的抽象。假设定义了如下一个类:

class School:

 def __init__(self, name):

self.name = name

self.students = []

 def addStudent(self, student):

self.students.append(student)

要创建School类的一个实例,可以执行下面的语句:

bit = School("Beijing Institute of Technology")

C++Java中创建类实例时,与类具有相同名称的构造函数被调用,而在Python中创建一个类的实例时,将调用名为__init__的特殊方法。Python中的类实例继承了类的所有方法和属性,并且有自己独立的名字空间,使用下面的方法可以访问类实例的方法和属性:

bit.addStudent("gary")

bit.students

Python中的对象属性有一个非常有趣的地方,那就是使用它们之前不用像C++Java那样,必须先在类中进行声明,因为这些都是可以动态创建的。作为一门动态类型语言,Python的这一特性的确非常灵活,但有时也难免产生问题。例如在许多针对接口的设计模式中,通常都需要知道对象所属的类,以便能够调用不同的实现方法,这些在C++Java这些强类型语言的对象模型中不难实现,但对Python来讲可就不那么简单了,因为Python中的每个变量事实上都没有固定的类型。

为了解决这一问题,Python的__builtin__模块提供了两个非常实用的内建函数:isinstance()和issubclass()。其中函数isinstance()用于测试一个对象是否是某个类的实例,如果是的话则返回1,否则返回0。其基本的语法格式是:

isinstance (instance_object, class_object)

例如:

>>> class Test:

pass

>>> inst = Test()

>>> isinstance(inst, Test)

1

而函数issubclass()则用于测试一个类是否是另一个类的子类,如果是的话则返回1,否则返回0。其基本的语法格式是:

issubclass(classobj1, classobj2)

例如:

>>> class TestA:

pass

>>> class TestB(TestA):

pass

>>> issubclass(TestA, TestB)

0

>>> issubclass(TestB, TestA)

1

和类一样,Python中的每个类实例也具有一些特殊的属性,它们都是由Python的对象模型所提供的
列出了这些属性:

 

 


表2 特殊的实例属性

4.3继承

在面向对象的程序设计中,继承(Inheritance)允许子类从父类那里获得属性和方法,同时子类可以添加或者重载其父类中的任何方法。在Python中定义继承类的语法格式是:

class (superclass, superclass, ...)

suit

例如,对于下面这个类:

class Employee:

 def __init__(self, name, salary = 0):

self.name = name

self.salary = salary

 def raisesalary(self, percent):

self.salary = self.salary * (1 + percent)

 def work(self):

 print self.name, "writes computer code"

可以为其定义如下的子类:

class Designer(Employee):

 def __init__(self, name):

 Employee.__init__(self, name, 5000)

 def work(self):

 print self.name, "writes design document"

C++Java的对象模型中,子类的构造函数会自动调用父类的构造函数,但在Python中却不是这样,你必须在子类中显示调用父类的构造函数,这就是为什么在Designer. __init__方法中必须调用Employee.__init__方法的原因。

人们对多重继承的看法一直褒贬不一,C++对象模型允许多重继承,而Java对象模型则是通过接口(Interface)来间接实现多重继承的。在对多重继承的处理上,Python采用了和C++类似的方法,即允许多重继承,例如:

class A:

 pass

class B(A):

 pass

class C:

 pass

class D(B, C):

 pass

4.4 多态

严格说来,像C++Java这些强类型语言对象模型中的多态概念并不适用于Python,因为Python没有提供类型声明机制。但由于Python本身是一种动态类型语言,允许将任意值赋给任何一个变量,如果我们对多态的概念稍加扩充,将其理解为具有能同时处理多种数据类型的函数或方法,那么Python对象模型实际上也支持经过弱化后的多态。

Python直到代码运行之时才去决定一个变量所属的类型,这一特性称为运行时绑定(runtime binding)。Python解析器内部虽然也对变量进行类型分配,但却十分模糊,并且只有在真正使用它们时才隐式地分配类型。例如,如果程序调用abs(num),则除数字之外的任何类型对变量num都没有意义,此时变量num事实上就进行了非正式的类型分配。

能够处理不同抽象层次的对象,是面向对象编程最重要的特性之一,也是Python的一个非常重要的组成部分。下面的例子示范了如何让Python中的一个函数能够同时处理多种类型的数据,在C++的对象模型中,这种多态被称为方法重载。

class Polymorph:

 def deal_int(self, arg):

 print '%d is an integer' % arg

 def deal_str(self, arg):

 print '%s is a string' % arg

 def deal(self, arg):

if type(arg) == type(1):

self.deal_int(arg)

elif type(arg) == type(' '):

self.deal_str(arg)

else:

print '%s is not an integer or a string' % arg

这样,Polymorph类中的方法deal就可以同时处理数字和字符串了:

>>> p = Polymorph()

>>> p.deal(100)

100 is an integer

>>> p.deal("Hello World!")

Hello World! is a string

4.5 可见性

Python对象模型对可见性的处理与C++Java完全不同。在C++Java中,如果属性或者方法被声明为private,那就意味着它们只能在类中被访问,而如果被声明为protected,则只有该类或者其子类中的代码能够访问这些属性和方法。但在Python对象模型中,所有属性和方法都是public的,也就是说数据没有做相应的保护,你可以在任何地方对它们进行任意的修改。

能够对可见性进行约束是面向对象编程的一个重要特点,其目的是使对象具有优良的封装性:对象仅仅向外界提供访问接口,而内部实现细节则被很好地隐藏起来。奇怪的是作为一门面向对象脚本语言,Python并没有提供对可见性进行约束的机制,所有属性和方法对任何人都是可见的,任何人想知道对象的内部实现细节都是可能的。虽然这样做能够带来部分效率上的优化,但却无法阻止其它程序员对已经封装好的类进行破坏,从某种程度上这不得不说是Python带给我们的一丝的缺憾。

直到Python 1.5,Guido才引入了名字压缩(name mangling)的概念,使得类中的一些属性得以局部化。在进行定义类时,如果一个属性的名称是以两个下划线开始,同时又不是以下划线结束的,那么它在编译时将自动地被改写为类名加上属性名。例如:

class Greeting:

__data = "Hello World!"

def __init__(self, str):

Greeting.__data = str

>>> g = Greeting("Hello Gary!")

>>> dir (g)

['_Greeting__data', '__doc__', '__init__', '__module__']

从上面的显示结果可以看出,Greeting类的属性__data变成了_Greeting__data。虽然这样仍然无法阻止外界对它的访问,但的确使得访问变得不再那么直接了,从而在一定程序上保护了类中的数据不被外界破坏。

五、在Python中应用设计模式


共3页 首页 上一页 [1] [2] [3下一页 尾页>
上一篇:
下一篇: 介绍 Python 语言
字母检索 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z