文章目录
前言
本文的主要内容是Python中类的介绍及使用,具体包括面向对象与面向过程的介绍、类的创建和使用、使用类和实例、继承、类的导入和Python标准库的使用,文中附有代码以及相应的运行结果辅助理解。
一、面向对象与面向过程
面向过程(procedure-oriented):注重过程,在解决一个问题的时候,面向过程会把事情拆分成 一个个函数和数据,然后按照一定的顺序,依次执行这些方法,等方法执行完了,问题就解决了。
面向对象(object-oriented):注重对象,在解决一个问题的时候,面向对象会把事物抽象成若干个对象,然后再给对象赋一些属性和方法,让每个对象去执行自己的方法,问题得到解决。
举一个例子:洗衣机洗衣服。
面向过程:
1.把衣服放进洗衣机;
2.往洗衣机中注水;
3.加入洗衣液;
4.启动洗衣机;
5.洗衣机清洗;
6.洗衣机烘干。
面向过程洗衣服就是按照顺序按部就班的执行一个个的“函数”。
面向对象:
先抽象出两个对象:“人”和“洗衣机”。
对“人”加一些属性和方法:“把衣服放进洗衣机”、“往洗衣机中注水”、“加入洗衣液”、“启动洗衣机”。
对“洗衣机”加一些属性和方法:“洗衣机清洗”、“洗衣机烘干”。
执行:人——“把衣服放进洗衣机”;人——“往洗衣机中注水”;人——“加入洗衣液”;人——“启动洗衣机”;洗衣机——洗衣机清洗;洗衣机——洗衣机烘干。
面向对象洗衣服就是先抽象出类,然后各个类再分别调用“方法”。
二、类的创建和使用
面向对象编程是最有效的软件编写方法之一,在面向对象编程中,你编写表示现实世界中的事物和情景的类,并基于这些类来创建对象。编写类时,你定义一大类对象都有的通用行为,基于类创建对象时,每个对象都自动具备这种通用行为,然后可根据需要赋予每个对象独特的个性。根据类来创建对象被称为实例化,这让你能够使用类的实例。
根据约定,在Python中,首字母大写的名称指的是类,类中的函数称为方法,通过实例访问的变量称为属性。
方法__init__()是一个特殊的方法,每当你给类创建新的实例时,Python都会自动运行它。在这个方法的名称中,开头和末尾各有两个下划线,这是一种约定,旨在避免Python默认方法与普通方法发生名称冲突。在这个方法的定义中,形参self是必不可少的,还必须位于其他形参的前面,因为Python调用__init__()方法来创建实例时,将自动传入实参self,因此我们不需要传递它,只需要给self后面的参数传递实参即可。每个与类相关联的方法调用都自动传递实参self,它是一个指向实例本身的引用,让实例能够访问类中的属性和方法。
下面是一个类的创建和使用的例子。
class User():
"""定义用户的类"""
def __init__(self, first_name, last_name, gender, age):
"""初始化属性"""
self.name = first_name.title() + ' ' + last_name.title()
#获取存储在形参first_name和last_name中的值,并将其存储到变量name中
self.gender = gender
self.age = age
#这里的name,gender和age都是属性
def describe_user(self):
"""描述用户的方法"""
if self.gender == 'male':
print("This user's name is " + self.name + ", and his age is " + str(self.age) + ".")
elif self.gender == 'female':
print("This user's name is " + self.name + ", and her age is " + str(self.age) + ".")
def greet_user(self):
"""问候用户的方法"""
print("Hello, " + self.name + "!")
#这里的describe_user()和greet_user()都是方法
user_1 = User('lebron', 'james', 'male', 37) #根据类创建实例,Python遇到这行代码会调用方法__init__()来提供属性
print('name : ' + user_1.name) #用句点表示法访问实例的属性
print('gender : ' + user_1.gender)
print('age : ' + str(user_1.age))
user_1.describe_user() #用句点表示法调用方法
user_1.greet_user()
print()
user_2 = User('rachel', 'green', 'female', 24) #创建多个实例
print('name : ' + user_2.name) #用句点表示法访问实例的属性
print('gender : ' + user_2.gender)
print('age : ' + str(user_2.age))
user_2.describe_user()
user_2.greet_user()
运行结果如下图所示。
由运行结果可知,对于类中的属性可以用句点表示法访问实例的属性,也可以直接调用类中的方法。
三、使用类和实例
可以使用类来模拟现实世界中的很多情景,类编写好以后,大部分时间都将花在使用根据类创建的实例上,还要执行的一个重要任务是修改实例的属性,可以直接修改实例的属性,也可以编写方法以特定的方式进行修改。
1.给属性指定默认值
类中的每个属性都必须有初始值,即使这个值是0或空字符串。在有些情况下,如设置默认值时,如果在方法__init__()内指定了初始值,那么在后面的括号中就无需包含其形参。
下面是给属性指定默认值的例子。
class User():
"""定义用户的类"""
def __init__(self, first_name, last_name, gender, age): #不用给login_attempts传递形参
"""初始化属性"""
self.name = first_name.title() + ' ' + last_name.title()
#获取存储在形参first_name和last_name中的值,并将其存储到变量name中
self.gender = gender
self.age = age
self.login_attempts = 0 #给属性指定默认值后不用再传递形参
def print_login_attempts(self):
"""打印属性login_attempts"""
print('login_attempts in function: ' + str(self.login_attempts))
user = User('lebron', 'james', 'male', 37) #不用给login_attempts传递实参
print('name : ' + user.name) #用句点表示法访问实例的属性
print('gender : ' + user.gender)
print('age : ' + str(user.age))
print('login_attempts : ' + str(user.login_attempts)) #直接访问实例属性
user.print_login_attempts() #调用方法打印属性login_attempts
运行结果如下图所示。
由运行结果可知,我们给属性指定默认值之后,可以直接访问实例的该默认属性,也可以通过方法来访问,其结果都是一样的。
2.修改属性的值
修改属性的值可以用三种不同的方式:直接通过实例进行修改;通过方法进行修改;通过方法进行递增。
下面是修改属性值的例子,里面包含了上面提到的三种方法。
class User():
"""定义用户的类"""
def __init__(self, first_name, last_name, gender, age): #不用给login_attempts传递形参
"""初始化属性"""
self.name = first_name.title() + ' ' + last_name.title()
#获取存储在形参first_name和last_name中的值,并将其存储到变量name中
self.gender = gender
self.age = age
self.login_attempts = 0 #给属性指定默认值后不用再传递形参
def print_login_attempts(self):
"""打印属性login_attempts"""
print('print_login_attempts login_attempts : ' + str(self.login_attempts))
def update_login_attempts(self, value):
"""修改属性login_attempts的值"""
self.login_attempts = value
print('update_login_attempts login_attempts : ' + str(self.login_attempts))
def increment_login_attempts(self, value):
"""修改属性login_attempts的值"""
self.login_attempts += value
print('increment_login_attempts login_attempts : ' + str(self.login_attempts))
user = User('lebron', 'james', 'male', 37) #不用给login_attempts传递实参
print('name : ' + user.name) #用句点表示法访问实例的属性
print('gender : ' + user.gender)
print('age : ' + str(user.age))
print('original login_attempts : ' + str(user.login_attempts)) #直接访问实例属性
user.login_attempts = 10 #直接通过实例进行修改默认属性值
user.print_login_attempts() #调用方法打印属性login_attempts
user.update_login_attempts(20) #调用方法修改默认属性的值
user.increment_login_attempts(10) #调用方法对默认属性值递增
运行结果如下图所示。
由上面运行结果可知,原始的login_attempts值为0;直接通过实例进行修改其值后为10;通过方法修改其值时会覆盖掉原来的10,修改为20;再调用方法对属性值递增,递增时不会覆盖掉已有的login_attempts值20,而是在其基础上递增10,结果即为30。
四、继承
并非所有类的编写总是从空白开始,如果你要编写的类是另一个现成类的特殊版本,可使用继承。一个类继承另一个类时,它将自动获得另一个类的所有属性和方法,原有的类称为父类(超类),而新类称为子类,子类继承了其父类的所有属性和方法,同时还可以定义自己的属性和方法。
创建子类时,父类必须包含在当前文件中,且位于子类前面。
定义子类时,必须在括号内指定父类的名称。
1.子类的方法__init__()
创建子类的实例时,Python首先需要完成的任务是给父类的所有属性赋值,而子类的方法__init__()需要父类施以援手。
super()是一个特殊函数,帮助Python将父类和子类关联起来。
下面是子类的方法__init__()编写的例子。
class User():
"""定义用户的类"""
def __init__(self, first_name, last_name, gender, age):
"""初始化属性"""
self.name = first_name.title() + ' ' + last_name.title()
self.gender = gender
self.age = age
def describe_user(self):
"""描述用户的方法"""
if self.gender == 'male':
print("This user's name is " + self.name + ", and his age is " + str(self.age) + ".")
elif self.gender == 'female':
print("This user's name is " + self.name + ", and her age is " + str(self.age) + ".")
def greet_user(self):
"""问候用户的方法"""
print("Hello, " + self.name + "!")
class Administrator(User):
"""定义子类Administrator继承父类User"""
def __init__(self, first_name, last_name, gender, age):
"""初始化父类的属性"""
super().__init__(first_name, last_name, gender, age)
admin = Administrator('lebron', 'james', 'male', 37)
admin.greet_user()
运行结果如下图所示。
通过上面的例子可以看到,子类Administrator继承了父类User的属性和方法,在子类的__init__()方法中需要用到super()来初始化父类的属性。子类继承父类后,就可以用父类中的属性和方法了。
2.给子类定义属性和方法
让一个类继承另一个类后,可添加区分子类和父类所需的新属性和方法。
下面是给子类定义属性和方法的例子。
class User():
"""定义用户的类"""
def __init__(self, first_name, last_name, gender, age):
"""初始化属性"""
self.name = first_name.title() + ' ' + last_name.title()
self.gender = gender
self.age = age
def describe_user(self):
"""描述用户的方法"""
if self.gender == 'male':
print("This user's name is " + self.name + ", and his age is " + str(self.age) + ".")
elif self.gender == 'female':
print("This user's name is " + self.name + ", and her age is " + str(self.age) + ".")
def greet_user(self):
"""问候用户的方法"""
print("Hello, " + self.name + "!")
class Administrator(User):
"""定义子类Administrator继承父类User"""
def __init__(self, first_name, last_name, gender, age):
"""初始化父类的属性"""
super().__init__(first_name, last_name, gender, age)
self.identity = 'administrator' # 添加子类的特有属性
def greet_admin(self): # 添加子类的特有方法
"""问候管理员的方法"""
print("Dear " + self.identity + ":")
print("Welcome to login, " + self.name + "!")
admin = Administrator('lebron', 'james', 'male', 37)
admin.greet_user() #调用子类继承父类的方法
admin.greet_admin() # 调用子类特有的方法
运行结果如下图所示。
可以看到,子类除了有父类的属性和方法,还可以添加新的属性和方法。
3.重写父类的方法
对于父类的方法,只要它不符合子类的要求,都可对其进行重写。为此,可在子类中定义一个这样的方法,即它与要重写的父类方法同名。这样,Python将不会考虑这个父类方法,而只关注你在子类中定义的相应方法。
下面是重写父类方法的例子。
class User():
"""定义用户的类"""
def __init__(self, first_name, last_name, gender, age):
"""初始化属性"""
self.name = first_name.title() + ' ' + last_name.title()
self.gender = gender
self.age = age
def describe_user(self):
"""描述用户的方法"""
if self.gender == 'male':
print("This user's name is " + self.name + ", and his age is " + str(self.age) + ".")
elif self.gender == 'female':
print("This user's name is " + self.name + ", and her age is " + str(self.age) + ".")
def greet_user(self):
"""问候用户的方法"""
print("Hello, " + self.name + "!")
class Administrator(User):
"""定义子类Administrator继承父类User"""
def __init__(self, first_name, last_name, gender, age):
"""初始化父类的属性"""
super().__init__(first_name, last_name, gender, age)
self.identity = 'administrator' # 添加子类的特有属性
def greet_admin(self): # 添加子类的特有方法
"""问候管理员的方法"""
print("Dear " + self.identity + ":")
print("Welcome to login, " + self.name + "!")
def describe_user(self):
"""重写父类的方法describe_user()"""
if self.gender == 'male':
print("This admin's name is " + self.name + ", and his age is " + str(self.age) + ".")
elif self.gender == 'female':
print("This admin's name is " + self.name + ", and her age is " + str(self.age) + ".")
user = User('lebron', 'james', 'male', 37)
user.describe_user() # 调用父类方法
admin = Administrator('emma', 'green', 'female', 24)
admin.describe_user() # 调用子类重写的父类方法
运行结果如下图所示。
通过上面运行结果的对比就可以知道,子类成功重写了父类的方法。
4.将实例用作属性
使用代码模拟实物时,你可能会发现给类添加的细节越来越多,属性和方法清单以及文件都越来越长,在这种情况下,可能需要将类的一部分作为一个独立的类提取出来,将大型类拆分成多个协同工作的小类。
下面是将实例用作属性的例子。
class User():
"""定义用户的类"""
def __init__(self, first_name, last_name):
"""初始化属性"""
self.name = first_name.title() + ' ' + last_name.title()
def print_name(self):
"""打印姓名"""
print("name : " + self.name)
class Attribute():
"""定义一个属性类"""
def __init__(self, gender, age):
"""初始化属性"""
self.gender = gender
self.age = age
def describe_attribute(self):
"""描述属性的方法"""
print("gender : " + self.gender)
print("age : " + str(self.age))
class Administrator(User):
"""定义子类Administrator继承父类User"""
def __init__(self, first_name, last_name):
"""初始化父类的属性"""
super().__init__(first_name, last_name)
self.attribute = Attribute('female', 24) # 将类用作属性
admin = Administrator('emma', 'green')
admin.print_name()
admin.attribute.describe_attribute() # 调用属性中的方法
运行结果如下图所示。
通过上面的例子可知,一个类可以作为另一个类的属性,这样一来,我们在完成一个复杂的问题时就可以将其拆解为多个小问题,每个小问题对应着一个小类,最后将它们合在一个大类中,大的问题就比较容易的解决了。
五、类的导入
如果不断地给类添加新的功能,文件可能变得很长,即便妥善地使用了继承也是如此,因此,可以将类存储在模块中,然后在主程序中导入所需的模块。
可以在一个模块里只存储一个类,比如在模块user.py中存储着名为User的这一个类,在主程序代码模块中导入该类时使用如下代码。
from user import User
也可以在一个模块中存储多个类,比如在模块user.py中存储着名为User、Admin等多个类,在主程序代码模块中要导入其中的几个类时使用如下代码。
from user import User, Admin
还可以使用如下代码导入user.py整个模块,再使用句点表示法访问需要的类。
import user
导入user.py模块中的所有类使用如下代码。
from user import *
下面是导入类的例子。
模块user.py中的代码如下。
class User():
"""定义用户的类"""
def __init__(self, first_name, last_name):
"""初始化属性"""
self.name = first_name.title() + ' ' + last_name.title()
def print_name(self):
"""打印姓名"""
print("name : " + self.name)
class Attribute():
"""定义一个属性类"""
def __init__(self, gender, age):
"""初始化属性"""
self.gender = gender
self.age = age
def describe_attribute(self):
"""描述属性的方法"""
print("gender : " + self.gender)
print("age : " + str(self.age))
class Administrator(User):
"""定义子类Administrator继承父类User"""
def __init__(self, first_name, last_name):
"""初始化父类的属性"""
super().__init__(first_name, last_name)
self.attribute = Attribute('female', 24) # 将类用作属性
主程序中的代码如下。
1.导入user.py整个模块。
import user
admin = user.Administrator('emma', 'green')
admin.print_name()
admin.attribute.describe_attribute() # 调用属性中的方法
2.从模块user.py中导入类。
from user import Administrator
# from user import *
# from user import User, Attribute, Administrator
# 对于本例,以上三条导入语法的运行结果一致
admin = Administrator('emma', 'green')
admin.print_name()
admin.attribute.describe_attribute()
对于本例而言,上面主程序中的代码不管是导入user.py整个模块还是从模块user.py中导入类,其运行结果都一样,如下图所示。
合理的导入类对于代码的可读性和维护性都有很大的好处。
六、Python标准库
Python标准库是一组模块,安装的Python都包含它,这是其他程序员编写好的模块,有时候我们需要用到它们,在程序开头包含一条import语句即可导入这些模块。
下面是Python标准库应用的例子。
from random import randint
class Dice():
"""掷骰子"""
def __init__(self):
self.sides = 6 #默认是6面的骰子
def roll_dice(self):
"""打印骰子点数"""
print(randint(1, self.sides))
def change_side(self,side):
"""改变骰子面数"""
self.sides = side
dice = Dice()
dice.roll_dice() # 点数在1-6之间
dice.change_side(10)
dice.roll_dice() # 点数在1-10之间
dice.change_side(20)
dice.roll_dice() # 点数在1-20之间
运行结果如下图所示。
本例用到的是random模块中的randint函数,这是Python自带的库,不用我们自己写,使用起来非常方便,使用Python标准库可以极大的方便我们编程。
总结
以上就是Python中类的介绍及使用的所有内容了,类的创建和使用是最基础也是最重要的;在继承中,子类既保留了父类的属性方法,还可以自己创建独有的属性和方法,将实例用作属性也是非常高效的编程手段;类的导入和Python标准库都是为了方便我们更好的编程,应当熟练运用。
本文参考书目:Python 编程 :从入门到实践 / (美) 埃里克•马瑟斯(Eric Matthes)著;袁国忠译
参考博文:
面向对象与面向过程的本质的区别
https://zhuanlan.zhihu.com/p/75265007
文章出处登录后可见!