【循序渐进学Python】7.面向对象的核心——类型(上)
我们知道Python是一门面向对象的脚本语言。从C#的角度来看:首先Python支持多继承。Python 类型成员通常都是public的,并且所有成员函数都是virtual的(可以直接重写)。
1. 定义类型
类是对象的模板,在Python中我们使用class
关键字来定义一个类型。
1 # -- coding: utf-8 -- 2 class Employee(object): 3 # self 关键字就是对象自身的一个引用(类似于C#中的this关键字) 4 def setName(self,name): 5 self.name = name 6 7 def getName(self): 8 return self.name 9 10 def greet(self): 11 print "hello,world! I'm %s" % self.name
可以这样使用我们定义好的Employee
类:
1 foo = Employee() 2 bob = Employee() 3 foo.setName('Sunshine') 4 bob.setName('Bob') 5 6 foo.greet() # hello,world! I'm Sunshine 7 bob.greet() # hello,world! I'm Bob 8 print foo.name # Sunshine 9 bob.name = 'Bob2' # name是Employee类的一个特性 10 bob.greet() # hello,world! I'm Bob2
1.1 使用新式类型
在Python 2.2之后,对象的工作方式有了很大的改变,所有导致了在Python 2.x 版本中存在两种形式的类:Python 2.2之前的旧式类,和之后新增的新式类,新式类提供了很多新的特性(比如:super
函数、property
函数等),如果不需要兼容旧版本的Python代码那么做好使用新式类,在Python中声明新式类有两种方法:
1.把赋值语句__metaclass__ = type
放置在定义模块的最开始位置,如下:
# -- coding: utf-8 -- _metaclass_ = type # 确定使用新式类 class Employee(): pass
2.子类化object
类型,或者是其他新式类型,如下:
class NewStyle(object): pass
2. 特性和成员方法
对象包括特性和方法,特性只是作为对象的一部分的变量,成员方法则是存储在对象内部的函数。Python中的所有方法函数在声明时显式地将第一个参数(self
)表示为对象(实例),这个参数的值在方法被调用时隐式赋值:
1 # -- coding: utf-8 -- 2 _metaclass_ = type # 确定使用新式类 3 4 class Class: 5 def method(self): 6 print 'I have a self' 7 8 def function(): 9 print 'i don\'t...' 10 11 instance = Class() 12 instance.method() # I have a self 13 instance.method = function # 绑定一个普通的函数 14 instance.method() # i don't...
通过self
参数可以使用该实例的所有成员对象:
1 # -- coding: utf-8 -- 2 _metaclass_ = type # 确定使用新式类 3 4 class Bird: 5 song = 'Squaawk!' 6 def sing(self): 7 print self.song 8 9 bird = Bird() 10 bird.sing() # Squaawk!
2.1 私有变量和私有方法
Python其实并不存在不能访问的私有变量和私有方法。不过在Python中有一个约定:以一个下划线(_)开头的名字,应该作为一个非公共的API(不论是函数、方法或者数据成员)。我们可以这样定义一个"私有变量":
_flag = True
Python解释器在遇到任何以双下划线(__)开头的标识符将会被替换为_className__spam
形式,其中className是当前的类型名称,__spam
就是当前的标识符名称。所以我们可以这样定义一个"私有方法":
1 # -- coding: utf-8 -- 2 _metaclass_ = type # 确定使用新式类 3 4 class Secretive: 5 def __inaccessible(self): 6 print 'Bet you can\' see me...' 7 8 def accessible(self): 9 print 'The secret message is:' 10 self.__inaccessible() 11 12 s = Secretive() 13 # AttributeError: Secretive instance has no attribute '__inaccessible' 14 s.__inaccessible()
因为在类的内部定义中,所有以双下划线开始的名字都被转换成前面加上单下划线和类名的形式,所以还是可以访问私有方法:
# Bet you can' see me... s._Secretive__inaccessible()
3. 继承
作为面向对象三个基本的特性之一———继承,我们可以利用它在现有类型的基础上创建自己的类型。在Python中定义派生类的方式如下:
1 # -- coding: utf-8 -- 2 _metaclass_ = type # 确定使用新式类 3 4 class Person: 5 def printName(self): 6 print 'Is a Person' 7 def printHello(self): 8 print 'hello,world' 9 10 class Employee(Person): 11 # override base Method 12 def printName(self): 13 print 'Is a Employee' 14 15 person = Person() 16 person.printName() # Is a Person 17 employee = Employee() 18 employee.printName() # Is a Employee 19 employee.printHello() # hello,world
可以看到子类继承了基类的方法,由于在Python中所有的成员函数都是virtual的,所有我们也可以选择重写基类的方法。
3.1 多重继承
Python是一个多继承语言,使用多重继承的语法很简单,只需要在定义子类后面的括号中添加多个父类名称即可,如:
class C(A,B): pass
注意
多重继承(multiple inheritance)是个很有用的工具。不过除非你特别熟悉多重继承,否则应该尽量避免使用。因为它可能会有很多出乎意料的行为。例如:一个方法从多个超类继承,那么根据继承的顺序(class语句中):先继承的类中的方法会重写后继承类中的方法。
3.2 查看继承关系
Python中有两个内置函数可拥有查看继承关系:
- 使用
isinstance
函数检查实例的类型 - 使用
issubclass
函数检查类的继承关系
使用方式如下:
1 # -- coding: utf-8 -- 2 obj = "string" 3 print isinstance(obj,str) # True 4 print obj.__class__ # <type 'str'> 5 6 print issubclass(bool,int) # True 7 print bool.__bases__ # (<type 'int'>,)
3.3 检查对象中的方法是否存在
使用hasattr(x,'call')
来判断一个对象是否存在某个方法,如下:
1 # -- coding: utf-8 -- 2 _metaclass_ = type # 确定使用新式类 3 4 class Person: 5 def PrintName(self): 6 print 'Is a Person' 7 def PrintHello(self): 8 print 'hello,world' 9 10 per = Person() 11 12 # check method Exists 13 print hasattr(per,'PrintName') # True