文章目录
- 参考
- 描述
- 面向对象编程
- 概念
- 类与实例
- 继承
- super() 与代理对象
- 方法的自动继承
- 属性的继承
- isinstance 与 type 内置函数
- isinstance()
- 可迭代对象仅能为元组
- 可能产生的 TypeError
- 嵌套的元组
- type
- isinstance() 与 type() 的区别
参考
项目 | 描述 |
---|---|
Python 官方文档 | https://docs.python.org/zh-cn/3/ |
搜索引擎 | Google 、Bing |
菜鸟教程 | Python isinstance() 函数 |
注:
本篇博客中的图片均来源于网络。
描述
项目 | 描述 |
---|---|
PyCharm | 2023.1 (Professional Edition) |
Python | 3.10.6 |
面向对象编程
概念
面向对象编程的含义是?如果从 字面含义
对其进行理解,那么你可能会认为
实际上
,面向对象编程(Object Oriented Programming,OOP)是一种 编程范式
,面向对象编程以对象作为程序的基本单元,将 数据
和 操作
封装在对象中,并通过对象之间的交互来实现程序的功能。
下面是面向对象编程的几个 核心概念
:
-
类(Class)
类是对象的蓝图或模板
,定义了对象的结构
和行为
。类就像是一种物品或者一个类别。例如,我们可以将汽车
定义为一个类,它们具有共同的属性
(如颜色、品牌、型号)和方法
(如启动、加速、刹车)。 -
对象(Object)
对象是类的实例,是类的具体实现
,对象具有类定义的属性和方法,并可以进行操作和交互。举个例子,一辆特定的汽车(比如一辆红色的宝马X5
)就是汽车类的一个对象,这个对象具有特定的属性值
(如红色、宝马、X5)和可以执行的方法
(如启动、加速、刹车)。
-
封装(Encapsulation)
封装
是将数据和对数据的操作封装在类中,使其成为对象的内部细节
,对外部隐藏。通过封装,对象的实现细节被保护起来,只提供公共的接口
供其他对象使用。类似于一辆汽车,我们只需知道如何使用车辆的控制器(方法)
来操作汽车,而不需要了解引擎、传动系统等内部细节。 -
继承(Inheritance)
继承
是一种机制,允许创建一个新类(子类)
从现有的类(父类)
继承属性和方法,子类可以重用
父类的代码,并可以扩展
或修改
父类的行为。例如,从汽车类派生出轿车类和卡车类,轿车和卡车将继承汽车类的通用属性和方法。
-
多态(Polymorphism)
多态
是指对象可以根据上下文的不同表现
出多种形态,多态允许使用统一的接口
来处理不同类型的对象,提高了代码的灵活性
和可重用性
。以动物为例,不同种类的动物(如狗、猫、鸟)可以共享一个发出声音
的方法,但每种动物的具体实现方式不同,产生了不同的声音。
- 抽象(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)
其中:
-
object
需要进行类型检查的对象,isinstance()
函数将判断object
是否是指定类型或指定类型的子类的实例。 -
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
上述代码定义了三个类:Grandpa
、Father
和 Son
,并建立了继承关系,即 Son
是 Father
的子类,而 Father
是 Grandpa
的子类。
接下来,使用 isinstance()
和 type()
函数进行类型检查,输出了一系列结果。
让我们逐个分析输出的结果和其原因:
-
print(isinstance(son, Grandpa))
输出True
,这是因为Son
是Grandpa
的子类的实例。因此,son
是Grandpa
的实例。 -
print(type(son) == Grandpa)
输出False
,这是因为type(son)
的结果是Son
,而不是Grandpa
。type()
函数返回的是对象的实际类型,不会考虑继承关系。 -
print(isinstance(son, Father))
输出True
,这是因为Son
是Father
的子类的实例。因此,son
是Father
的实例。 -
print(type(son) == Father)
输出False
,这是因为type(son)
的结果是Son
,而不是Father
。同样地,type()
函数返回的是对象的实际类型,不会考虑继承关系。 -
print(isinstance(son, Son))
输出True
,这是因为son
是Son
的实例。 -
print(type(son) == Son)
输出True
,这是因为type(son)
的结果是Son
。
根据以上的示例和结果,可以总结出 isinstance()
和 type()
函数的应用场景:
-
isinstance()
函数用于检查一个对象是否是指定类或其子类的实例。它会考虑继承关系,如果对象是指定类或其子类的实例,返回True
,否则返回False
。 -
type()
函数用于获取对象的实际类型,不考虑继承关系。它返回的是对象的实际类型,而不是对象所属的类或其父类。
在实际应用中,根据需求来选择使用 isinstance()
还是 type()
。如果需要考虑继承关系,判断一个对象是否是指定类或其子类的实例,可以使用 isinstance()
。如果只关心对象的实际类型,不考虑继承关系,可以使用 type()
。