Python 类型检测:isinstance() 与 type()

本文介绍了面向对象编程的核心概念,包括类、实例、继承、封装、多态和抽象。接着详细讲解了类与实例的创建,以及继承的概念,展示了super()函数和方法的自动继承。此外,还探讨了isinstance()和type()这两个内置函数的用途和区别,以及在处理可迭代对象时的注意事项。
摘要由CSDN通过智能技术生成

参考

项目描述
Python 官方文档https://docs.python.org/zh-cn/3/
搜索引擎GoogleBing
菜鸟教程Python isinstance() 函数

注:

本篇博客中的图片均来源于网络。

描述

项目描述
PyCharm2023.1 (Professional Edition)
Python3.10.6

面向对象编程

概念

面向对象编程的含义是?如果从 字面含义 对其进行理解,那么你可能会认为

实际上,面向对象编程(Object Oriented Programming,OOP)是一种 编程范式,面向对象编程以对象作为程序的基本单元,将 数据操作 封装在对象中,并通过对象之间的交互来实现程序的功能。

下面是面向对象编程的几个 核心概念

  1. 类(Class)
    类是对象的 蓝图或模板,定义了对象的 结构行为。类就像是一种物品或者一个类别。例如,我们可以将 汽车 定义为一个类,它们具有 共同的属性(如颜色、品牌、型号)和 方法(如启动、加速、刹车)。

  2. 对象(Object)
    对象是类的实例,是类的 具体实现,对象具有类定义的属性和方法,并可以进行操作和交互。举个例子,一辆特定的汽车(比如一辆红色的 宝马X5)就是汽车类的一个对象,这个对象具有 特定的属性值(如红色、宝马、X5)和 可以执行的方法(如启动、加速、刹车)。

  1. 封装(Encapsulation)
    封装 是将数据和对数据的操作封装在类中,使其成为 对象的内部细节,对外部隐藏。通过封装,对象的实现细节被保护起来,只提供公共的接口 供其他对象使用。类似于一辆汽车,我们只需知道如何使用 车辆的控制器(方法) 来操作汽车,而不需要了解引擎、传动系统等内部细节。

  2. 继承(Inheritance)
    继承 是一种机制,允许创建一个 新类(子类)现有的类(父类) 继承属性和方法,子类可以 重用 父类的代码,并可以 扩展修改 父类的行为。例如,从汽车类派生出轿车类和卡车类,轿车和卡车将继承汽车类的通用属性和方法。

  3. 多态(Polymorphism)
    多态 是指对象可以 根据上下文的不同表现 出多种形态,多态允许使用 统一的接口 来处理不同类型的对象,提高了代码的 灵活性可重用性。以动物为例,不同种类的动物(如狗、猫、鸟)可以共享一个 发出声音 的方法,但每种动物的具体实现方式不同,产生了不同的声音。

  1. 抽象(Abstraction)
    抽象 是指从 具体的事物抽取出共同的特征和行为,形成类的抽象描述。抽象的目的是 忽略不必要的细节,关注对象的关键属性和行为,以便于更好地理解和处理问题。抽象可以让我们将问题领域的复杂性 抽象化为简单的模型,从而更好地组织和管理代码。

这些概念共同构成了面向对象编程的基础,使得程序设计更加 模块化可维护可扩展。面向对象编程提供了一种 思考组织代码 的方法,使得代码更具 可读性可理解性,并支持面向对象分析、设计和开发的整个软件开发生命周期。

类与实例

Python 中,我们可以使用 class 关键字来定义一个类,class 关键字后面紧跟类的名称和一个冒号。类的定义包含在一个代码块中,其中可以定义属性、方法和其他相关内容。
一旦我们定义了一个类,我们就可以通过 实例化操作 来创建该类的对象。在 Python 中,通过类名后面跟随括号的方式调用类的 构造函数,可以将一个类实例化为一个对象。

举个栗子

class MyClass:
	# 定义 MyClass 类的构造函数,该函数
	# 将在该类被实例化为对象时自动执行。
    def __init__(self):
    	# 定义一个属性
        self.name = 'RedHeart'
    
    # 定义一个方法
    def get_name(self):
        return self.name
    

# 将 MyClass() 类实例化为一个对象
myClass = MyClass()

# 将 myClass 对象的字符串表示输出至控制台中
print(myClass)

# 将 myClass 对象的 name 属性的值输出至控制台中
print(myClass.name)

# 通过调用 myClass 对象的 get_name() 方法
# 获取该对象的 name 属性的值
print(myClass.get_name())

执行效果

<__main__.MyClass object at 0x000001D721E46D10>
RedHeart
RedHeart

继承

在 Python 中,我们可以通过 继承(Inheritance) 来创建一个类从另一个类派生的子类。子类继承了父类的属性和方法,并且可以添加自己特定的属性和方法。

类继承的基本语法是,在定义一个类时,在类名后面使用括号指定要继承的父类

super() 与代理对象

在 Python 中 super() 是一个 内置的类对象,在类的内部实例化该类将得到一个特殊的 代理对象,该对象 绑定了父类的方法super() 提供了一种方便的方式来 访问 父类的方法,允许你调用父类的方法,而不需要 显式地 引用父类的名称。对此,请参考如下示例:

class Parent:
    def __init__(self):
        self.name = 'Parent'

    def get_self_name(self):
        return self.name


class Children(Parent):
    def get_parent_name(self):
        # 通过调用 super() 返回的代理对象的
        # get_self_name() 方法获取父类对象的 name 属性值
        return super().get_self_name()


children = Children()
print(children.get_parent_name())

执行效果

Parent
方法的自动继承

一旦类与类之间确立了 继承关系,子类将 自动继承 父类中的 所有方法,包括实例方法、类方法和静态方法。这样,子类便可以 重用 父类的功能,并可以在子类中 添加新方法扩展 子类的行为。

class Parent:
    def __init__(self):
        self.name = 'Parent'

    def get_self_name(self):
        return self.name


class Children(Parent):
    def get_parent_name(self):
        # 通过调用从父类继承得到的 get_self_name
        # 方法获取父类的 name 属性值
        return self.get_self_name()


children = Children()
print(children.get_parent_name())

执行效果

Parent

注:

子类可以通过 重写 父类的方法来 改变方法的行为。当子类定义了与父类 同名 的方法时,子类的方法会 覆盖 父类的方法。这样,子类可以根据自己的需求来重新定义方法的功能。对此,请参考如下示例:

class Parent:
    def __init__(self):
        self.name = 'Parent'

    def get_self_name(self):
        return self.name


class Children(Parent):
    # 定义与父类同名的方法,子类的方法将覆盖父类的
    # 同名方法。
    def get_self_name(self):
        return 'Hello World'


children = Children()
print(children.get_self_name())

执行效果

Hello World
属性的继承

即使确定了类与类之间的继承关系,子类也 不会自动继承 父类的属性(除 静态属性 外),并且使用 super() 返回的代理对象也仅能够访问父类中的 方法。那么,子类该如何继承父类中的属性呢?
可以通过调用含有 实例属性定义 的方法来继承父类中的属性。对此,请参考如下示例:

class Parent:
    def set_parent_attrs(self):
        # 在 Children 的父类中的 set_parent_attrs
        # 函数中定义属性 name 
        self.name = 'Parent'


class Children(Parent):
    pass


children = Children()

# 尝试访问定义于父类中的实例属性 name。
try:
    print(children.name)
except AttributeError:
    # 由于自 set_parent_attrs() 函数还未被调用
    # name 实例属性还未被定义。
    print("'Children' object has no attribute 'name'")

# 调用由父类中继承的 set_parent_attrs() 以
# 继承父类的属性 name。
children.set_parent_attrs()
print(children.name)

执行效果

'Children' object has no attribute 'name'
Parent

在 Python 中,常用于定义实例属性的方法为类对象的构造函数 __init__()。由于子类中也常需要使用到 __init__() 来定义该类的实例属性,而这将导致从父类继承的来的 __init__() 方法被覆盖。因此,常在子类的 __init__() 方法中通过 super() 返回的代理对象调用父类的 __init__() 方法来继承定义于父类 __init__() 方法中的实例属性。对此,请参考如下示例:

class Parent:
    def __init__(self):
        self.name = 'Parent'


class Children(Parent):
    def __init__(self):
        super().__init__()
        self.local_name = 'Children'


children = Children()

print(children.name)
print(children.local_name)

执行效果

Parent
Children

注:

如果子类不需要 特别定制扩展 父类的 初始化过程,可以不定义属于子类的 __init__() 构造函数,让子类自动继承父类的 __init__() 方法。对此,请参考如下示例:

class Parent:
    def __init__(self):
        self.name = 'Parent'


class Children(Parent):
    pass


children = Children()

print(children.name)

执行效果

Parent

isinstance 与 type 内置函数

isinstance()

isinstance() 函数是 Python 中的 内置函数,该函数用于检查一个对象是否是 指定类其子类实例。如果对象是给定类型的实例,则返回 True;如果不是,则始终返回 False

isinstance(object, classinfo)

其中:

  1. object
    需要进行类型检查的对象,isinstance() 函数将判断 object 是否是指定类型或指定类型的子类的实例。

  2. classinfo
    classinfo 的值允许为一个类型对象、多个类型对象组成的 元组Union 类型。

# 判断数值 1 是否是 int 类型或该类型的子类类型的实例
result = isinstance(1, int)
print(result)

# 判断数值 1 是否是 str 类型或该类型的子类类型的实例
result = isinstance(1, str)
print(result)

# 判断数值 1 是否是 str 或 int 类型或其子类类型的实例
result = isinstance(1, (str, int))
print(result)

# 判断数值 1 是否是 str、int、bool 类型或其子类类型的实例
result = isinstance(1, str | int | bool)
print(result)

# 判断数值 1 是否是 str、int、bool、list、tuple
# 类型或其子类型的实例
result = isinstance(1, (str | int, bool | list, tuple | tuple, tuple))
print(result)

执行效果

True
False
True
True
True
可迭代对象仅能为元组

isinstance() 函数的参数 classinfo 的值可以为包含一个或多个类型对象的元组,但这不意味着可以使用与元组同为 可迭代对象列表 等数据类型。否则,Python 将抛出 TypeError 异常错误。

result = isinstance(1, [int, str])
print(result)
可能产生的 TypeError

isinstance 函数的 classinfo 参数不符合预期时,isinstance() 函数将抛出 TypeError 异常,但也存在例外。对此,请参考如下示例:

result = isinstance(1, (int, 1))
print(result)

执行效果

True

倘若将 isinstance() 函数的第二个参数 (int, 1) 中的内容的顺序修改为 (1, int),则 Python 将为此抛出 TypeError 异常错误。
这是因为在通过 isinstance() 函数在进行类型检查时,isinstance() 函数会按照元组中的顺序逐个检查类型,一旦找到与 object 相匹配的类型对象,就返回 True。而如果在检查过程中遇到无效的类型,则将引发 TypeError 异常。

嵌套的元组

参数 classinfo 的值允许为多个类型对象组成的 元组,并且该元组中还能够嵌套元组。对此,请参考如下示例:

result = isinstance(1, (list, (str, (bool, (tuple | int)))))
print(result)

result = isinstance(1, (list, (str, (bool, (tuple | set)))))
print(result)

执行效果

True
False

type

在 Python 中,你可以向 type() 传入一个参数,该函数将返回该 参数所属的类对象type() 函数可以帮助我们在 程序运行时确定对象的类型,从而采取相应的操作或逻辑。通过使用 type() 函数,我们可以 了解一个对象所属的具体类型,这对于调试、验证输入数据或处理不同类型的对象时非常有用。

type() 函数返回一个 类对象,表示对象所属的类或数据类型。类型信息,即类对象的字符串表示为 <class '类型'>,例如 <class 'int'> 表示整数类型。

举个栗子

# 自定义一个类,该类的名称为 MyClass
class MyClass:
    pass


# 实例化 MyClass() 得到 myClass 对象
myClass = MyClass()

# 将 MyClas 类对象的字符串形式输出至控制台中
print(myClass)

# 将 myClass 所属的类对象的字符串形式输出至控制台中
print(type(myClass))

# 将数值 1 所属的类对象的字符串形式输出至控制台中
print(type(1))

# type() 函数返回的值为一个类对象而非字符串
print(type(1) == "<class 'int'>")

执行效果

<__main__.MyClass object at 0x00000212CBAB5690>
<class '__main__.MyClass'>
<class 'int'>
False

isinstance() 与 type() 的区别

type()isinstance() 函数一样,同样可以用于判断对象是否是由某一类对象实例化产生的。但也存在不同,type() 函数不考虑类的继承关系,而 isinstance() 函数会对此进行考虑。

class Grandpa:
    pass


class Father(Grandpa):
    pass


class Son(Father):
    pass


grandpa = Grandpa()
father = Father()
son = Son()

print(isinstance(son, Grandpa))
print(type(son) == Grandpa)

print(isinstance(son, Father))
print(type(son) == Father)

print(isinstance(son, Son))
print(type(son) == Son)

执行效果

True
False
True
False
True
True

上述代码定义了三个类:GrandpaFatherSon,并建立了继承关系,即 SonFather 的子类,而 FatherGrandpa 的子类。

接下来,使用 isinstance()type() 函数进行类型检查,输出了一系列结果。

让我们逐个分析输出的结果和其原因:

  1. print(isinstance(son, Grandpa)) 输出 True,这是因为 SonGrandpa 的子类的实例。因此,sonGrandpa 的实例。

  2. print(type(son) == Grandpa) 输出 False,这是因为 type(son) 的结果是 Son,而不是 Grandpatype() 函数返回的是对象的实际类型,不会考虑继承关系。

  3. print(isinstance(son, Father)) 输出 True,这是因为 SonFather 的子类的实例。因此,sonFather 的实例。

  4. print(type(son) == Father) 输出 False,这是因为 type(son) 的结果是 Son,而不是 Father。同样地,type() 函数返回的是对象的实际类型,不会考虑继承关系。

  5. print(isinstance(son, Son)) 输出 True,这是因为 sonSon 的实例。

  6. print(type(son) == Son) 输出 True,这是因为 type(son) 的结果是 Son

根据以上的示例和结果,可以总结出 isinstance()type() 函数的应用场景:

  • isinstance() 函数用于检查一个对象是否是指定类或其子类的实例。它会考虑继承关系,如果对象是指定类或其子类的实例,返回 True,否则返回 False

  • type() 函数用于获取对象的实际类型,不考虑继承关系。它返回的是对象的实际类型,而不是对象所属的类或其父类。

在实际应用中,根据需求来选择使用 isinstance() 还是 type()。如果需要考虑继承关系,判断一个对象是否是指定类或其子类的实例,可以使用 isinstance()。如果只关心对象的实际类型,不考虑继承关系,可以使用 type()

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BinaryMoon

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值