玉钩帘下香阶畔,
醉后不知斜阳晚。
——晏殊《木兰花·池塘水绿风微暖》
本期文章8100字
根据之前文章的后台统计数据推算
本期预计所需阅读时间47分钟
本系列文章已加入“维权骑士”(rightknights.com)的版权保护计划
本文原创内容受到保护
终于说到这部分了——面向对象编程。这部分有了很多与之前的部分不一样的知识。本文的类与对象的概念是整个面向对象编程的基础,所以一定要理解明白才行呀。
类(class)
在之前,我们已经见过两种编程范式——命令式(程序由语句,循环和函数所组成)和函数式(程序由纯函数,高阶函数和递归所组成)。
从这次开始我们将认识另一个非常流行的编程范式——面向对象编程(OOP, Object-Oriented Programming)。
OOP的重点在于,这种编程方式使用类创建对象。
类描述了对象的内容,但与对象本身是分开的。换句话说,类可以理解为是对象的框架、整体描述或预定义。
我们可以使用同一个类作为框架来创建多个不同的对象。
举个例子,我们可以定义一个类,叫做“人”,以这一个类作为框架可以创建出多个“人”类的对象——比如小孩子,中年人,老年人等等。类和对象都可以有自己的属性。作为整体框架,类所具有的属性当然是所有这个类的对象都必有的——比如不管是小孩子,中年人还是老年人,都会有“性别”这一个属性,那么“性别”这个属性就可以直接定义到“人”这个类上,之后,在用这个类具体定义出几个不同的“人”类对象的时候,就不必在每个对象里单独定义在类中已经定义过的“性别”属性了。由此可以看出,对象是类这个抽象框架经过具象化后的实体,后面会详细讲这个级别关系。
接着说类。
我们可以使用class语句来创建类,然后可以通过加缩进的方式来写这个类的各种附属代码(包括属性的定义和方法的定义等)。类的方法基本等同于我们之前说到的函数。方法也是用来实现某些功能的一组代码,而且方法也是由def语句来定义的,区别在于方法在类的内部,而已。
下面是一个例子,展示了一个简单的类和由它实例化的三个对象。
classCat:
def__init__(self, color, legs):
self.color = color
self.legs = legs
felix =Cat("ginger", 4)
rover =Cat("dog-colored", 4)
stumpy =Cat("brown", 3)
上面的例子中,我们定义了一个名为Cat的类,这个类有两个属性:color和legs。
之后,我们创建了这个类的3个互相独立的对象:felix, rover和stumpy,这三个对象针对类的两个属性分别拥有了具体属性值。
可以看到,在上面的例子中,我们在Cat类中定义了一个方法:__init__。__init__方法(注意,两边各有两个"_")对于所有的类都可以说是最重要的方法。
当我们在类的外部,使用类名作为函数来创建类的实例(对象)的时候,就相当于用相应的参数调用了__init__方法。比如,我们在上面的例子中,在类的定义的外部使用类名Cat作为函数名进行了调用。以调用函数的形式调用类名,就必定是要创建这个类的对象,这是对于对象的创建的一个很重要的判断标准。同时也可以看出,__init__方法的作用就是用来创建该类的对象,一般不需要用它实现其他功能。所以,__init__方法也被称为类的构造函数。
所有__init__方法都必须将self作为其第一个参数,这非常重要。但是,在调用这个方法(创建对象)的时候,我们不需要明确指定这个参数。比如上面的例子中,我们在创建对象felix的时候,传递的参数("ginger", 4)分别对应的是color和legs,而并没有指定self参数。self用来在__init__函数(方法)内部代表要创建的对象,后面会说到这件事。
类的实例(对象)具有它们自己的属性值,属性是在类中就已经定好了的(“从类继承来的属性”),但是每个对象的各个属性的具体属性值是与对象自己的特性相关联的数据。比如“人”类的“性别”属性,在某些对象中值为“男”,另一些对象的“性别”属性值就是“女”,属性是类规划好的,但是属性值是对象自己决定的。
在示例中,从Cat类的__init__方法可以看出,Cat类的所有对象都具有两个属性——颜色和腿。我们把对象实例化完成后,可以通过在对象名后面加一个点再加属性名的方式来访问属性值。来看例子:
class Cat:
def__init__(self, color, legs):
self.color = color
self.legs = legs
felix = Cat("ginger", 4)
print(felix.color)
运行结果:
>>>
ginger
>>>
不难想到,在__init__方法内部,在self后面加一个点再加属性名,向这个属性赋值,就可以设置属性的初始值。例如:
class Cat:
def__init__(self, color, legs):
self.color = "brown"
self.legs = legs
felix = Cat("ginger", 4)
print(felix.color)
rover = Cat(4)
print(rover.color)
运行结果:
>>>
brown
TypeError: __init__() missing 1 required positional argument: 'legs'
>>>
为什么向felix对象传递了参数值"ginger",但是felix的color属性值还是"brown"呢?我们可以从之前说过的函数参数的角度来理解这件事情:
"ginger"和4这两个参数值分别对应赋值给了__init__函数(方法)的color和legs变量(再次说明,不需要指定self参数)。之前说过,self用来在__init__函数(方法)内部代表要创建的对象,所以创建出的对象的实际color属性值是由__init__内部语句
self.color = "brown"
所定义的。由于这里没有使用color参数变量来为self.color赋值,所以对象的color属性值实际是"brown"。传进来的"ginger"实际上未被使用,在这种情况下,每个对象的color属性也就自然与传进来的参数没有关系。
同时也可以看出,self参数在__init__方法中的作用就是作为将要被创建的对象的一个“替身”,因为我们在__init__里需要指定定义每个属性值的方式,但是又不可能用对象名加点和属性名来表示对应的属性,那样就只针对特定名的对象,而不具有通配性了。所以我们就用self这样一个“替身”来代替所有将被创建的对象,以这样一种通用的方式来表示定义对象属性值的具体方式。
测试题16.1.
填空,创建一个类和它的构造函数,在构造函数中获取一个参数并将其分配给对象的“name”属性。然后,创建该类的一个对象。
_____ Student:
def _____ (self, name):
self _____ _____ = name
test = Student("Bob" _____
点击下方空白区域查看答案
▼
class __init__ . name)
上面这题的完整代码如下:
class Student:
def __init__ (self, name):
self.name = name
test = Student("Bob")
需要说明的是,self.name中的name与name参数是不一样的两个东西——self.name是指对象的name属性,而name参数只是代表了传进来的对应参数值。所以,参数名的name是可以用别的变量名来代替的,但是属性名的name代表了对象的属性名,决定了这个类产生的所有对象的这个属性的名字,所以属性名就没有参数变量名那么随意了。
下面的代码与上面题目的答案可以产生一样的效果:
class Student:
def __init__ (self, a):
self.name = a
test = Student("Bob")
print(test.name)
运行结果:
Bob
可以理解,对象具体有几个属性,是__init__方法内部向self定义的属性的量来决定的,而不是由传递的参数的量来决定的。
除了构造函数(__init__方法)之外,类的内部还可以定义其他方法来为类的对象添加更多功能。
请记住,在Python中,所有方法都必须将self作为其第一个参数,所有self参数都是“替身”的角色,不需要从外部向self对应参数。
在类和对象的外部调用这些方法的时候,我们用与调用属性的时候相同的“点”的语法来调用方法(对象内函数)。比如:
class Dog:
def__init__(self, name, color):
self.name = name
self.color = color
defbark(self):
print("Woof!")
fido = Dog("Fido", "brown")
print(fido.name)
fido.bark()
运行结果:
>>>
Fido
Woof!
>>>
类内部不止可以有方法,也可以有类属性。我们通过在类的内部创建变量来创建类属性,这些类属性(变量)可以从类的对象或类本身来调用。来看例子:
class Dog:
legs = 4
def__init__(self, name, color):
self.name = name
self.color = color
fido = Dog("Fido", "brown")
print(fido.legs)
print(Dog.legs)
运行结果:
可以看到,类属性由类的所有对象所共享。
测试题16.2.
填空,创建一个类,这个类包含方法sayHi( )。
class Student _____
def __init__(self, name):
self.name = name
_____ sayHi( _____ ):
print("Hi from "+ _____ .name)
s1 = Student("Amy")
s1.sayHi()
领取专属 10元无门槛券
私享最新 技术干货