...

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.关门()

对比示意图如下

graph LR subgraph 面向过程 A1[定义 打开冰箱门] A2[定义 把大象放进去] A3[定义 关上冰箱门] A[打开冰箱门]-->B[把大象放进去] --> C[关上冰箱门] end subgraph 面向对象-按主体归类 D([冰箱])-->D1[开门] D-->D2[关门] E([大象])-->E1[进入冰箱] F([冰箱.开门]) --> G([大象.进入冰箱]) -->H([冰箱.关门]) end

类与对象(实例)的关系

和函数声明和函数调用一样,面向对象也分为定义和使用两部分。
通常我们使用一种抽象的泛指概念来描述一类事物,如人类,动物,猫,冰箱等等,这种问称之为类。
而符合该类的某一个具体的事物,如张三、一只名为泡芙的猫、我家的西门子冰箱等等,这种称为实例,即一个具体的对象。
张三是人类的实例,泡芙是猫的实例,我家的西门子冰箱是冰箱的实例。

面向对象,一般的使用方法为:

  1. 定义类,描述对象属性和对象操作
  2. 调用类创建出一个具体的实例,使用这个实例调用其具体操作

以猫类和泡芙为例,实现代码如下。

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方法,调用该方法输出不同格式的内容。

posted @ 2020-11-21 03:18  韩志超  阅读(966)  评论(0编辑  收藏  举报