您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > Python

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

时间:2020-03-05 14:36:07  来源:  作者:

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

作者 | Radek Fabisiak

译者 | 弯月,责编 | 郭芮

出品 | CSDN(ID:CSDNnews)

以下为译文:

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

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

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

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

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

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

创建Python类

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

>>> classMyClass:

... 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__如下:

>>> classMyClass:

... 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 ofMyClasscreated

arg_1: 2, arg_2: 4, arg_3: 8

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

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

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

数据属性

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

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

>>> classMyClass:

... 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的解包机制,用更紧凑的形式编写这段代码:

>>> classMyClass:

... 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)引用对象本身,但我们无需在调用方法时指定这个参数:

>>> classMyClass:

... def__init__( self, arg_1, arg_2, arg_3) :

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

...

... defset_z( self, value) :

... self.__z = value

...

... defget_z( self) :

... returnself.__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的功能:

>>> classMyClass:

... def__init__( self, arg_1, arg_2, arg_3) :

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

...

... @property

... defz( self) :

... returnself.__z

...

... @z.setter

... defz( 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添加三个方法:

>>> classMyClass:

... def__init__(self, arg_1, arg_2, arg_3):

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

...

... deff(self, arg):

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

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

... print( f'instance attributes:n {vars(self)}' )

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

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

...

... @classmethod

... defg(cls, arg):

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

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

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

...

... @staticmethod

... defh(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')

classmethodgcalled

cls:< class' __main__. MyClass'>

arg:my-argument

>>> MyClass.h( 'my-argument')

static method h called

arg:my-argument

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

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

>>> c.g( 'my-argument')

classmethodgcalled

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:

>>> classMyOtherClass(MyClass):

... def__init__(self, u, v, w, x, y, z):

... super.__init__(x, y, z)

... self.__u, self.__v, self.__w = u, v, w

...

... deff_(self, arg):

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

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

... print( f'instance attributes:n {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中还有很多类和面向对象的功能,例如:

  • 方法:.__repr__和.__str__
  • 方法:.__new__
  • 操作符
  • 方法:.__getattribute__、.__getattr__、.__setattr__和.__delattr__
  • 生成器
  • 可调用性
  • 创建序列
  • 描述器
  • 上下文管理
  • 抽象类和成员
  • 多重继承
  • 使用super
  • 拷贝
  • 序列化
  • slot
  • 类修饰器
  • 数据类

等等……

现如今面向对象是非常流行的编程方式。如果你立志做一名Python开发人员,那么就应该学习面向对象编程。但请不要忘记,Python还支持其他编程范式,例如过程式编程、函数式编程等,在某些情况下也许选用这些范例更为合适。

尽情享受编程的快乐!

原文:https://www.blog.duomly.com/object-oriented-programming-in-python/

本文为 CSDN 翻译,转载请注明来源出处。



Tags: Python 面向对象   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
现如今面向对象编程的使用非常广泛,本文我们就来探讨一下Python中的面向对象编程。作者 | Radek Fabisiak译者 | 弯月,责编 | 郭芮出品 | CSDN(ID:CSDNnews)以下为译文:Python支持...【详细内容】
2020-03-05  Tags: Python 面向对象  点击:(60)  评论:(0)  加入收藏
▌简易百科推荐
近几年 Web3 被炒得火热,但是大部分人可能还不清楚什么是 Web3,今天就让w3cschool编程狮小师妹带你了解下 Web3 是什么?与我们熟知的 Web1 和 Web2 又有什么区别呢?web3.0什么是...【详细内容】
2022-07-15  编程狮W3Cschool    Tags:Web3.0   点击:(2)  评论:(0)  加入收藏
1、让我们一起来看下吧,直接上图。 第一眼看到是不是觉得很高逼格,暗黑画风,这很大佬。其实它就是------AidLearning。一个运行在安卓平台的linux系统,而且还包含了许多非常强大...【详细内容】
2022-07-15  IT智能化专栏    Tags:AidLearning   点击:(2)  评论:(0)  加入收藏
真正的大师,永远都怀着一颗学徒的心! 一、项目简介 今天说的这个软件是一款基于Python+vue的自动化运维、完全开源的云管理平台。二、实现功能 基于RBAC权限系统 录像回放 ...【详细内容】
2022-07-14  菜鸟程序猿    Tags:Python   点击:(3)  评论:(0)  加入收藏
前言今天笔者想和大家来聊聊python接口自动化的MySQL数据连接,废话不多说咱们直接进入主题吧。 一、什么是 PyMySQL?PyMySQL是在Python3.x版本中用于连接MySQL服务器的一个库,P...【详细内容】
2022-07-11  测试架构师百里    Tags:python   点击:(18)  评论:(0)  加入收藏
aiohttp什么是 aiohttp?一个异步的 HTTP 客户端\服务端框架,基于 asyncio 的异步模块。可用于实现异步爬虫,更快于 requests 的同步爬虫。安装pip install aiohttpaiohttp 和 r...【详细内容】
2022-07-11  VT漫步    Tags:aiohttp   点击:(15)  评论:(0)  加入收藏
今天我们学习下 Queue 的进阶用法。生产者消费者模型在并发编程中,比如爬虫,有的线程负责爬取数据,有的线程负责对爬取到的数据做处理(清洗、分类和入库)。假如他们是直接交互的,...【详细内容】
2022-07-06  VT漫步    Tags:Python Queue   点击:(34)  评论:(0)  加入收藏
继承:是面向对象编程最重要的特性之一,例如,我们每个人都从祖辈和父母那里继承了一些体貌特征,但每个人却又不同于父母,有自己独有的一些特性。在面向对象中被继承的类是父类或基...【详细内容】
2022-07-06  至尊小狸子    Tags:python   点击:(25)  评论:(0)  加入收藏
点击上方头像关注我,每周上午 09:00准时推送,每月不定期赠送技术书籍。本文1553字,阅读约需4分钟 Hi,大家好,我是CoCo。在上一篇Python自动化测试系列文章:Python自动化测试之P...【详细内容】
2022-07-05  CoCo的软件测试小栈    Tags:Python   点击:(27)  评论:(0)  加入收藏
第一种方式:res = requests.get(url, params=data, headers = headers)第二种方式:res = requests.get(url, data=data, headers = headers)注意:1.url格式入参只支持第一种方...【详细内容】
2022-07-05  独钓寒江雪之IT    Tags:Python request   点击:(19)  评论:(0)  加入收藏
什么是python类的多态python的多态,可以为不同的类实例,或者说不同的数据处理方式,提供统一的接口。用比喻的方式理解python类的多态比如,同一个苹果(统一的接口)在孩子的眼里(类实...【详细内容】
2022-07-04  写小说的程序员    Tags:python类   点击:(28)  评论:(0)  加入收藏
站内最新
站内热门
站内头条