百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

你是如何理解Python中的面向对象编程的?

off999 2024-09-23 11:32 37 浏览 0 评论

现如今面向对象编程的使用非常广泛,本文我们就来探讨一下Python中的面向对象编程。

Python支持多种类型的编程范式,例如过程式编程、函数式编程、面向对象编程,而且还可以融合多种类型的范式。

现如今面向对象编程的使用非常广泛。面向对象编程的基本元素是对象,其包含的数据成员称为属性,函数(例程、过程)称为方法。

对象是类的实例。换句话说,类主要定义对象的结构,然后我们以类为模板创建对象。类不但包含方法定义,而且还包含所有实例共享的数据。

本文我们来探讨一下Python中的面向对象编程。我们将演示如何创建类,并使用类来实例化对象。本文的主要内容如下:

  • 创建Python类
  • 数据属性
  • 实例方法
  • 属性
  • 类和静态方法
  • 继承


本文无法涵盖这些主题的所有详细信息。Python中的面向对象编程还包含其他很多方面。希望本文能够为你学习Python及实现面向对象提供一个良好的开端。

创建Python类

我们可以使用关键字class定义Python类,关键字后面紧跟类的名称、分号和类的实现:

>>> class MyClass:
... pass
...

按照惯例,Python类的命名采用首字母大写(即PascalCase)。

现在让我们创建这个新类的一个实例,名为MyClass:

>>> a = MyClass()
>>> a
<__main__.MyClass object at 0x7f32ef3deb70>

语句a = MyClass()创建了MyClass的一个实例,并将它的引用赋值给变量a。

我们可以通过Python内置的函数type()或直接通过属性.__class__来获取类型(即对象的类)。在拿到类(类型)之后,我们就可以利用属性.__ name__获取类的名字:

>>> type(a)

<class '__main__.MyClass'>

>>> a.__class__

<class '__main__.MyClass'>

>>> a.__class__.__name__

'MyClass'

顺便提一句,Python类也是对象。它们是type的实例:

>>> type(MyClass)
<class 'type'>

下面,我们来定义一个方法。

Python中每个实例方法的第一个参数必须对应于该实例,即该对象本身。按照惯例,这个参数名为self。后面是其他参数(如果有需要的话)。在调用方法时,我们无需明确提供与参数self相对应的参数。

通常,我们需要定义的一个最重要的方法是.__init__()。在类的实例创建后就会调用这个方法。该方法负责初始化类成员。我们定义的.__init__()如下:

>>> class MyClass:
... def __init__(self, arg_1, arg_2, arg_3):
... print(f'an instance of {type(self).__name__} created')
... print(f'arg_1: {arg_1}, arg_2: {arg_2}, arg_3: {arg_3}')
...

下面,我们来创建一个MyClass实例,看看这个初始化方法的具体工作。我们的.__init__()方法需要三个参数(arg_1、arg_2和arg_3),记住我们不需要传递与self对应的第一个参数。所以,在实例化对象时,我们需要传递三个参数:

>>> a = MyClass(2, 4, 8)

an instance of MyClass created

arg_1: 2, arg_2: 4, arg_3: 8

上述声明产生的结果如下:

  • 创建一个MyClass类型的对象的实例。
  • 自动调用该实例的方法.__init__()。
  • 我们传递给MyClass()方法的参数:(2,4和8)会被传递给.__init__()。
  • .__init__()执行我们的请求,并输出结果。它利用type(self).__name__获取类的名称。


现在我们得到了一个类,它有一个方法.__init__(),以及这个类的一个实例。

数据属性

下面我们来修改MyClass,增加一些数据属性。

我们利用.__init__()初始化和定义了实例,我们还可以在这个方法或其他实例方法中,通过给某个数据属性赋值的方式改变属性值:

>>> class MyClass:

... def __init__(self, arg_1, arg_2, arg_3):

... self.x = arg_1

... self._y = arg_2

... self.__z = arg_3

...

现在MyClass有三个数据属性:

  • .x可以获取arg_1的值
  • ._y可以获取arg_2的值
  • .__ z可以获取arg_3的值


我们可以利用Python的解包机制,用更紧凑的形式编写这段代码:

>>> class MyClass:

... def __init__(self, arg_1, arg_2, arg_3):

... self.x, self._y, self.__z = arg_1, arg_2, arg_3

...

属性名称中的下划线(_)是为了表明这些属性是“私有”属性:

  • 开头没有下划线的属性(比如.x)通常可供对象外部的调用和修改。
  • 开头拥有一个下划线的属性(比如._y)通常也可以从对象外部调用和修改。然而,下划线是一种惯用的标志,即该类的创建者强烈建议不要使用该变量。应该仅通过类的功能成员(比如方法和属性)调用和修改该变量。
  • 开头拥有双下划线的属性(比如.__ z)将在名字修饰过程中被改名(在本例中它将被改名为._MyClass__z)。你也可以通过这个新名称从对象外部调用和修改它们。但是,我强烈反对这种做法。应该尽通过类的功能成员以其原始名称进行调用和修改。


Python对象的数据属性通常存储在名为.__ dict__的字典中,它也是对象的属性之一。但是,你也可以将数据属性存储在其他地方。我们可以直接访问__dict__,或利用Python的内置函数vars()获取.__ dict__:

>>> a = MyClass(2, 4, 8)
>>> vars(a)
{'x': 2, '_y': 4, '_MyClass__z': 8}
>>> a.__dict__
{'x': 2, '_y': 4, '_MyClass__z': 8}

名字修饰过程把键'__z'变成了'_MyClass__z'。

我们可以把.__ dict__当成普通的Python字典使用。

获取和修改与数据属性关联的值的常规方法如下:

>>> a.x
2
>>> a._y
4
>>> a.__z
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
AttributeError: 'MyClass' object has no attribute '__z'
>>> a.x = 16
>>> a.x
16
>>> vars(a)
{'x': 16, '_y': 4, '_MyClass__z': 8}

请注意,我们无法访问.__ z,因为.__ dict__没有键'__z'。

实例方法

下面,我们来创建两个实例方法:

●.set_z():修改.__ z。

●.get_z():返回.__ z的值。

请记住,每个实例方法的第一个参数(按照约定名为self)引用对象本身,但我们无需在调用方法时指定这个参数:

>>> class MyClass:

... def __init__(self, arg_1, arg_2, arg_3):

... self.x, self._y, self.__z = arg_1, arg_2, arg_3

...

... def set_z(self, value):

... self.__z = value

...

... def get_z(self):

... return self.__z

...

>>> b = MyClass(2, 4, 8)

方法.get_z()和.set_z()提供了传统的检索和修改.__ z值的方法:

>>> b.get_z()
8
>>> b.set_z(16)
>>> vars(b)
{'x': 2, '_y': 4, '_MyClass__z': 16}

你也可以在.get_z()和.set_z()中添加其他功能,例如检查数据的有效性。这种方法实现了面向对象编程中的一个主要概念:封装。

属性

还有一种方法(一种更Python的方式)访问和修改数据属性是使用属性。属性封装了一系列方法:getter、setter和deleter,但其行为与普通的数据属性相同。

下面的代码实现了属性.z,其中还包含.get_z()和.set_z()的功能:

>>> class MyClass:

... def __init__(self, arg_1, arg_2, arg_3):

... self.x, self._y, self.__z = arg_1, arg_2, arg_3

...

... @property

... def z(self):

... return self.__z

...

... @z.setter

... def z(self, value):

... self.__z = value

...

>>> b = MyClass(2, 4, 8)

如下,我们利用相应的属性.z来访问和修改数据属性.__ z:

>>> b.z
8
>>> b.z = 16
>>> vars(b)
{'x': 2, '_y': 4, '_MyClass__z': 16}

这段代码比上述示例更精简优雅。

类与静态方法

除了实例方法和属性之外,类还可以拥有类方法和静态方法。

下面让我们为MyClass添加三个方法:

>>> class MyClass:

... def __init__(self, arg_1, arg_2, arg_3):

... self.x, self._y, self.__z = arg_1, arg_2, arg_3

...

... def f(self, arg):

... print('instance method f called')

... print(f'instance: {self}')

... print(f'instance attributes:

{vars(self)}')

... print(f'class: {type(self)}')

... print(f'arg: {arg}')

...

... @classmethod

... def g(cls, arg):

... print('class method g called')

... print(f'cls: {cls}')

... print(f'arg: {arg}')

...

... @staticmethod

... def h(arg):

... print('static method h called')

... print(f'arg: {arg}')

...

>>> c = MyClass(2, 4, 8)

方法.f()是一个实例方法。实例方法的第一个参数是对象本身的引用。这些方法可以利用self访问对象,利用vars(self)或self.__dict__访问对象的数据属性,还可以利用type(self)或self.__class__访问对象对应的类,而且它们还可以拥有自己的参数。

方法.g()的开头包含修饰器@classmethod,表明这是一个类方法。每个类方法的第一个参数都会指向类本身,按照约定该参数名为cls。与实例方法的情况一样,我们不需要明确提供与cls对应的参数。而类方法可以利用cls和自己的参数访问类本身。

方法.h()的开头包含修饰器@staticmethod,表明这是一个静态方法。静态方法只能访问自己的参数。

Python中常见的调用实例方法的方法如下:

>>> c.f('my-argument')
instance method f called
instance: <__main__.MyClass object at 0x7f32ef3def98>
instance attributes:
{'x': 2, '_y': 4, '_MyClass__z': 8}
class: <class '__main__.MyClass'>
arg: my-argument

通常,我们应该直接通过类(而不是实例)调用类方法和静态方法:

>>> MyClass.g('my-argument')
class method g called
cls: <class '__main__.MyClass'>
arg: my-argument
>>> MyClass.h('my-argument')
static method h called
arg: my-argument

请记住,我们不需要传递类方法的第一个参数:与cls相对应的参数。

但是,我们可以像下面这样调用类方法和静态方法:

>>> c.g('my-argument')
class method g called
cls: <class '__main__.MyClass'>
arg: my-argument
>>> c.h('my-argument')
static method h called
arg: my-argument

当我们调用c.g或c.h,但实例成员没有这样的名称时,Python会搜索类和静态成员。

继承

继承是面向对象编程的另一个重要特性。在这个概念中,类(称为子类或派生类)会继承其他类(称为超类或基类)的数据和函数成员。

在Python中,所有类都会默认继承Python自带的类对象。但是,我们可以根据需要定义合适的类继承层次结构。

例如,我们可以创建一个名为MyOtherClass的新类,该类继承了MyClass:

>>> class MyOtherClass(MyClass):
... def __init__(self, u, v, w, x, y, z):
... super().__init__(x, y, z)
... self.__u, self.__v, self.__w = u, v, w
... 
... def f_(self, arg):
... print('instance method f_ called')
... print(f'instance: {self}')
... print(f'instance attributes:
{vars(self)}')
... print(f'class: {type(self)}')
... print(f'arg: {arg}')
...
>>> d = MyOtherClass(1, 2, 4, 8, 16, 32)

如上,MyOtherClass拥有MyClass的成员:.x、._y、.__z以及.f()。你可以通过语句super().__init__(x, y, z)初始化基类的数据成员x、._y和.__z,该语句会调用基类的.__init__()方法。

除此之外,MyOtherClass还有自己的成员:.__u、.__v、.__w和.f_()。

下面,我们通过vars()获取数据成员:

>>> vars(d)
{'x': 8,
 '_y': 16,
 '_MyClass__z': 32,
 '_MyOtherClass__u': 1,
 '_MyOtherClass__v': 2,
 '_MyOtherClass__w': 4}

我们可以调用基类和派生类中的所有方法:

>>> d.f('some-argument')
instance method f called
instance: <__main__.MyOtherClass object at 0x7f32ef3e7048>
instance attributes:
{'x': 8,
 '_y': 16,
 '_MyClass__z': 32,
 '_MyOtherClass__u': 1,
 '_MyOtherClass__v': 2,
 '_MyOtherClass__w': 4}
class: <class '__main__.MyOtherClass'>
arg: some-argument
>>> d.f_('some-argument')
instance method f_ called
instance: <__main__.MyOtherClass object at 0x7f32ef3e7048>
instance attributes:
{'x': 8,
 '_y': 16,
 '_MyClass__z': 32,
 '_MyOtherClass__u': 1,
 '_MyOtherClass__v': 2,
 '_MyOtherClass__w': 4}
class: <class '__main__.MyOtherClass'>
arg: some-argument

但是,如果派生类包含的某个成员与基类同名,则优先使用派生类的成员。

总结

面向对象编程是Python支持的编程范式之一。面向对象蕴含的抽象以及表征的现实世界行为在某些时候会非常有帮助性。然而,有时也可能会违反直觉,并为开发过程带来不必要的麻烦。

在本文中,我们介绍了如何利用Python编写基本的面向对象程序。Python中还有很多类和面向对象的功能,知道的伙伴可以评论区留言一波!

相关推荐

windows7安装windows10(windows7安装光盘下载)

在安装Win7时,出现提示“Windows无法安装到这个磁盘。这台计算机的硬件可能不支持启动到此磁盘。请确保在计算机的bios菜单中启用了磁盘的控制器。” 解决方法: 1.如果之前你做过BIOS设置,...

装机配置模拟器(装机配置模拟器教程)
装机配置模拟器(装机配置模拟器教程)

装机模拟器2好装机模拟器2装系统方法1.在游戏PC装机模拟器里,有时候我们修理好电脑之后,发现电脑没有安装操作系统,这时候应该先安装系统。2.第一步,点击PC装机模拟器游戏,登录游戏。3.第二步,进入游戏之后,找到需要没有安装操作系统的电脑...

2025-11-10 21:51 off999

电脑网络正常但是上不了网(网络正常但电脑无法上网)

分析如下1、首先检查网卡的问题,打开电脑后,打开电脑右下角的WiFi连接,然后从里面的网络和共享中心检查,打开网络和共享中心后,出现对话框,在对话框左侧上方找到更改适配器设置,单击左键打开,就可以发现...

vs2008安装包下载(vs2008下载官方下载)

vs2008是面向WindowsVista、Office2007、Web2.0的下一代开发工具,VS2008引入了250多个新特性,整合了对象、关系型数据、XML的访问方式,语言更加简洁。使用V...

怎么换系统win7(怎么换系统盘固态硬盘)
  • 怎么换系统win7(怎么换系统盘固态硬盘)
  • 怎么换系统win7(怎么换系统盘固态硬盘)
  • 怎么换系统win7(怎么换系统盘固态硬盘)
  • 怎么换系统win7(怎么换系统盘固态硬盘)
cad2018序列号(cad2018序列码)

AutoCAD2018序列号和密钥:序列号:356-72378422,666-69696969,667-98989898,400-45454545,066-66666666等密钥:001J1CA...

恢复出厂设置win7(恢复出厂设置win11)
  • 恢复出厂设置win7(恢复出厂设置win11)
  • 恢复出厂设置win7(恢复出厂设置win11)
  • 恢复出厂设置win7(恢复出厂设置win11)
  • 恢复出厂设置win7(恢复出厂设置win11)
ip检测网站(ip地址测试)

IP检测工具(IPNetChecker)V1.5.2是一个简易实用,功能强大的网络监控软件,使您可以检查互联网和局域网上的IP主机的网络状态。IP检测工具(IPNetChecker)V1.5....

云电脑app哪个好(手机云电脑app哪个最好)

答:以下是一些比较好的云电脑应用程序推荐:1.AnyDesk-支持Windows、MacOS、Linux、Android和iOS,可用于远程访问和控制PC或移动设备。2.Splashtop...

怎样注册邮箱163免费(怎样注册邮箱163免费账号)

一、工具:电脑(联网)、浏览器二、操作步骤:【1】打开浏览器,找到“163邮箱”,点击。【2】点击右边的“注册”。【3】网站默认注册手机号码邮箱,填写信息,点击“注册”。若不想泄漏手机号码或不想使用手...

微软surface pro 6(微软surface pro 6可以扩容吗)

SurfacePro6的接口包含:1个标准尺寸USB3.0端口,3.5mm耳机插孔,MiniDisplayPort,1个SurfaceConnect端口,Surface专业键盘盖端口,microSDX...

电源已接通未充电怎么回事(电源已接通未充电 真正解决办法)

原因分析:出现这样的原因有可能是长时间没有充电,导致电池的内部电量耗完后亏电严重,只是电脑充电的保护,不让过充而已,只要设置一下电池选项一般就可以解决问题了。解决方法:1、关机,拔下电源,拔出电池,...

华为云会议app下载(华为云会议下载)

 华为云会议可以在PC客户端或者手机客户端上一键发起立即会议,1秒创会。然后在会中选择企业通讯录中的人加入,系统会自动呼叫这些与会人,接听后即加入会议。ZOOM是一个云会议服务平台,为客户提...

路由器重置方法(路由器重置方法详细步骤)

路由器靠近WAN口边上的有一个小孔用于路由器的重置,路由器配置完成后,我们可能会忘记他的用户名或者是密码,那么我们可以把它恢复到出厂设置,再靠近万口或电源之间,有一个小孔,用一个尖锐的金属查一下大约五...

100个有效qq号以及密码(有效qq号和密码大全)

如果你的电脑知识好的话,不妨用一些复合密码!SHIFT+一些特殊符号,字母,数字!虽然麻烦了点,但总比被人盗号了的好,是吧!最好还用手机绑定一下,这样的话方便改密码也不怕QQ被盗了哦。。。QQ密码找回...

取消回复欢迎 发表评论: