Python基础06-类与对象
类与对象
类(Class)和对象(Object),也称作实例(Instance)是面向对象编程(OOP)中的重要概念。类的主要作用如下:
- 在同一模块中,对多个函数进行分组,并共享其中的变量;
- 按动作主体归类函数动作,使得逻辑更清晰。
面向过程及面向对象
面向过和面向对象是两种编程风格。
- 面向过程:主要考虑功能的实现步骤和过程,即怎么去实现,多使用函数相互组合调用实现。
- 面向对象:主要考虑动作的主体和相互关系,即谁去实现,怎么配合,使用类的继承或组合实现。
面向过程的实现逻辑如下:
- 拆分过程
- 定义函数实现每个过程(过程可以包含子过程及相互调用)
- 在主函数中组合调用各个过程函数,完成整个流程。
同时,当函数较多时可以拆分模块进行分组,模块较多时可以使用包进行分组
例如:
# 函数定义
def 打开冰箱门():
pass
def 把大象塞入冰箱():
pass
def 关闭冰箱门():
pass
# 函数调用
打开冰箱门()
把大象塞入冰箱()
关闭冰箱门()
面向对象将不同的操作按主体进行分组,然后指挥不同的对象组合完成不同的操作
面向对象实现逻辑如下:
- 根据动作主体进行建模,即需要几种对象(角色),每个对象需要哪些属性和方法
- 设计各个对象需要的类
- 在主流程中将每个类生成对象,组合对象完成整个流程操作。
同时,类可以在统一模块中,对不同的函数进行分组,并共享一些变量(即对象属性)。
例如:
# 按对象定义类
class 冰箱:
def 开门(self):
pass
def 关门(self):
pass
class 大象:
def 进冰箱(self):
pass
# 调用类生成具体对象
b = 冰箱()
e = 大象()
b.开门()
e.进冰箱()
b.关门()
对比示意图如下
类与对象(实例)的关系
和函数声明和函数调用一样,面向对象也分为定义和使用两部分。
通常我们使用一种抽象的泛指概念来描述一类事物,如人类,动物,猫,冰箱等等,这种问称之为类。
而符合该类的某一个具体的事物,如张三、一只名为泡芙的猫、我家的西门子冰箱等等,这种称为实例,即一个具体的对象。
张三是人类的实例,泡芙是猫的实例,我家的西门子冰箱是冰箱的实例。
面向对象,一般的使用方法为:
- 定义类,描述对象属性和对象操作
- 调用类创建出一个具体的实例,使用这个实例调用其具体操作
以猫类和泡芙为例,实现代码如下。
class Cat: # 定义类,使用class关键字
def talk(self): # self指具体具体的每一个实例对象,这也被称为实例绑定方法,即实例方法
print('喵~')
jiafei = Cat() # 创建实例
jiafei() # 调用实例方法
对象初始化方法
Python类中拥有很多魔术方法,起不同的作用,其中__init__(self)
方法称作对象初始化方法,在调用类创建对象时自动调用,通常作用如下:
- 将创建类传人的参数,绑定到对象属性
- 做一些对象初始化操作
例如
class Student:
def __init__(self, name, age):
print('我是一个学生')
self.name = name
self.age = age
创建对象时将自动将参数传递给对象,并打印初始化信息,例如:
lilei = Student('李磊', 18) # 创建对象
print(lilei.name, lilei.age)
运行可以看到在创建对象lilei时自动输出“我是一个学生”,并且可以使用对象的name,age属性获得传人的参数值。
类属性及实例属性
类中的属性称为类属性,绑定self的属性称为实例属性,同时实例自动继承类属性。
- 类属性:可以使用类名或对象访问
- 对象属性:一般使用对象进行访问
例如:
class Student:
role = '学生' # 类属性
def __init__(self, name, age):
self.name = name # 对象属性
self.age = age # 对象属性
lilei = Student('李磊', 18) # 生成对象
print(lilei.role) # 使用对象引用类属性
print(lilei.name, lilei.age) # 使用对象引用对象属性
print(Student.role) # 使用类名引用类属性
类方法、实例方法及静态方法
类和实例是两种不同的范畴,因此在类中可以实例方法,也可以有类方法,如果方法根类和实例都没有关系,则可以设置成静态方法,示例如下:
from datetime import datetime
class Student:
role = '学生' # 类属性
def __init__(self, name, age):
self.name = name # 对象属性
self.age = age # 对象属性
def get_name(self): # 实例方法,self代表实例本身
return self.name
@classmethod
def get_class_role(cls): # 类方法,cls代表当前类名
return cls.role
@staticmethod
def get_datetime(): # 静态方法,与类和对象都无关 (无需访问类/对象属性或调用其方法)
return datetime.now().strftime('%Y%m%d %H:%M:%D')
# 使用对象调用
lilei = Student('李磊', 18) # 生成对象
print(lilei.get_name()) # 对象调用实例方法
print(lilei.get_class_role()) # 对象调用类方法
print(lilei.get_datetime()) # 对象调用静态方法
# 使用类名调用,注意类名后不加括号(加括号是调用类并生成对象,即实际为对象)
print(Student.get_class_role()) # 类名调用类方法
print(Student.get_datetime()) # 类名调用静态方法
严格来说,类名也可以调用对象方法,但是需要传入一个对象本身,例如:
lilei = Student('李磊', 18) # 生成对象
print(Student.get_name(lilei)) # 类名调用对象方法,需要一个对象
面向对象3大特性
- 封装:封装就是隐藏对象的属性和实现细节,将对象属性及操作封装称对象的某个方法;
- 继承:继承是指,类可以一种方式快速包含另一个类中的全部属性及功能,被继承的类称为父类;
- 多态:多态建立在继承的基础上,多态是指不同的子类继承父类的某一方法后,可以在子类中覆盖并实现各自不同的逻辑。
封装
例如
class Student:
def __init__(self, name, age):
self._name = name
self._age = age
def get_name(self):
"""获取姓名"""
return self._name
def get_age(self):
"""获取年龄"""
return self._age
def introduce(self):
"""自我介绍"""
print('我叫 %s,年龄 %d' %(self.get_name(), self.get_age()))
这里对象名称及年龄为私有属性_name
及_age
,类中对属性的获取封装称对象方法(相当于公开接口),以供用户使用。
使用方式如下:
lilei = Student('李磊', 18)
print(lilei.get_name(), lilei.get_age())
继承
例如
class Person:
def __init__(self, name, age):
self._name = name
self._age = age
def get_name(self):
"""获取姓名"""
return self._name
def get_age(self):
"""获取年龄"""
return self._age
class Student(Person): # 继承Person类并快速拥有其方法
def introduce(self):
"""自我介绍"""
print('我叫 %s,年龄 %d' %(self.get_name(), self.get_age()))
多态
例如
class Person:
def __init__(self, name, age):
self._name = name
self._age = age
def get_name(self):
"""获取姓名"""
return self._name
def get_age(self):
"""获取年龄"""
return self._age
class Student(Person):
def get_name(self):
return '学生: ' + self._name
class Staff(Person):
def get_name(self):
return '职员: ' + self._name
两个子类中都对父类Person中的get_name方法进行了重写(覆盖)。同时,不同的子类Student和Staff的对象都有get_name方法,调用该方法输出不同格式的内容。