查看原文
其他

Python 教学 | 一文搞懂面向对象中的“类和实例”

Python教学 数据Seminar 2023-09-18


Python教学专栏,旨在为初学者提供系统、全面的Python编程学习体验。通过逐步讲解Python基础语言和编程逻辑,结合实操案例,让小白也能轻松搞懂Python!
>>>点击此处查看往期Python教学内容

本文目录

一、引言

二、类和实例

  (一)创建类

  (二)使用类创建实例

三、如何使用类

  (一)子类与继承

  (二)模块与类的导入

四、实例

五、总结

六、Python教学系列文章

本文共7866个字,阅读大约需要20分钟,欢迎指正!

Part1引言

面向对象(Object-Oriented Programming,OOP)和面向过程(Process-Oriented Programming,POP)是目前最流行的两种编程思想,Python 在设计之初就是一门面向对象的编程语言,那么什么是面向对象的思想呢?笔者时而看到有同学提出这样的疑问,于是我们希望本篇文章能够为有疑惑的读者提供一些灵感。

首先我们需要理解 OOP 和 POP 两种编程思想的区别,举个例子,如果你现在需要盖房子,在 POP 的思想下,你要先准备工地,然后打地基,建造墙壁,安装窗户和门等等。这里的每个步骤都是独立的,并且你需要亲自掌握每个步骤的执行。而 OOP 的思想就像是雇佣了一家建筑公司来盖房子,你只需要向公司说明要求,然后他们来负责整个施工过程。建筑公司会将盖房子拆分为多个部分,如地基、墙壁、窗户等,每个部分由特定的人员负责,你只需要跟建筑公司沟通,而不必亲自掌握每个步骤的执行。

通过这个例子,我们可以总结出两种编程思想的优缺点,POP 是一种流程化的思维方式,配合着短小精悍的代码使得每个步骤很清晰,不足的是代码的复用性差,扩展性也不高。相较之下,OOP 更接近人类的思考方式,因为我们本身就具有把任务交给专人完成的本质,它允许将代码模块化,使得代码的复用性更强、更易于维护。其次,将数据和相关操作封装在一起可以隐藏内部实现细节,确保了数据的安全性。最后,OOP 具有继承性和多态性,这使得代码的可扩展性和灵活性更强。现在我们已经明确了面向对象思想的优点,下面我们来看一下其中的核心概念。

Part2类和实例

面向对象编程的两个核心概念是类(Class)和实例(Instance)。类是一个抽象的概念,我们可以将它看作一个模板或蓝图,其中描述了对象应该具有的属性和能够执行的操作。实例是根据类创建的具体对象,使用类来创建对象的过程就是实例化,每个实例都拥有类的属性和方法,并且不同实例之间相互独立,可以单独修改和操作。

下面我们将介绍如何创建类和实例。

(一)创建类

在 Python 中,类是通过class关键字来定义的,其格式为class 类名 + (),现在我们创建一个“数据库(Database)”类,然后详细介绍这个类中的内容,代码如下:

# 创建 Database 类
class Database():
    def __init__(self, name, URL):
        self.name = name
        self.URL = URL

    def describe_database(self):
        print(self.name + '数据库的访问地址是:' + self.URL + '。')

以上代码创建了一个名为 Database 的类,在这个类的内部有两段以def开头的代码,这种在类的内部定义的函数被称为“方法”,编写方法与自定义函数是一致的,但两者调用方式有所不同,这个我们在后文中再介绍。下面我们具体看一下 Database 类的两个方法。

第一个__init__()方法是一个特殊方法(也称为“类的构造函数”),两个下划线开头的这类函数是声明该属性为私有,不能在类的外部被访问或使用。当使用 Database 类创建实例时,Python 会自动调用__init__()方法,用于初始化实例的属性。在__init__()方法中,self表示类的实例本身,参数nameURL用于接收传递给实例的值,需要注意的是,该方法必须包含参数self且该参数位于首位。

__init__()方法定义的变量 name 和 URL 都是以self为前缀的,通过self.name = nameself.URL = URL__init__()方法的参数值分别赋给类的实例的属性,这就意味着类的实例创建时会持有这两个属性,并且我们也可以在类的其他方法中使用它们。

第二个describe_database()方法,它的作用是介绍数据库的特征。由于该方法没有提供额外的信息,因此只需要参数self(在调用时自动传递实例的属性),此后通过 Database 类创建的实例都可以访问这个方法,具体来说,被创建的实例都可以通过调用describe_database()方法来描述其数据库特征。

(二)使用类创建实例

现在我们就通过 Database 类来创建一个名为 NBS (“国家统计局”)的实例,访问网址为http://www.stats.gov.cn/,代码如下:

# 创建名为 NBS 的实例
NBS = Database(name='国家统计局', URL='http://www.stats.gov.cn/')

当我们根据 Database 类创建实例时,只需要为__init__()方法的两个参数提供实际值。创建实例的格式为类名(形参1 = 实参1, 形参2 = 实参2, xxx)。运行上述代码时,Python 将调用 Database 类中的__init__()方法来创建一个表示特定数据库的实例,这个数据库的属性 name 和 URL 分别接收传入的实参 '国家统计局' 和 'http://www.stats.gov.cn/',该实例存储在变量 NBS 中。

当我们创建了一个具体的实例后,就可以通过实例名.属性来访问该实例的属性,代码如下:

# 访问实例的属性
print(NBS.name) # 国家统计局
print(NBS.URL)  # http://www.stats.gov.cn/ 

此外,该实例还可以通过实例名.方法()来调用类中的其他方法,比如我们想要实例 NBS 调用describe_database()方法,代码如下:

# 调用类中的方法
NBS.describe_database() # 国家统计局数据库的访问地址是:http://www.stats.gov.cn/。

从上面的结果可以看到,创建的实例 NBS 在调用 Database 类中的方法时不再需要重复给定其自身的属性,这是因为在创建该实例时其属性已经绑定在self中,此时会自动传递到类中的其他方法。

Part3如何使用类

(一)子类与继承

在实际定义一个类时我们并非一定要从完全空白开始,某些时候我们需要的是在一个类的基础上对其功能进行扩展或修改,从而得到一个更加符合要求的新的类。面向对象的一个重要特性就是具有继承性。通过继承,子类(新的类)可以得到父类(原有的类)的所有属性和方法,我们也可以在子类中添加新的属性和方法,或者修改父类的属性和方法,实现更具体的功能。

下面我们通过一个例子介绍如何创建子类。现在我们有一个名为“普惠金融库”的数据库,因为它拥有一些独有的性质,可以视作一种特殊的数据库,于是我们需要创建一个代表“普惠金融库”的类具体的做法是我们将之前创建的数据库 Database 作为父类,以此为基础创建一个普惠金融库 FinIncluDatabase 子类,子类 FinIncluDatabase 应该具有 Database 的所有属性和方法,同时还有其独特的属性:所属领域 field 和普惠对象子库 IncluObj,实现代码如下:

# 创建 Database 的子类 FinIncluDatabase
class FinIncluDatabase(Database):
    def __init__(self, name, URL, field):
        super().__init__(name, URL)
        self.field = field
        self.IncluObj = ['民营企业统计''涉农经营主体统计''个体经营户统计']
        
    def describe_inclu(self):
        print(self.name + '数据库涉及的领域是:' + self.field + ',\n' +
              '其拥有' + '、'.join(self.IncluObj) + '等子库。')

以上代码我们可以看到,创建子类的格式为class 子类名(父类名),由于子类可以继承了父类的所有属性和方法,因此通过子类创建实例时,Python 需要先给父类的所有属性赋值,这一任务在子类的__init__()方法中实现。

super().__init__(name, URL)中的super()是一个可以将父类和子类关联起来的特殊函数,这行代码的作用是让 Python 调用父类 Database 的__init__()方法,使得子类 FinIncluDatabase 的实例包含父类的所有属性(在此例中是 name 和 URL)。

除了父类的属性,子类 FinIncluDatabase 还具有独有的属性 field 与 IncluObj,这两个属性也在子类的__init__()方法中作了声明。稍有不同的是,属性 field 需要在创建子类对象时通过实参传入,而属性 IncluObj 不需要在创建对象时传入(可以在创建之后通过访问实例的属性来修改)。

子类 FinIncluDatabase 同时也继承了父类中的所有方法,除此之外,子类 FinIncluDatabase 中还定义了一个独有的describe_inclu()方法,该方法只有通过子类创建的实例才能调用。

下面我们通过子类 FinIncluDatabase 来创建一个实例 TFID,代码如下:

# 创建子类 FinIncluDatabase 的实例
TFID = FinIncluDatabase(name = '浙商大泰隆-企研中国普惠金融数据库',
                        URL = 'https://r.qiyandata.com/data_centre/TFID',
                        field = '普惠金融')

💡 浙商大泰隆-企研中国普惠金融数据库(简称“TFID”)是由企研数据携手浙江工商大学泰隆金融学院共同发起,针对普惠金融领域学术研究及智库建设而倾力打造的中国普惠金融数据库,旨在促进中国普惠金融研究的发展,服务新发展格局下国家在普惠金融领域的各项重大战略举措。>>>点此查看TFID更多介绍


可以看到,通过 FinIncluDatabase 创建实例时需要传入三个参数,分别对应父类的属性,以及子类特有的属性field。现在我们访问 TFID 的属性,可以看到其包含父类的所有属性和子类的特有属性,代码如下:

# 访问实例的属性
print(TFID.name)      # 浙商大泰隆-企研中国普惠金融数据库
print(TFID.URL)       # https://r.qiyandata.com/data_centre/TFID
print(TFID.field)     # 普惠金融
print(TFID.IncluObj)  # ['民营企业统计', '涉农经营主体统计', '个体经营户统计']

同时,通过子类创建的实例可以调用父类和子类中的所有方法,代码如下:

# 调用父类中的方法
TFID.describe_database()
'''
浙商大泰隆-企研中国普惠金融数据库数据库的访问地址是:https://r.qiyandata.com/data_centre/TFID。
'
''

# 调用子类中的方法
TFID.describe_inclu()
'''
浙商大泰隆-企研中国普惠金融数据库数据库涉及的领域是:普惠金融,
其拥有民营企业统计、涉农经营主体统计、个体经营户统计等子库。
'
''

(二)模块与类的导入

通常一个类中包含多个方法,实际上我们不可能在需要使用一个类时将这个类中的代码全部放在当前脚本中。为了便于管理代码,一般将类保存在模块中,然后在当前脚本中通过模块来导入所需的类。模块的文件扩展名为.py,一个.py文件就是一个模块,该文件的名称就是模块名。由于一个模块中可以保存多个类,当我们只需要导入其中的一个类时,使用from 模块名 import 类名;如果需要导入一个模块中的所有类,可以使用import 模块名

假设我们已经将前文创建的类 Database 和类 FinIncluDatabase 保存在文件“Database_Class.py”中,此时我们就可以通过这个模块(Database_Class.py)来导入类了。比如,现在我们需要将模块 Database_Class 中的 类 FinIncluDatabase 导入,并像上节一样创建实例 TFID,然后调用describe_inclu()方法。代码如下:

# 从模块中导入类
from Database_Class import FinIncluDatabase
# 创建实例 TFID
TFID = FinIncluDatabase(name = '浙商大泰隆-企研中国普惠金融数据库',
                        URL = 'https://r.qiyandata.com/data_centre/TFID',
                        field = '普惠金融')
# 调用 describe_inclu() 方法
TFID.describe_inclu()
'''
浙商大泰隆-企研中国普惠金融数据库数据库涉及的领域是:普惠金融,
其拥有民营企业统计、涉农经营主体统计、个体经营户统计等子库。
'
''

Part4实例

本章我们将通过一个更加完整的例子来展示类的作用。在这个例子中,我们首先在一个模块(名为“GAODE.py”)中定义了一个类 GaodeApi ,其中包括两个方法geocoding_by_address_city()regeocode_by_lonlat(),两者的作用分别是将文本地址转换为经纬度坐标(也称为“地理编码”)以及将经纬度坐标转回文本地址(也称为“逆地理编码”),具体的实现原理可以前往往期文章数据治理 | 根据地址获取经纬度及行政区划——API的妙用。该模块的内容如下:

# 文件名:GAODE.py

import warnings
import requests
warnings.filterwarnings('ignore')

class GaodeApi():
    def __init__(self, key = 'xxxxxxxxxxxxxxxx'):
        self.key = key

    def _get(self, url, params):
        """
        返回数据
        :param url: 不同的功能需要对应不同的url,见官方文档
        :param params: 传入参数
        :return: 返回json类型的查询结果
        "
""
        resp = requests.get(
            url, params=params
        )
        resp.raise_for_status()
        return resp.json()

    def geocoding_by_address_city(self, addr, city):
        """
        根据地址文本内容获取经纬度等信息
        "
""
        url = 'https://restapi.amap.com/v3/geocode/geo'
        params = {
            'key': self.key,
            'address': addr,
            'city': city,
            'batch': False,
        }
        Results = self._get(url, params)
        Result = Results['geocodes'][0]['location']
        return Result

    def regeocode_by_lonlat(self, lon, lat):
        """
        根据经纬度获取所在地文本描述等信息
        "
""
        url = 'https://restapi.amap.com/v3/geocode/regeo'
        params = {
            'key': self.key,
            'location'','.join([lon, lat]),
            'batch': True
        }
        Results = self._get(url, params)
        Result = Results['regeocode']['formatted_address']
        return Result

现在我们通过该模块导入类 GaodeApi ,并调用类中的两个方法来实现地理位置与经纬度坐标之间的相互转换,代码如下:

# 调用 GAODE.py 模块中的类 GaodeApi
from GAODE import GaodeApi

GaodeApi().geocoding_by_address_city('钱塘区2号大街100号''杭州市')
# '120.393592,30.311114'

GaodeApi().regeocode_by_lonlat('120.393592''30.311114')
# '浙江省杭州市钱塘区白杨街道2号大街100号浙江工商大学下沙校区'

Part5总结

在面向对象的编程思想中,类可以看作一种用于创建实例的模板,通过定义类,我们可以创建具有相似属性和行为的多个实例。类中的属性是实例的特征,而类中的方法就是实例的行为;此外,类还可以继承父类的属性和方法,从而实现代码的复用和扩展。学会创建类与实例,我们就可以更好地组织和管理代码,这也有助于提高代码的可读性和可维护性。

Part6Python 教学系列内容

 向下滑动查看往期同系列内容



加入数据seminar-Python交流学习群

与志同道合的朋友学习Python




星标⭐我们不迷路!想要文章及时到,文末“在看”少不了!

点击搜索你感兴趣的内容吧

往期推荐


数据可视化 | 没错!在 Python 中也能像 ggplot2 一样绘图

Python 实战 | ChatGPT + Python 实现全自动数据处理/可视化

Python实战 | 如何使用 Python 调用 API

Python 教学 | 列表推导式 & 字典推导式

Python 教学 | Pandas 时间数据处理方法





数据Seminar




这里是大数据、分析技术与学术研究的三叉路口


文 | 《社科领域大数据治理实务手册》


    欢迎扫描👇二维码添加关注    

点击下方“阅读全文”了解更多

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存