python开发学习笔记(4)————面向对象编程

面向对象编程

1.面向对象(OOP)

过程:类似函数,只负责执行,而没有返回值
函数:不仅能执行,还有返回值
定义
面向过程:把某一个需求的所有步骤从头到尾逐步实现,并将某些功能独立的代码封装成函数,最后完成代码。
面向过程特点:注重步骤和过程;如果需求复杂,代码也会复杂;开发复杂项目的难度大。
面向对象:面对需求时,首先明确职责(要做的事情),根据职责确定不同的对象,在对象中封装不同的方法,最后完成代码,让把不同对象调用不同的方法。
面向对象的特点:注重对象和职责;专门应对复杂项目开发,提供固定套路;需要一些面向对象的语法。

2.类和对象
1)定义

类是对一群具有相同特征或行为的事物的统称,是抽象的,不能直接使用。
特征称为属性,行为成为方法。
类是用来创建对象的。
对象是由类创建出来的一个具体存在,由哪个类创建出来的对象,则具有相应类中的属性和特征。

2)类和对象的关系

类是模板,对象是根据类这个模板创建出来的,先有类,再有对象。
类只有一个,对象可以有很多个。不同对象的属性各不相同。对象的属性和方法由类决定。

3)类的设计

面向对象开发前,首先进行需求分析,确定程序中需要包含哪些类。
类名:某类事物的名字,满足大驼峰命名法。每个单词的首字母都要大写,单词与单词之间没有下划线。
属性:这类事物具有的特征
方法:这类事物具有的行为
类名的确定:名词提炼法,分析整个业务流程,出现的名词。
属性和方法的确定:对象的特征描述通常定义为属性,对象具有的行为,通常定义成方法。

3.面向对象基础语法
1)dir函数

可以查看对象内所有的属性及方法
__方法__ 格式的方法是python提供的内置方法/属性

2)定义简单的类

1>语法格式:

class 类名:
	def 方法一(self,参数列表):
		pass
	def 方法二(self,参数列表):
		pass

2>创建对象
语法格式:

对象变量 = 类名()
3)引用概念

使用print输出对象变量,可以输出这个变量是由哪一个类创建的对象,以及在内存中的地址(十六进制表示)。
定义的变量引用了创建的对象在内存中的地址。
%d 以10进制输出数字;%x以16进制输出数字。

4)给对象设置属性(类外)

可以使用 .属性名 利用赋值语句即可。但此种方法一般不推荐使用。
self参数:哪一个对象调用的方法,self就是哪一个对象的引用。
所以在类的方法中,使用self.属性 来调用对象的属性
***** 对象的属性也应当封装在类中

5)初始化方法

创建对象时,自动进行:1.为对象在内存中分配空间;2.为对象的属性设置初始值。
这个设置初始值的方法就是 __init__ 方法。专门定义对象具有哪些属性。

6)在初始化方法内部设置属性

self.属性名 = 属性的初始值

7)使用参数设置属性初始值
def __init__(self,参数):
	self.属性名 = 参数

初始化方法中引入一个形参,将要设置的属性变为实参转入
步骤:
1>把希望设置的属性值,定义成__init__方法的参数
2>在方法内部,使用self.属性=形参 接收外部传递的参数
3>创建对象时,使用 类名(属性1,属性2,…)调用

8)其他内置方法和属性

1>del方法
当创建对象时,为对象分配完空间后,自动调用__init__方法。当对象被从内存中销毁时前,会自动调用__del__方法
2>str方法
print输出对象变量时,会输出这个对象变量是由哪个类创建,以及在内存中的地址。
使用__str__方法,可以自定义打印的内容。
语法结构:
在类中定义一个方法

def __str__(self):
		return 要返回的内容(返回的内容必须是字符串)

实际开发有多个类时,先开发简单的类,或者一个类被另一个类调用,则开发被调用的类。

9)一个对象的属性可以是另一个类创建的对象

士兵突击实例

10)身份运算符

身份运算符用于比较两个对象的内存地址是否一致(是否是对同一对象的引用)

is  x is y,类似id(x)==id(y)
is not  x is not y,类似id(x)!=id(y)

is和 == 的区别
is 判断的是两个变量引用对象是否是同一个
==判断的是引用变量的值是否相等

11)私有属性和私有方法

1>定义
只能在对象的内部被使用,而不能在外部被访问到。
在属性名或方法名前增加两个下划线,定义的就是私有属性或方法。
在对象的一般方法内部,是可以访问对象的私有属性的。
2>伪私有属性和私有方法
python中,并没有真正意义的私有。
python中,私有属性的真正名字为 _类名__私有属性名, 在外部通过这个属性名即可直接调用该私有属性。
python中,私有方法的真正名字为 _类名__私有方法名, 在外部通过这个方法名即可直接调用该私有方法。
日常开发中,不要使用这种方法访问对象的私有属性或私有方法。

4.继承(相同的代码不需要复写)

面向对象三大特性:封装、继承、多态

1)单继承

定义:子类拥有父类的所有属性和方法
语法格式:

class 子类名(父类名):

专业术语:
例子: Animal 父类, Dog 子类
Dog是Animal的子类,Animal是Dog的父类,Dog类从Animal类继承
Dog类是Animal类的派生类,Animal类是Dog类的基类,Dog类从Animal类派生。

2)继承的传递性:

C类从B类继承,B类又从A类继承。那么,C类就具有B类和A类的所有属性和方法。
继承传递性注意事项:

3)方法重写

当父类的方法实现不能满足子类需求时,可以对方法进行重写。
重写父类方法有两种情况:
a.覆盖父类的方法
子类中重新写父类中的方法,使用子类对象调用方法时,会调用子类中重写的方法。
方法:在子类中,定义一个和父类同名的方法并且实现
b.对父类方法进行扩展
前提:父类原本封装的方法实现是子类方法的一部分
方法:在子类中重写父类的方法;在需要的位置使用super().父类方法,来调用父类方法的执行;代码其他的位置针对子类的需求,编写子类特有的代码实现。
关于super:
python中,super是一个特殊的类;super()就是使用super类创建出来的对象;最常使用的场景就是在重写父类方法时,调用在父类中封装的方法实现。
调用父类方法的另外一种方式(python2.x)
父类名.方法(self)
python3.x 也支持,但是不推荐这样调用,因为父类一旦发生改变,这里也需要修改。

5.私有属性和私有方法(继承方面)

1)子类不能在自己的方法内部直接访问父类的私有属性或私有方法
2)子类对象可以通过父类的公有方法间接访问私有属性或私有方法

6.多继承
1)概念

子类可以拥有多个父类,并且拥有所有父类的属性和方法
语法:

class 子类名(父类名1,父类名2,……):
	pass
2)注意事项

a.如果不同父类中存在同名的方法,子类对象在调用方法时,会调用某一类中的方法。在实际开发中要避免这种情况,父类之间存在同名方法时,应该尽量避免使用多继承。
科普:python中的MRO----方法搜索顺序
MRO是 方法解决顺序,主要用于在多继承时判断方法、属性的调用路径。
python中内置属性__mro__可以查看方法搜索顺序。
如,print(c.__mro__)会输出c对象的所有关系类,输出顺序则为方法的搜索顺序。找到相应方法就执行,没有找到就继续向下搜索。

3)新式类与旧式类(经典类)

object是python为所有对象提供的基类。
新式类:以object类为基类,推荐使用。
经典类:不以object类为基类,不推荐使用。
python3.x中定义的类默认都是新式类。
python2.x中,如果没有指定父类,则不会以object为基类。
为了编写的代码在python2.x和python3.x中都能运行,建议今后定义类时,如果没有父类,统一继承自object。

class 类名(object):
		pass
7.多态

不同的子类对象调用相同的父类方法,产生不同的执行结果。
特点:增加代码的灵活度;以继承和重写父类方法为前提;调用方法的技巧,不会影响到类的内部设计。

8.类属性、类方法、静态方法
1)类结构

术语:创建出来的对象叫类的实例;创建对象的动作叫实例化;对象的属性叫实例属性;对象调用的方法叫实例方法。
每个对象都有自己独立的内存空间,保存各自不同的属性;多个对象的方法,在内存中只有一份,在调用方法时,需要把对象的引用传递到方法内部。

2)类是一个特殊的对象

程序运行时,类会被加载到内存中;python中,类是特殊的对象——类对象;程序运行时,类对象在内存中只有一份,使用一个类可以创建出很多个对象实例;除了封装实例的属性和方法外,类对象还可以拥有自己的属性和方法;通过 类名. 的方法可以访问类的属性或者类的方法。

3)类属性和实例属性

1>类属性:类对象中定义的属性;通常用来记录与这个类相关的特征;类属性不会用于记录具体对象的特征。
2>属性的获取机制
python中属性的获取存在一个向上查找机制
步骤:首先在对象内部查找对象属性;如果没有找到就会向上寻找类属性。
一般是 类名.类属性名 进行调用。对象.类属性也可以调用,但不推荐。
注意:如果使用 对象.类属性 = 值 语句时,只会给对象添加一个属性,而不会影响到类属性的值。

4)类方法

语法结构:

@classmethod
def 类方法名(cls):
	pass

1>类方法需要用修饰器 @classmethod 来标识,告诉解释器这是一个类方法
2>类方法的第一个参数应该是cls
由哪一个类调用的方法,方法内的cls就是哪一个类的引用
这个参数和实例方法的第一个参数是self类似
提示使用其他名称也可以,不过习惯使用cls
3>通过 类名. 调用类方法,调用方法时,不需要传递cls参数
4>在方法内部:
可以使用 cls. 访问类的属性
也可以通过 cls. 调用其他的类方法
5)静态方法
场景:开发时,如果需要在类中封装一个方法,这个方法:既不需要访问实例属性或者调用实例方法,也不需要访问类属性或调用类方法。这个时候,可以把这个方法封装成一个静态方法。
语法:

@staticmethod
def 静态方法名():
	pass

 静态方法需要用修饰器 @staticmethod 标识,告诉解释器这是一个静态方法
 通过类名,调用静态方法

6)方法综合

实例方法:方法内部需要访问实例属性;实例方法内部可以使用 类名.访问类属性
类方法:方法内部只需要访问类属性
静态方法:方法内部,不需要访问实例属性和类属性

9.单例模式
1)设计模式和单例设计模式

设计模式:前人工作的总结和提炼,通常,设计模式都是针对某一特定问题的成熟的解决方案。使用设计模式为了可重用代码、让代码更容易地被他人理解、保证代码可靠性。
单例设计模式:目的:让类创建的对象,在系统中只有唯一的一个实例。
每一次执行 类名() 返回的对象,内存地址是相同的。

2)__new__方法

1>使用 类名() 创建对象时,python解释器首先会调用 __new__ 方法为对象分配空间。
2>__new__是一个由object基类提供的内置的静态方法,作用有两个:在内存中为对象分配空间;返回对象的引用。
3>python解释器获得对象的引用后,将引用作为第一个参数,传递给__init__方法
4>重写__new__方法一定要 return super().__new__(cls)
5>如果不做上一步,python解释器就得不到分配了空间的对象引用,就不会调用对象的初始化方法。
6>注意:__new__是一个静态方法,调用时需要主动传递cls参数

3)单例设计模式思路分析

1.>定义一个类属性,初始值是None,用于记录单例对象的引用
2>重写__new__方法
3>如果类属性 is None,调用父类方法分配空间,并在类属性中记录结果;如果类属性 is not None,则直接把类属性中记录的对象引用返回。
4>返回类属性中记录的对象引用。

class 类名:
instance = None
def __new__(cls, *args, **kwargs):
	if cls.instance is None:   #判断类属性是否已经被赋值
		cls.instance = super().__new__(cls)
	return cls.instance    #返回类属性的单例引用
4)只执行一次初始化工作

上一节中,每次创建新对象,占用的都是同一个内存地址,即对象引用一直保持不变,但是,初始化方法还会被再次调用。
需求
让初始化动作只被执行一次。
解决方法:
1>定义一个类属性 init_flag 标记是否执行过初始化方法,初始值为False
2>在 __init__ 方法中,判断init_flag,如果为False 就执行初始化动作
3>然后将 init_flag 设置为True
4>这样,再次自动调用 __init__ 方法时,初始化动作就不会再被执行了。

10.异常

python解释器遇到错误,会停止程序执行,并提供一些列错误信息,就是异常。
程序停止执行并且提示错误信息,通常称之为抛出异常。
通过异常捕捉可以针对突发事件做集中的处理,从而保证程序的稳定性和健壮性。

1)异常捕获

语法:

try:
	尝试执行的代码
except:
	出现错误的处理
2)错误类型捕获

捕获错误类型,可以针对不同类型的错误,做出不同的响应。
语法:

try:
	尝试执行的代码
except 错误类型1:
	针对错误类型1,对应的代码处理
except (错误类型2,错误类型3):
	针对错误类型2和3,对应的代码处理
except Exception as result:
	print(“未知错误 %s” % result)

最后一个except 可以捕获未考虑到的错误,这样,无论出现任何错误,程序都不会终止。实际开发中,要预判所有可能出现的错误还是有难度的。

3)异常捕获完整语法
try:
	尝试执行的代码
except 错误类型1:
	针对错误类型1,对应的代码处理
except (错误类型2,错误类型3):
	针对错误类型2和3,对应的代码处理
except Exception as result:
	print(“未知错误 %s” % result)
else:
	没有异常才会执行的代码
finally:
	无论是否有异常,都会执行的代码
4)异常的传递

当函数/方法执行出现异常,会将异常传递给函数/方法调用一方。
如果传递到主程序,仍然没有异常处理,程序才会被终止。
提示:在开发中,可以在主函数中增加异常捕获;在主函数中调用其他函数,只要出现异常,都会传递到主函数的异常捕获中;这样就不需要在代码中,增加大量的异常捕获,能够保证代码的整洁。

5)抛出raise异常

根据应用程序特有的业务需求主动抛出异常。
比如,提示用户输入密码,如果长度少于8, 抛出异常。
python中提供了一个Exception异常类
步骤:创建一个Exception的对象;使用raise关键字抛出异常对象
语法步骤:1>创建异常对象 ex = Exception(“错误信息”) 括号内可以输入错误信息。
2>抛出异常 raise ex

11.模块
1)模块的两种导入方式

1>import 导入
如,import 模块名1
import 模块名2
每个导入应该独占一行
导入之后,使用 模块名. 使用模块提供的工具 ——全局变量、函数、类
可以使用as指定模块的别名
import 模块名1 as 模块别名
模块别名应该符合大驼峰命名法
2>from…import导入
如果希望从某一个模块中,导入部分工具,就可以使用from…import的方式
import 模块名 是一次性把模块中所有工具全部导入,并且通过模块名/别名访问
语法:
from 模块名1 import 工具名
导入之后,不需要通过模块名;可以直接使用模块提供的工具——全局变量、函数、类
注意:如果两个模块含有同名的函数,后导入模块的函数会覆盖先导入的函数。
3>from…import * (知道)
语法:
from 模块名1 import *

2)模块的搜索顺序

python解释器在导入模块时,会:
a. 搜索当前目录指定模块名的文件,如果有就直接导入
b. 如果没有,再搜索系统目录
开发时,给文件起名,不要和系统的模块文件重名
python中每一个模块都有一个内置属性,__file__可以查看模块的完整路径

3)原则———每一个文件都应该是可以被导入的

1>一个独立的python文件就是一个模块
2>在导入文件时,文件中所有没有任何缩进的代码都会执行一遍
__name__属性
__name__是python的一个内置属性,记录着一个字符串
如果是被其他文件导入的,__name__就是模块名
如果是当前执行的程序 __name____main__

4)包

1>概念:包含多个模块的特殊目录;目录下有一个特殊的文件__init__.py;包名的命名方式和变量名一致,小写字母。
2>好处:使用 import 包名 可以一次性导入包中所有的模块
3>建立包的方式:新建一个包,新建一个名为__init__.py文件
4>要在外界使用包中的模块,需要在__init__.py中指定对外界提供的模块列表
from . import 其他py文件名

5)发布模块

1>制作发布压缩包步骤
a. 创建setup.py文件
b. 构建模块
python3 setup.py build
c. 生成发布压缩包
python3 setup.py sdist

6)安装模块包
tar -zxvf 包名.tar.gz
sudo python3 setup.py install

卸载时,直接从安装目录下删除包即可
12.文件操作

1)文件的概念

1>定义
计算机的文件,就是存储在长期储存设备上的一些数据
长期存储设备包括:硬盘、U盘、移动硬盘、光盘。。。
2>文件的作用
讲数据长期保存下来,在需要的时候使用
3>文件的存储方式
计算机中,文件是以二进制的方式保存在磁盘上的

文本文件:
a。可以使用文本编辑器查看
b。本质上还是二进制文件
c。例如:python源文件
二进制文件:
a。保存的内容不是给人直接阅读的,而是提供给其他软件使用的
b。例如:图片文件、音频文件、视频文件等
c。二进制文件不能使用文本编辑器查看
2)文件操作

1>操作文件的步骤:打开文件;读写文件;关闭文件
2>操作文件的函数/方法
函数 open 打开文件,并且返回文件操作对象
方法 read 将文件内容读取到内存
方法 write 将指定内容写入文件
方法 close 关闭文件
如果忘记关闭文件,就是造成资源的消耗,而且会影响到后续对文件的访问。
read方法是一次性读取并返回文件的全部内容
3>文件指针
read方法执行后,会把文件指针移动到文件的末尾。
文件指针标记从哪个位置开始读取数据
第一次打开文件时,通常文件指针会指向文件的开始位置
当执行了read方法后,文件指针会移动到读取内容的末尾
4>打开文件的方式
语法:

f = open(“文件名”, “访问方式”)
r  以只读方式打开文件,这个默认方式
w  以只写方式打开文件,如果文件存在则会被覆盖
a  以追加方式打开文件,如果文件已存在,文件指针将会放在文件的末尾。
r+ 以读写方式打开文件,文件的指针将会放在文件的开头
w+ 以读写方式打开文件
a+ 以读写方式打开文件,如果文件已存在,文件指针将会放在文件的末尾。如果不存在,创建新文件进行写入。

5>readline读取(读取大文件,避免给内存压力)
readline方法可以一次读取一行内容
方法执行后,会把文件指针移动到下一行,准备再次读取。
6>小文件复制
打开一个文件,读取所有内容,并写入到另一个文件中。
7>大文件复制
打开一个文件,逐行读取内容,并顺序写入另一个文件中
8>文件/目录的常用管理操作
python中需要导入os模块

13.文本编码

python2.x 默认使用 ASCII 编码
python3.x 默认使用 UTF-8 编码
ASCII 编码
计算机中只有256个ASCII字符
一个ASCII在内存中占用一个字符的空间
UTF-8 编码
使用1-6个字节表示一个utf-8 字符

1)python2.x中使用中文
# *-* coding:utf-8 *-*
2)python2.x中处理带中文的字符串

字符串引号前加一个字母u,告诉解释器这是一个utf-8编码格式的字符串

14.内建函数eval

eval()函数:将字符串当成有效的表达式来求值并返回计算结果。
注意:不要滥用eval函数,开发时,不要使用eval直接转换input的结果
__import__(‘os’).system(‘ls’) 其他用户用这个命令查看本机文件
其他用户可以通过eval 来操作本机系统

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值