简介
如果你已经学会了函数式编程过程,那么基本上可以解决一些常见的问题了。但是想编写大型复杂的程序,此时就需要用到类(class)这种方法了。一般来说,python的开发方法分为面向过程和面向对象两种,而使用类就属于面向对象的方式。
面向过程和面向对象
面向过程和面向对象(Object Oriented Programming,简称OOP)只是两种不同的编程方法,他们都可以实现同样的功能,区别就在于面向过程关注程序运行过程的细节,而面向对象更关注这个过程的参与者,也就是对象。比如,我们要写一个去奶茶店买奶茶的程序:
面向过程的方法:去奶茶店—选择某种口味奶茶—寻找制作原料—制作该口味的奶茶—将奶茶送到你手上—喝奶茶;
面向对象的方法:首先把你这个人和奶茶店看成是两个对象,每个对象都有自己的属性(变量)和方法(函数),比如:奶茶店的属性有名字、店的位置等,方法有制作奶茶,买卖奶茶等。这些属性和方法都是先封装到一个类当中。于是面向对象做了一件什么事呢?它就是负责关注对象之间的联系,你去奶茶店买奶茶,奶茶店做好奶茶给了你这样一件事。
换句话说,面向过程注重编程中的细节,而面向对象不需要关注这些细节的实现过程,只是从宏观上进行控制。在编写大型项目的时候,面向对象就能展现它的优势了,可以将大型项目分成许多小的对象,然后安排给不同的人去开发,最后只要组装这些对象就够了。
类的定义
说了那么多,那么类是什么角色呢?类可以看成是产生对象的模板,比如:有一个类叫People,通过这个People能够产生小明、小红、小张等具体的对象。在类中包括两部分:
属性:变量
方法:函数
People的属性可以有名字、年龄、身高、体重等描述人的变量,方法可以有听、说、读、写等描述人的函数。People中的属性和方法在产生对象(小明、小红、小张)的时候就赋予了他们。
创建类
创建一个类的格式如下:
class 类名():
属性
def 方法名(self, 参数):
code block
1
2
3
4
class类名():
属性
def方法名(self,参数):
codeblock
通过class关键字创建一个类,这个类中包括属性和方法。需要注意几点:
当这个类不用继承其他类时,后面可以不加括号();
类名的命名遵循骆驼记法(camelCase),比如:BuyBook、MyDataWithMethod等,首字母大写;
方法中需要加self参数,这个参数代表实例对象本身。这个参数本身不接受传入值,如果你不是很清楚,只需知道当定义方法的时候,需要这个参数就够了。
我们现在就创建一个People的类:
class People():
hand = '手'
foot = '脚'
body = '身体'
head = '头'
def write(self):
print('I am writing')
def read(self):
print('I am reading')
def listen(self):
print('I am listening')
def speak(self):
print('I am speaking')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
classPeople():
hand='手'
foot='脚'
body='身体'
head='头'
defwrite(self):
print('I am writing')
defread(self):
print('I am reading')
deflisten(self):
print('I am listening')
defspeak(self):
print('I am speaking')
我们创建完People类后,在这个类中包含了四个属性(手、脚、身体和头)和四个方法(听、说、读和写)。接下来我们就会介绍如何产生对象。
对象的定义
定义好了类相当于写好了一个模板,真正要使用该类,则是通过产生对象来调用这些属性和方法。类本身是一个抽象的概念,而对象就是这个抽象概念的具体化。
创建对象
通过类产生对象的过程称为实例化。它的格式如下:
对象名1 = 类名()
对象名2 = 类名()
1
2
对象名1=类名()
对象名2=类名()
可以看出就是通过简单的赋值=,就实例化了一个对象。对象调用属性和方法的格式如下:
对象名.属性
对象名.方法()
1
2
对象名.属性
对象名.方法()
我们可以将一个类实例化成多个对象,这些对象之间的属性和方法都是独立的,互不干扰。
接下来我们创建(小明、小红和小张)三个人:
>>>xiaoming = People()
>>>xiaoming.hand
'手'
>>>xiaoming.write()
I am writing
>>>xiaohong = People()
>>>xiaohong.foot
'脚'
>>>xiaohong.read()
I am reading
>>>xiaozhang = People()
>>>xiaozhang.body
'身体'
>>>xiaozhang.listen()
I am listening
>>>xiaozhang.head = '大头'
>>>xiaozhang.head
'大头'
>>>xiaoming.head
'头'
>>>xiaohong.head
'头'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
>>>xiaoming=People()
>>>xiaoming.hand
'手'
>>>xiaoming.write()
Iamwriting
>>>xiaohong=People()
>>>xiaohong.foot
'脚'
>>>xiaohong.read()
Iamreading
>>>xiaozhang=People()
>>>xiaozhang.body
'身体'
>>>xiaozhang.listen()
Iamlistening
>>>xiaozhang.head='大头'
>>>xiaozhang.head
'大头'
>>>xiaoming.head
'头'
>>>xiaohong.head
'头'
在以上的例子中,我们实例化了xiaoming(小明)、xiaohong(小红)和xiaozhang(小张)三个人,并且通过.调用属性和方法。这三个人的属性和方法是独立,都是通过People这个类产生。因此当我们改变xiaozhang(小张)的head为'大头'时,小明和小红的head属性不变。
如果我们紧接着输入以下命令:
>>>People.head = '超级大头' #改变类People的属性
>>>People.head
'超级大头'
>>>xiaoming.head #已经实例化的对象属性不会变
'头'
>>>xiaohong.head
'头'
>>>xiaozhang.head
'大头'
>>>xiaowang = People() #新建的对象属性发生改变
>>>xiaowang.head
'超级大头'
1
2
3
4
5
6
7
8
9
10
11
12
>>>People.head='超级大头'#改变类People的属性
>>>People.head
'超级大头'
>>>xiaoming.head#已经实例化的对象属性不会变
'头'
>>>xiaohong.head
'头'
>>>xiaozhang.head
'大头'
>>>xiaowang=People()#新建的对象属性发生改变
>>>xiaowang.head
'超级大头'
当我们修改类People中的head属性时,已经实例化的对象xiaoming、xiaohong和xiaozhang的head属性不会变,然而新建的对象xiaowang的head属性发生了变化。
构造方法
在上面的例子中,我们创建的三个人都有四个相同的属性(手、脚、身体和头), 而并不能区分这是谁的手,这是谁的头。因此我们需要让类接受对应的参数,能够变化的处理一些问题。这个时候,构造方法就显得特别重要了。构造方法是指在对象创建的时候自动执行的方法,也叫初始化方法。表示成__init__(),具体的格式如下:
class 类名():
属性
def __init__(self, 参数):
code block
def 方法名(self, 参数):
code block
1
2
3
4
5
6
class类名():
属性
def__init__(self,参数):
codeblock
def方法名(self,参数):
codeblock
针对不同对象输出不同的名字,我们可以这样来处理:
class People():
hand = '手'
foot = '脚'
body = '身体'
head = '头'
def __init__(self, name):
self.name = name
def listen(self):
print(self.name + ' is listening')
def speak(self):
print(self.name + ' is speaking')
1
2
3
4
5
6
7
8
9
10
11
12
13
classPeople():
hand='手'
foot='脚'
body='身体'
head='头'
def__init__(self,name):
self.name=name
deflisten(self):
print(self.name+' is listening')
defspeak(self):
print(self.name+' is speaking')
在上面的构造方法中self后面传入了参数name,它将接受对象的名字。完成该类定义后,我们就可以重新实例化三个具体的对象:
>>>xiaoming = People('xiaoming')
>>>xiaoming.listen()
xiaoming is listening
>>>xiaohong = People('xiaohong')
>>>xiaohong.listen()
xiaohong is listening
>>>xiaozhang = People('xiaozhang')
>>>xiaozhang.listen()
xiaozhang is listening
1
2
3
4
5
6
7
8
9
10
11
>>>xiaoming=People('xiaoming')
>>>xiaoming.listen()
xiaomingislistening
>>>xiaohong=People('xiaohong')
>>>xiaohong.listen()
xiaohongislistening
>>>xiaozhang=People('xiaozhang')
>>>xiaozhang.listen()
xiaozhangislistening
在实例化的时候,类People括号中的参数实际上是传给了构造函数__init__()中的参数name。同样可以看到,对象跟对象之间的数据不会互相影响。有了构造函数,事实上我们可以将属性都放到构造函数当中进行初始化。比如:
class People():
def __init__(self, name):
self.hand = '手'
self.foot = '脚'
self.body = '身体'
self.head = '头'
self.name = name
...
1
2
3
4
5
6
7
8
classPeople():
def__init__(self,name):
self.hand='手'
self.foot='脚'
self.body='身体'
self.head='头'
self.name=name
...
私有属性和私有方法
在类中还存在私有属性和方法,顾名思义,这些属性和方法只能在类中使用,有点像局部变量的概念。通过两个下划线__开头定义私有属性和方法,例如:
class People():
__hand = '手'
hand = '手'
def finthon(self):
print('welcome')
xiaoming = People()
print(xiaoming.hand)
print(xiaoming.__hand)
1
2
3
4
5
6
7
8
9
10
classPeople():
__hand='手'
hand='手'
deffinthon(self):
print('welcome')
xiaoming=People()
print(xiaoming.hand)
print(xiaoming.__hand)
结果为:
手
Traceback (most recent call last):
File "XXX", line 10, in
print(xiaoming.__hand)
AttributeError: 'People' object has no attribute '__hand'
1
2
3
4
5
手
Traceback(mostrecentcalllast):
File"XXX",line10,in
print(xiaoming.__hand)
AttributeError:'People'objecthasnoattribute'__hand'
可以看出私有属性__hand不能被外部调用。
总结
本文介绍了类的概念。从面向过程和面向对象的区别开始,引申出类在面向对象中的应用;通过实例化类产生对象,对象可以调用类的属性和方法,对象与对象之间的数据不会产生影响;通过构造方法能够初始化许多自定义的量,使得类的应用更加灵活。平时编写小型项目时,即使你有些看不懂类也没关系,通过面向过程编程也是可以的。但是以后想做大型项目的话,类就非常重要了。