面向对象编程基础

一、面向对象概念

1.1 什么是面向过程

​ 就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。

​ 生活中的的例子举例。

1.2 什么是面向对象

​ 面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。

  1. 面向对象是一种思维方法
  2. 面向对象是一种编程方法
  3. 面向对象并不只针对某一种编程语言

1.3 面向对象和面向过程的区别和联系

面向过程,做什么

面向过程过程侧重整个问题的解决步骤,着眼局部或者具体,核心:过程的实现

【面向过程】:

为了把大象装进冰箱,需要3个过程。

  1. 把冰箱门打开(得到打开门的冰箱)
  2. 把大象装进去(打开门后,得到里面装着大象的冰箱)
  3. 把冰箱门关上(打开门、装好大象后,获得关好门的冰箱)

    每个过程有一个阶段性的目标,依次完成这些过程,就能把大象装进冰箱。

面向对象,谁来做

面向对象侧重具体的功能,让某个对象具有这样的功能。更加侧重于整体。核心:对象

【面向对象】:

为了把大象装进冰箱,需要做三个动作(或者叫行为)。

每个动作有一个执行者,它就是对象。

  1. 冰箱,你给我把门打开
  2. 大象,你给我钻到冰箱里去
  3. 冰箱,你给我把门关上

    依次做这些动作,就能把大象装进冰箱。
各自的优缺点

面向过程的优点:
流程化使得编程任务明确,在开发之前基本考虑了实现方式和最终结果;
效率高,面向过程强调代码的短小精悍,善于结合数据结构来开发高效率的程序。。
流程明确,具体步骤清楚,便于节点分析。 缺点是:需要深入的思考,耗费精力,代码重用性低,扩展能力差,维护起来难度比较高,
对复杂业务来说,面向过程的模块难度较高,耦合度也比较高。 面向对象的优点:结构清晰,程序便于模块化,结构化,抽象化,更加符合人类的思维方式;
封装性,将事务高度抽象,从而便于流程中的行为分析,也便于操作和自省;
容易扩展,代码重用率高,可继承,可覆盖;
实现简单,可有效地减少程序的维护工作量,软件开发效率高。 缺点是:效率低,面向对象在面向过程的基础上高度抽象,从而和代码底层的直接交互非常少机会,
从而不适合底层开发和游戏甚至多媒体开发;
复杂性,对于事务开发而言,事务本身是面向过程的,过度的封装导致事务本身的复杂性提高。

编程语言对面向对象的实现主流的有两种方式:基于类的面向对象和基于原型的面向对象。

不管以什么方式实现,都具有面向对象的三大特征:

  • 封装

    也就是把客观事物封装成抽象的类或具体的对象,并且类或对象可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。

  • 继承

    可以让某个类型的对象获得另一个类型的对象的属性的方法

  • 多态

    不同实例的相同方法在不同情形有不同表现形式。多态机制使具有不同内部结构的对象可以共享相同的外部接口。

1.4编程语言中面向对象的实现方式

1.4.1基于类的面向对象

典型的语言:Java、C#、 pthon 、c++等

对象(object)依靠 类(class)来产生

1.4.2基于原型的面向对象

典型的语言:JavaScript

对象(object)则是依靠 构造器(constructor)利用 原型(prototype)构造出来的

二、python中的类

python 是基于类的面向的对象语言, 所以学习 python 面向对象, 必须要先学习类

2.1类和实例的概念

通过前面的学习我们已经知道, 面向对象编程(Object Oriented Programming,简称OOP),是一种程序设计思想。OOP把对象作为程序的基本单元,一个对象包含了 数据和操作数据的函数(方法)

而面向对象的程序设计把计算机程序视为一组对象的集合,而每个对象都可以接收其他对象发过来的消息,并处理这些消息,计算机程序的执行就是一系列消息在各个对象之间传递。


2.1.1 类的理解

在 python 中所有类型的数据都可以看成对象, 包括我们我们以前学习的所有的内置类型int, float等.

像这些 int, float, list这些数据类型, 就是我们面向对象中的类

我们可以根据需要自定义很多类型出来, 这些自定义的类型也是我们面向对象中的类


2.1.2对象的理解

我们天天说对象, 到底该怎么去理解对象?

a = 3 变量 a 赋值为整数 3, 这里的 3 就是一个int类型的对象.

nums = [2, 4, 1] 这里的 [2, 4, 1] 就是list类型的列表对象.

可以这么说, 在 python 中任何类型的数据数据都是对象.(和其他语言 c++, java 等不太一样, 他们有一些不是对象的基本数据类型)

对象其实就是对数据和操作数据的方法进行的封装


2.1.3类与对象的关系

类与对象的关系, 就是我们每个人同人类的关系一样.

人类是对每个具体的人的共同的特点的抽象. 比如都有手脚, 耳朵, 还都可以吃饭, 娱乐, 男人还可以去大保健. 人类就是编程语言中的类型.

而每个人是人类的一个个的具体的实现. 每个人都是编程语言中的一个对象


类是对对象的抽象描述, 而对象是类的具体实现. 他们是抽象与具体的关系.


例如:

汽车制造图纸和一个个的汽车.

图纸就是类, 汽车就是对象


2.1.4先有对象还是先有类

看情况:

  1. 在做面向对象分析的时候, 一般是先有对象, 然后把对象的共性抽象出来, 然后就形成了类.
  2. 编写代码的时候, 一般是先完成类的编写, 然后在需要的时候创建对象就可以了.

2.2 定义类

我们需要关键字class来定义类

class 类名:
# 类中定义的内容

比如我们定义一个表示学生的Student类:

class Student:
pass

说明:

  1. class 后面紧跟类名. 类名的命名使用驼峰命名法.
  2. 类名的后面跟一个冒号
  3. 然后是带有正确缩进的类的主体.(上面的例子中使用 pass, 表示空的类主体)

2.3创建对象

定义类的目的就是使用类来创建对象.

在 python 中使用类创建对象与其他语言差别较大, 其他语言需要使用关键字new, python 精简了创建方式, 我们不需要new.

2.3.1 python 就是以函数形式调用来创建对象的!


python 创建对象直接使用类名()就可以了.

class Student:
pass s1 = Student() # 使用类创建对象
print(s1)

创建对象的过程是不是和方法调用一样一样的?!

2.4类定义的深入研究

类必须先定义再使用

类的定义与函数定义是一样的, 都要遵循先定义再使用

s2 = Student()    # 此处无法使用类来创建对象

class Student:
pass

可以在if语句中甚至函数中定义类

if True:
class Student:
pass s1 = Student()
print(s1)

使用类的时候, 一定要保证类被已经被定义了.


类的主体

类主体中都可以定义什么?

在 python 中类可以定义:


1. 字段(field, 在国内很多人叫属性)

在 python 中字段分 2 种:

  1. 实例变量(Instance Variables):

    他存储的值是属于每一个对象的, 或者对不同的对象来说他们是独立. 就像人的私有财产
  2. 类变量(Class Variables):

    他存储的值是属于类本身的, 而不是属于某一个具体的对象, 或者说他是被所有的对象所共有的. 就像公共财产

2. 方法

方法就是我们以前学习的函数, 只是同类扯上关系了而已!

在 python 中的方法分 3 种:

  1. 实例方法.

    和实例变量一样, 他是属于对象的.

    实例方法相比普通的函数有一个比较特殊的地方:第一个形参总是会自动传入这个实例(对象)
  2. 类方法

    和类变量一样, 是属于类的.

    类方法与实例方法的区别在于第一个参数: 类方法的第一个参数总是这个类本身.
  3. 静态方法

    静态方法和实例没有任何关系. 它仅仅是定义在类中而已, 这个时候类就相当于这个方法的命名空间.

2.4.1类中定义字段

2.4.1.1类变量

类变量表示所有的对象所共有的一种数据.换句话说, 所有的对象都可以直接访问到, 并且他们访问到的是同一个变量(肯定是相同的值!)

把变量直接声明在类的内部的变量.

访问类变量直接通过类名.变量名来访问.

class Student:
# 直接在类中定义变量,
# 这样的变量就是类变量(类属性, 类似 java 中的静态属性)
country = "china" print(Student.country)
# 修改类变量的值
Student.country = "usa"
print(Student.country)


当然你也可以在任何的地方通过类名.属性=值的方式动态给类添加类属性.

class Student:
# 直接在类中定义变量,
# 这样的变量就是类变量(类属性, 类似 java 中的静态属性)
country = "china" Student.count = 1 # 动态添加类属性
print(Student.count)

但是, 建议在类中直接定义类属性, 只有在需要的时候才使用动态的方式添加类属性.


2.4.1.2 实例变量

实例变量表示每个对象都自己所独有.

所以, 实例变量与每个具体的对象相关.

添加实例变量:

一般是在一个叫做__init__()的方法里面来添加. (关于方法下节再细讲, 现在你只需要知道他是一个函数就可以了)

__init__(), 注意他是左右分别有 2 个_. 这个方法不需要我们手动去调用, 当你使用类创建对象的时候, 会自动调用这个方法.

这个方法的第 1 个参数永远是创建的那个对象(所有的实例方法都是这样的), 我们可以通过这个参数来向对象中添加属性, 这样的属性就是实例属性.

作为国际惯例, 第 1 个参数的一般都命名为self, 当然你也可以给他起个别的名字, 但是何必呢!


class Student:
def __init__(self):
self.name = "李四"
self.age = 20 s = Student()
print(s.name)
print(s.age)


上面这种写法, 会导致使用这个类创建的对象的nameage这个两个实例变量的值都会初始化为同样的值, 这其实并不好.

我们想每个变量初始化的值都不一样, 可以在创建的对象的是把具体的值沟通过实参传递过去, 则实参会自动传到__init__()方法的第 2 个开始的参数中.

class Student:
def __init__(self, name, age):
self.name = name
self.age = age zs = Student("张三", 20)
print(zs.name + " " + str(zs.age))
ls = Student("李四", 30)
print(ls.name + " " + str(ls.age))

你会发现每个对象的值都不一样的!


2.4.1.3 可以通过对象直接访问类变量

python 允许通过对象直接访问到类变量. (有些语言是不允许的, 比如 c#, JavaScript 就不允许, 但是 java 允许)

class Student:
country = "china" def __init__(self, name, age):
self.name = name
self.age = age zs = Student("张三", 20)
print(zs.name + " " + str(zs.age))
ls = Student("李四", 30)
print(ls.name + " " + str(ls.age)) print(zs.country) # 通过对象直接访问类变量
print(ls.country)


2.4.2 类中定义方法

2.4.2.1. 定义实例方法

实例方法和普通方法的区别:

  1. 实例方法必须定义在类中
  2. 实例方法的第一个参数永远是那个具体的对象, 而且不需要调用者手动传入, python 会自动传入那个对象. 而且这个形参一般命名为self
  3. 实例方法调用方式:对象.实例方法(实参)

class Student:
def __init__(self, name):
self.name = name # 定义一个实例方法:一个参数表示具体的对象, python 会默认传入
def speak(self):
print("我的名字是:" + self.name) # 在实例方法中访问实例变量 s = Student("志玲")
s.speak()


self的理解

学过其他语言的人都知道, python 的 self 其实就是在其他语言的this.

那么self到底指代哪个对象?

通过哪个对象调用的这个实例方法, 那么这个实例方法中的self就指代谁

而且 python 的self一朝绑定, 终身不变. (不像 javascript 中的那个 this 小婊砸随着调用方式的不同而而更改绑定对象, 让你眼花缭乱到怀疑人生)


class Student:
def __init__(self, name):
self.name = name # 定义一个实例方法:一个参数表示具体的对象, python 会默认传入
def speak(self):
print("我的名字是:" + self.name) # 在实例方法中访问实例变量 s = Student("志玲")
# s.speak 的 this 永远指定的是 s 对象
foo = s.speak # 重新定义一个变量, 指向了对象 s 的 speak 方法.
foo() # 则 self 仍然绑定的是 s 对象


class Student:
def __init__(self, name):
self.name = name def speak(self):
print("我的名字是:" + self.name) # 在实例方法中访问实例变量 s1 = Student("志玲")
s2 = Student("凤姐") s2.speak = s1.speak s2.speak()

说明:

s1.speak表示的那个方法赋值给s2.speak, 虽然你调用的时候使用的是s2.speak(), 但是他指向的那个方法的self已经永远的绑定到了s1


2.4.2.2. 定义类方法

类方法和实例方法的区别:

  1. 一个方法想成为类方法, 需要在方法的上面要添加一个内置装饰器:@classmethod
  2. 实例方法的第一个参数是具体的对象, 而类方法的第一个参数是类对象.(python 中一切皆对象, 那么类本身也是个对象, 我们一般称之为类对象). 类对象也是 python 自动传递. (类对象一般起名为 cls)
  3. 调用实例方法使用对象.实例方法(实参), 而调用类方法使用类名.类方法(实参)
  4. 类方法中可以访问类变量, 但是不能访问实例变量, 因为没有self啊.

class Student:
country = "china" @classmethod
def say(cls):
print("我们的国家是:" + cls.country) Student.say()


什么时候使用类方法

如果一个方法不需要操作实例变量, 则这个方法建议定义成类方法!


注意:

有一点注意, 类方法也可以通过实例对象来调用, 但是不管怎么调用, 类方法的第一个参数总是类对象!

class Student:
country = "china" @classmethod
def say(cls):
print("我们的国家是:" + cls.country) Student.say()
s = Student()
s.say()


2.3.2.3. 定义静态方法

静态方法其实是一种普通的函数, 他仅仅是处于类的命名空间中.(把当前类作为了他的命名空间, 其他情况与普通函数没有任何区别).

  1. 定义静态方法只需要在函数的上面添加一个装饰器:@staticmethod
  2. 调动静态方法: 类名.静态方法(实参). 只需要把类名作为他的前缀来执行, 与普通函数相比, 没有其他任何多余的操作!

class Student:
@staticmethod # 定义静态方法
def create_student():
print("我是个静态方法") Student.create_student()


静态方法的应用场景

因为 python 的类中只有一个__init__()方法, 意味着创建对象的方式只能有一种.

我们可以使用静态方法给外界提供其他的创建对象的方式.


import time
class Date:
"""
创建一个表示日期的类
"""
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day @staticmethod
def now():
"""
创建表示当前日期的对象
:return:
"""
t = time.localtime()
return Date(t.tm_year, t.tm_mon, t.tm_mday) @staticmethod
def tomorrow():
"""
创建表示明日日期的对象
:return:
"""
t = time.localtime(time.time() + 60 * 60 * 24)
return Date(t.tm_year, t.tm_mon, t.tm_mday) now = Date.now()
print("现在是: %d年%d月%d日" % (now.year, now.month, now.day))
now = Date.tomorrow()
print("明天是: %d年%d月%d日" % (now.year, now.month, now.day))

2.4.3 python中的__init()__方法

在任何一个 python 类中, 都存在一个__init__()的方法, 而且只能存在一个.

我们不管用什么办法创建对象, 都会自动的去执行__init__()方法

默认情况下的__init()__

默认情况, __init()__什么都不做.

__init__()初始化实例变量

__init()__方法的主要作用就是添加并初始化实例变量. 初始化的实例变量的值在创建对象的时候通过实参传递过来.

__init__()的第一个形参总是新创建的那个实例对象.

Python第七章-面向对象的更多相关文章

  1. Python第七章-面向对象高级

    面向对象高级 一. 特性 特性是指的property. property这个词的翻译一直都有问题, 很多人把它翻译为属性, 其实是不恰当和不准确的. 在这里翻译成特性是为了和属性区别开来. 属性是指的 ...

  2. 简学Python第七章__class面向对象高级用法与反射

    Python第七章__class面向对象高级用法与反射 欢迎加入Linux_Python学习群  群号:478616847 目录: Python中关于oop的常用术语 类的特殊方法 元类 反射 一.P ...

  3. <automate the boring stuff with python>---第七章 正则实例&正则贪心&匹配电话号码和邮箱

    第七章先通过字符串查找电话号码,比较了是否使用正则表达式程序的差异,明显正则写法更为简洁.易扩展.模式:3 个数字,一个短横线,3个数字,一个短横线,再是4 个数字.例如:415-555-4242 i ...

  4. Python第六章 面向对象

    第六章 面向对象 1.面向对象初了解 ​ 面向对象的优点: ​ 1.对相似功能的函数,同一个业务下的函数进行归类,分类 ​ 2.类是一个公共的模板,对象就是从具体的模板中实例化出来的,得到对象就得到一 ...

  5. 流畅的python第七章函数装饰器和闭包学习记录

    本章讨论的话题 python如何计算装饰器句法 python如何判断变量是不是局部的(通过函数内部是否给变量赋值过来判断是否是局部变量) 闭包存在的原因和工作原理(闭包是一种函数,它会保留定义函数时存 ...

  6. Python第七章(北理国家精品课 嵩天等)

    7.1文件的使用 1.1文本类型 文本文件:由单一特定编码组成的文件,如.txt 二进制文件:如.png,.avi 1.2文件的打开和关闭 打开-操作-关闭 <变量名> = open(&l ...

  7. python第七章:常用模块--小白博客

    yagmail模块 python标准库中发送电子邮件的模块比较复杂,因此,有许多开原的库提供了更加易用的接口来发送电子邮件,其中yagmail是一个使用比较广泛的开原项目,yagmail底层依然使用了 ...

  8. java 第七章 面向对象高级特性

    一.类的继承 (一)继承的含义 1.在Java中定义一个类时,让该类通过关键字extends继承一个已有的类,这就是类的继承(泛化). 2.被继承的类称为父类(超类,基类),新的类称为子类(派生类). ...

  9. 简学Python第六章__class面向对象编程与异常处理

    Python第六章__class面向对象编程与异常处理 欢迎加入Linux_Python学习群  群号:478616847 目录: 面向对象的程序设计 类和对象 封装 继承与派生 多态与多态性 特性p ...

随机推荐

  1. web博客

    欢迎大家来戳一戳

  2. Linux命令学习神器!命令看不懂直接给你解释!

    大家都知道,Linux 系统有非常多的命令,而且每个命令又有非常多的用法,想要全部记住所有命令的所有用法,恐怕是一件不可能完成的任务. 一般情况下,我们学习一个命令时,要么直接百度去搜索它的用法,要么 ...

  3. python webp转jpg

    webp格式转jpg格式 从网页上保存下来的webp格式的图片用ps和一些看图软件打不开,所以需要进行下转换. 直接上py代码.代码用到了PIL库,如果电脑上没有还需要pip install Pill ...

  4. element ui table render-header自定义表头信息使用

    在使用vue自定义组件内容过程之中,我们绝大多数情况下都是通过预先写好不同的html模板,再通过props传入不同的值来渲染不同的模板.例如我们需要实现一个<v-title size='1'&g ...

  5. ES6的编程风格

    1,建议使用let替代var 2,全局常量使用const,多使用const有利于提高程序的运行效率. const有两个好处:一是阅读代码的人立刻会意识到不应该修改这个值,二是防止无意间修改变量值导致错 ...

  6. 跨域解决方案之CORS

    什么情况表示遇到跨域请求 一般在前后端分离项目中,前端请求接口,浏览器控制台报如下错误 类似 No 'Access-Control-Allow-Origin' header 报错 为什么会有跨域请求 ...

  7. Spring Boot从入门到精通(八)日志管理实现和配置信息分析

    Spring Boot对日志的处理,与平时我们处理日志的方式完全一致,它为Java Util Logging.Log4J2和Logback提供了默认配置.对于每种日志都预先配置使用控制台输出和可选的文 ...

  8. JavaMail(一):利用JavaMail发送简单邮件

    JavaMail,提供给开发者处理电子邮件相关的编程接口.它是Sun发布的用来处理email的API.它可以方便地执行一些常用的邮件传输.但它并没有包含在JDK中,要使用JavaMail首先要下载ja ...

  9. LeetCode 41,一题解读in-place思想

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是LeetCode题解系列第21篇,今天来看一道人狠话不多的题目. 题面 题目非常简单,只有一句话,给定一个整数数组,要求返回最小的不在 ...

  10. Python装饰器及内置函数

    装饰器 听名字应该知道这是一个装饰的东西,我们今天就来讲解一下装饰器,有的铁子们应该听说,有的没有听说过.没有关系我告诉你们这是一个很神奇的东西 这个有多神奇呢? 我们先来复习一下闭包 def fun ...