Python的学习心得和知识总结(六)|Python 面向对象编程(一)

前面我们已经做了大量的基础的学习 和 准备工作,从今天开始正式进入Python的面向对象编程。对于Python而言,它是支持前面的面向过程、OOP和函数式编程等大量编程范式。

至于OOP这个东西也比较简单,我们在C++的时候已经说过了。OK 开始今天的学习!


面向对象与前面的面向过程,是两种完全不同的编程思想。面向对象其主要是针对大型软件的设计开发的,其优点和特性如下:

1、程序的更强的扩展性 可读性
2、代码与数据的组织方式更加接近人的思维,即:把数据和方法封装在对象中
3、Python同样也支持OOP的基本概念:封装、继承和多态
4、Python里面 一切皆对象

面向过程和面向对象的区别

所谓面向过程(如C语言),其更加关注:任务怎么按照步骤 流程来完成(一步一步来解决问题) 或者说 是一种解决方式的逻辑流程。 但是当我们遇到一些逻辑上就非常复杂的问题时,基于步骤的解决方案 可能就不太适合了。(在我看来,面向过程更加适合于完成底层的基础设施搭建。一个worker角色)

而面向对象则聚焦于 问题之中 or 软件里面对象之间的关系,这是站在作为设计者的上帝视角。这点更加符合我们人的思维方式。(面向对象则适合于顶层的宏观思想设计。一个designer视角)对于复杂问题的考量,首先需要抽取出尽可能多的对象进而抽象成 类;然后确定对象的属性和行为(类的数据和方法);最后组装成类,并完成类间关系的确立。

虽然是二者之间的差别巨大,但是在我看来 这是密不可分的有机体。(相互配合,可能效果更佳 色香味俱全)

小结一下:

  1. 二者都是解决问题的一种方案(代码的组织方式)
  2. 面向过程不需要OOP也可以解决问题(适合于小型问题,但并不意味着人家干不了大事)
  3. 在一个复杂问题上:顶层面向对象设计,底层面向过程实现
  4. 两种思维方式的碰撞,没有优劣之分。相互配合,效果更佳

注:Python里面的对象,通俗来说:就是不同类型数据和操作数据的方法的有机体。其一切皆对象,就是除了其值以外,还包含了一些其数据的操作方法的对象。( 类是抽象的,对象是真实的。类是对象的模板,通过类的定义来创建一个个实例对象;进而使用类里面定义的方法进行实际的行为

OK,下面我们就进入OOP的世界!

详解类的定义和对象的创建

因为程序代码都是由 一个个被抽象出来的类来组织的,它是创建出来对象的模具。前面也说了 类的数据和方法就对应上了对象的属性和行为。对象是运行时期被创建出来的 根据Python的一切皆对象,此时的类 也是对象。(不过它是产生对象的对象)

和我们的C++一样的是,同一个类可以创建出来不同的对象。这些对象共享同一套这个类的方法,但他们拥有自己私有的数值。
在这里插入图片描述
和C++里面(this指针)一样的是 这里显式展示的第一个参数 self,就是指向刚刚创建好的新对象

上面的这个就太简单了,因此善意小提示:在下建议 等你学会了C/C++之后,再来学Python 真的是好简单!

对象的构造函数

上面也看到了一句 obj1=_MyClass1("songbaobao","家里蹲大学",425) 通过类名(参数列表)就可以创建出来一个对象。

它实际上是首先调用了__new__() 方法来创建一个对象(这个方法我们不用进行重写);然后调用了那个自己重写的叫做__init__ 的构造函数,来初始化一个创建好的空对象(初始化对象的属性,赋初值 无需返回值)。

此时的Python对象三部分就包含了:id、type和value(属性attribute与方法method的集合)。

OK,下面就来详细看一下这个__init__ 构造函数。其注意事项有下面这些:

1、函数名就叫做__init__
2、函数(类里面的方法)参数列表的第一个参数就是self,以指向刚刚创建好的新对象
3、__init__ 构造函数 只是负责一个赋初值的init作用
4、使用类名(参数列表)就可以创建出来一个对象(创建并初始化)。之后将创建好的对象引用给相应的变量

对象的实例属性

对象的属性对应于类的数据,其是属于实例对象的变量 因此也被称为:实例变量。对象的实例属性有如下的注意事项:

1、实例属性一般是在__init__ 构造函数里面 进行赋初值
2、在类中的实例方法里面,使用self.variable进行访问
3、创建实例对象之后,使用object1.variable进行访问

注:当我们在外面使用object1.variable并且赋值的情况下,若是variable之前不存在 那么这个相当于给object1对象增加新的实例变量。(这个跟类 或者说 模板没有任何关系)若是接下来又object2=class(v1,v2……)重新创建的新对象object2 它是没有object1的新增实例变量的。

对象的实例方法

和上面一样,实例方法是从属于实例对象的。其定义格式如下:

def functionname(self [ , 形参列表]):
【一个tab】函数体

对象的实例方法调用有如下的注意事项:

1、实例方法一般是使用object1.functionname(实参列表)来进行访问
2、在实例方法被定义的时候:第一个参数是self,用来指向当前的实例对象
3、但是在方法调用的时候 不需要也不能给self传值。因为人家解释器会自动指向,如下:
在这里插入图片描述
如上,解释器做的事情:因为实例方法从属于实例对象,所以左边使用对象去调用方法的时候。也就解释成了:对象引用a(就是self)作为实参传入,来区别是哪个对象在调用方法。 注:这些方法是诸多对象公有共享的。

这里的实例方法和普通的函数的异同点如下:

  1. 他们本质一样,都是用来完成一个功能的代码块
  2. 实例方法的调用是对象完成。方法从属于一个指定的实例对象;而函数则无
  3. 方法在定义的时候 需要传递self;函数不需要

下面来看一下实例方法的一些操作:
在这里插入图片描述
上面我们说的都是:通过类来创建的实例对象。下面我们来看一下类(类对象)

类也是一个对象

当解释器执行class语句的时候,就会去创建一个类对象。
在这里插入图片描述
上面的type其实是一个 模具类,而我们这里的_MyClass类就相当于从模具类而来的子类。解释器执行class之后,生成了一个变量名为 类名_MyClass类型type 的类对象,且可以通过简单的赋值进行对象的引用转移。之后就可以通过新的引用变量MyClass实现后续的相关对象生成的方法调用操作。

注:pass相当于一个占位符,没有什么实际意义。

类属性和类方法

类属性是从属于“类对象”的属性,也被称之为 类变量。因为类属性从属于类对象,所以它可以被所有的实例对象共享。
在这里插入图片描述
解释上面的代码:当解释器执行class之后,生成了一个类名_MyClass、类型type 的类对象,且可以通过简单的赋值进行对象的引用转移。然后类属性的定义之后,是会被放在上面类对象的堆内存中。而类方法(这些代码对象)则都是存在于类对象的堆内存当中,obj1等对象的实例方法都只是该类方法的引用。(以达到共享一套方法的目的)

而当需要创建一个obj1对象的时候,其实例属性(如name)是存在于obj1对象的堆内存中;实例方法都只是该类方法的引用。在实际的实例方法被调用的时候,还是最终指向到类方法上。

同类属性一样,类方法也是从属于类对象。类方法是借助于装饰器@classmethod 来定义的,其语法格式如下:

@classmethod
def class_function(cls [ , 参数列表]):
【一个tab键】 函数体

有下面几点注意事项:

  1. 装饰器必须位于类方法的上面一行
  2. 第一个参数cls必须有,且指向的就是类对象自身
  3. 调用类方法格式:使用类名.类方法名(参数列表)。而且不可以为参数cls传值
  4. 在类方法中访问实例属性or实例方法会出错
  5. 当子类继承父类方法的时候,此时传入的cls的类对象就是子类对象

在这里插入图片描述
类属性和类方法在新产生的obj对象里面,是没有的。他们是属于类对象(类)的东西。(一般来说,实例方法操作实例属性;类方法操作类属性,类方法中访问实例属性or实例方法会出错。)

Python静态方法

在Python里面,允许在类里面去定义与 类对象无关的方法,称之为静态方法(也不操作类属性,当然也是可以的)。静态方法的定义是需要借助于装饰器@staticmethod来完成,它在模块中定义的其他普通函数没有太大区别。不同的是:静态方法是放在了类的名字空间里面,需要通过类名调用访问。 其语法格式如下:

@staticmethod
def staticfunction(参数列表):
【一个tab键】 函数体

其注意事项有:

1、@staticmethod放在该方法的上面一行
2、当调用该静态方法的时候:classname.staticfunction(参数列表)
3、静态方法中访问实例属性or实例方法会出错

在这里插入图片描述
注:类方法和静态方法是从属于类的,类产生的obj对象他们是没有的。因此在类方法、静态方法里面去访问obj的属性和方法是会出错的(调用不了self)。(模具有了,但不一定有样品。所以在模具里面调用样品的东西 它可能还没有呢?)

对象的析构函数

__del__() 方法来析构一个对象,即:销毁对象的操作。(包含释放对象占用的资源等 并不仅仅指的是内存资源 还有文件、网络连接等)

与C++不一样的是,Python提供了一个自动处理的垃圾回收机制(类似于C++的智能指针):当对象的引用计数为0 的时候,垃圾回收机制开始工作 调用__del__() 方法。

当然我们也可以直接通过del语句来删除对象(从而保证调用__del__() 方法),该方法是系统自动提供,一般情况下我们不需要进行重写。
在这里插入图片描述
不同的IDE,显示的结果有所不同 下面看一下VS2019的:
在这里插入图片描述
注:这个不重要,大家掌握引用计数 和 垃圾回收机制就可以了。

可调用对象是啥

在Python里面,一般来说 定义了__call__() 方法的对象,就被称为:可调用对象。也就是说,这个对象可以像函数一样被调用。 (此时看似在调用object() 实际在调用前面的__call__() 方法,这个过程由解释器来处理执行)

在这里插入图片描述

方法是没有重载

首先说明:Python木有方法重载,因此不要使用重名的方法。

我们在学C++的时候,重载的区分在于:即使函数的函数名相同,但参数列表(个数与类型)的不同。 但是在Python里面,一来函数的参数没有具体的指定类型,二来参数的个数可以由可变参控制。

按照常理来看,Python是没有办法来做到方法重载了。可是为了实现这种重载:定义一个方法即可有多种调用方式,这就 间接实现了方法的重载。

:若是在类里面去定义多个重名的方法(即使参数列表不同),只有最后一个方法会有效(前面的都被它覆盖了)。

之前我们也说过了Python是一门动态语言(解释执行),可以体现在 我们动态的为一个类添加新方法,or 动态的修改类的已有方法。 详情如下:
在这里插入图片描述

详解面向对象封装的具体实现

私有属性

与严格厚重的C++不一样的是:Python对于类的成员是没有严格的访问控制权限的限制。在Python里面,私有的属性、方法有以下几个注意事项:

1、通常约定:__开头的属性是private;其他的为public
2、类的内部可以访问私有属性和私有方法
3、类外部不能够 直接访问 私有属性和私有方法
4、在类外部只能通过 objectname._classname__privateelementname来访问私有的(属性or方法)

一般来说,方法在本质上也是属性,不同的是 它可以通过()来执行。
在这里插入图片描述
注:大家要看一下 人家的提示符。也就是说直接访问私有属性是不可以的 只能够使用下面的方式:

# Python的封装:私有属性 与 私有方法

class Student:

    def __init__(self, name,score):
        self.name=name
        self.__score=score #这里已经定义成了私有属性

s1=Student("songbaobao",425)

print(s1.name)
print(s1._Student__score) #只有这种方法来间接访问

在这里插入图片描述
下面来看一下,我们把属性私有化之后 背后的原理:
在这里插入图片描述

私有方法

在这里插入图片描述
上面的私有属性(方法)对外是私有的,在类的内部 调用是畅通无阻的。如下所示
在这里插入图片描述

上面是展示了类的私有属性和私有方法,其实我们也可以使用同样的方式来定义类的私有变量
在这里插入图片描述
2020年5月4日02:17:23

装饰器@property

它可以将一个方法的调用变成普通的 属性调用,(其实际的作用:为属性增加相应的get set方法的)示例如下图:
在这里插入图片描述
首先,我们先看一下 类似于Java里面的set get方法,实例如下:
在这里插入图片描述
下面我们来使用一下装饰器@property来实现同样的功能:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_43949535/article/details/105785986