28 类的基础--设计、使用
上一章说过,类是事物功能和属性的抽象,对象是类的实例化。就像人人都知道小汽车可以干什么什么的,但光想小汽车如何好是没有用的,得开车或坐才能感受到小汽车的好。人脑里的小汽车是抽象的即类,而坐上的某辆车是小汽车的实例化即对象。 所以,如果一门语言提供了、支持面向对象编程的机制,那么首先得先设计程序所需要的类,然后再在程序里将这些类实例化产生对象,通过对象这个程序元素(和变量、函数等起着相同的作用,构成程序的基本元素),所以类的设计是面向对象编程是否有效、合理、成功的关键。
28.1 类
类总的来说是专有数据用专用方法处理,即数据和处理数据方法的集合,故类的里有数据(属性)和函数(功能),且类里的数据必须用类里的方法来操作处理。
类里的这些函数也有时又称方法、成员函数,如果方法或函数作用于类本身称之为类方法,如果方法作用于由类产生出的实例对象上,这些方法称之为实例对象的方法。类里的数据称为属性(类属性和实例对象属性)、成员变量。
类不能无源而生,需有自己的父类,而object这个类是Python下的根类(base class),也就是说用户自己的类可以继承object 这个类作为自己(父)类的起点,类的父类需要用圆括号括起来放在类名字的后边。
28.1.1 定义类
基于上边讲述,定义一个常规的类格式如下:
class 类名字(父类序列):
类的成员变量 = 初值
def __init__(self, 形参序列):
self.实例对象的成员变量名 = 初值
其他语句
def 其他实例对象函数名(self,形参序列):
语句
@classmethond
def 类的成员函数名(cls,形参序列):
cls.类的成员变量名 = 初值
语句
@staticmethond
def 函数名(形参序列):
语句
类的语法格式里出现了一些奇奇怪怪的符号,下面一一解释一下。 class和定义函数的def一样是Python里的关键字,用于定义一个类的标识符。
位于class下和_ _init_ _函数间声明的变量是类的变量,可被类或类的对象共有。
_ _init_ _可以成为类的实例对象的构造函数,每次通过类创建一个该类的对象是调用此函数,所以其下的以sefl.前缀的变量是每个创建好了的实例(化)对象的所独有的。换句话说,有多少个类的对象内存里就有多少份这个实例对象变量存在。就像生产了多少小汽车就有多少个方向盘似的。
self代表运行时的类的实例对象本身,一般在类的内部设计时出现,在程序里使用对象编程时不用self。在实例对象的成员函数里以self.前缀的变量是实例对象的成员变量,没有self.的变量是本方法函数的局部变量。
cls和self出现在构造和实例对象函数的第一个参数位置上一样,cls关键字出现在类的方法函数里,区分于对象函数和变量时会用到。在类的函数里以cls.前缀的变量也是类的成员变量,没有这个前缀的是局部变量。
@classmethon这个关键字是修饰器,修饰也是说下面的函数是类的方法函数而不是类的对象的方法函数。
@staticmethod 这个也是修饰器,说明接下来的函数是一个静态函数,和实例对象的成员函数、类函数的区别主要在第一个形参,既无self又无cls。可以被类或对象直接调用。 差不多解释完了,下面来看一个具体的类的实例程序。
28.1.2 定义一个类的示例
下面创建一个Horse类,类里除了有实例对象的方法函数、类方法函数和静态方法函数,还有实例对象成员变量和类变量。
# coding:utf-8
class Horse(object):
variety = "大宛马"
def __init__(self, name = "green", height = 0.5, length = 1.3, sex = "male"):
self.name = name
self.height = height
self.length = length
self.sex = sex
print "A baby horse is born called", self.name
@classmethod
def pp(cls):
print cls.variety, Horse.variety, cls.address
@classmethod
def print_variety(cls):
cls.address = "xi'an"
print cls.variety, Horse.variety, cls.address
Horse.pp()
def print_info(self):
print self.name, self.height, self.length, self.sex, Horse.variety#,Horse.address
Horse.print_variety()
@staticmethod
def print_ci(x, y):
print x, y
1). 出现在class下一行的variety是类Horse的变量,是类变量,可以通过Horse.variety在类的内部或者外部任何地方被访问。
2). _ _init_ _函数是Horse类的实例对象的构造函数,每次创建一个Horse类的实例对象时,这个函数均会被调用执行,其下以self.开始的变量是每个实例对象的成员变量,即标地这个实例对象的属性、特征用的。
3). 用修饰器@classmethod修饰的两个函数pp、print_variety,是类Horse的类函数,类函数只可通过类或cls使用。 在pp这个函数里可以看出一点,在类的内部类变量的使用需前缀类名.或cls.。
类名.类变量
cls.类变量
从print_variety函数可以看出,在类的内部可以通过类调用类的方法函数。
类名.类方法
4). 用@staticmethod修饰的print_ci函数是静态函数,它的第一个参数不是特殊的self或者cls,静态函数可在类内部或类的外部调用,也可被类的对象调用。
28.2 创建对象
面向对象编程实际是在设计好类以后,用与类同名的函数来创建类的对象,用类的对象调用对象的方法函数来编写整个程序,有时可能根据需要少量地用类调用类方法的语句代码出现,一般都是对象调用类里设计好的对象方法函数来完成整个程序的功能,故称面向对象编程。
创建类的实例对象的语法:
变量 = 类名([参数序列])
通过这样的方式创建类的实例对象本质是调用了类里的_ _ init_ _()方法函数,括号里的[参数序列]意思是看_ _ init_ _()方法函数是否有除self外的其他形参,如无,换括号里没有任何实参。
需要特别说明的是任何实例对象的self形参不用赋值,在Python解译执行程序语句时self代表点儿运算符(.)前的实例对象,或者说self被Python赋值为点儿运算符前的实例对象。
a = Horse(sex = "male")
b = Horse(name = "marong", sex = "female")
28.3 面向对象编程示例
面向对象编程,需要两步,第一步先设计好类,第二步基于类创建对象并通过对象调用函数来完成整个程序需要实现的功能。 下面是本章设计的一个Horse类的面向对象程序设计的完整示例。
# coding:utf-8
class Horse(object):
variety = "大宛马"
def __init__(self, name = "green", height = 0.5, length = 1.3, sex = "male"):
# self.name是成员变量,name是形参、局部变量
self.name = name
self.height = height
self.length = length
self.sex = sex
print "A baby horse is born called", self.name
def print_info(self):
print self.name, self.height, self.length, self.sex, Horse.variety#,Horse.address
Horse.print_variety() # 在对象方法里通过类调用类方法,避免
Horse().print_ci(200, 100)# 对象调用静态方法
Horse.print_ci(200, 100) # 类调用静态方法
@staticmethod
def print_ci(x, y):
print x, y
@classmethod
def pp(cls):
# 类使用类变量
print cls.variety, Horse.variety, cls.address
#cls.print_variety()
print Horse().name # 对象使用对象的成员变量
@classmethod
def print_variety(cls):
cls.address = "xi'an"
print "type", type(cls.address)
print cls.variety, Horse.variety, cls.address
Horse.pp()# 类调用类方法
Horse().print_ci(100, 100)# 对象调用静态方法
a = Horse("xiaoxuanfeng")
b = Horse("pilihuo", sex = "female")
a.print_info()
b.print_info()
Horse.print_variety()
print "*" * 20
Horse.pp() # 类调用类方法
Horse.print_ci(12, 23)# 类外类调用静态方法
a.print_ci(23, 31) # 类外对象调用静态方法