面向对象-学习笔记整理

面向对象( Object Oriented Programming,OOP)

面相过程 根据开发需求,将某些 功能独立 的代码 封装 成一个又一个 函数 顺序地调用 不同的函数
面向对象 是 根据 职责 在 一个对象中 封装 多个方法
1.在完成某一个需求前,首先确定 职责 —— 要做的事情(方法)
2.根据 职责 确定不同的 对象,在 对象 内部封装不同的 方法(多个)
3.最后完成的代码,就是顺序地让 不同的对象 调用 不同的方法


是对一群具有 相同 特征 或者 行为 的事物的一个统称,是抽象的,不能直接使用
特征 被称为 属性
行为 被称为 方法

对象
对象 是 由类创建出来的一个具体存在可以直接使用,具有被该类创建出来的属性和方法
类是模板,对象 是根据 类 这个模板创建出来的,应该 先有类,再有对象
类 只有一个,而 对象 可以有很多个
不同的对象 之间 属性 可能会各不相同
类 中定义了什么 属性和方法,对象 中就有什么属性和方法,不可能多,也不可能少

类的设计
设计一个类,通常需要满足一下三个要素
类名 这类事物的名字,满足大驼峰命名法
属性 这类事物具有什么样的特征
方法 这类事物具有什么样的行为

面相对象基础语法
dir() 传入 标识符 / 数据,可以查看对象内的 所有属性及方法
在这里插入图片描述

_方法名_ 格式的方法是 Python 提供的 内置方法 / 属性

定义只包含方法的类

class 类名:
	def 方法1(self,参数1,参数2....):
		pass
	def 方法2(self,参数1,参数2....):
		pass

注意: 方法的定义类似于函数,但方法中第一个参数必须为self
self 参数
在类封装的方法内部,self 就表示 当前调用方法的对象自己
调用方法时,不需要传递 self 参数
在方法内部 可以通过 self. 访问对象的属性 也可以通过 self. 调用其他的对象方法
类的外部,通过 变量名. 访问对象的 属性和方法
类封装的方法中,通过 self. 访问对象的 属性和方法
创建对象
通过 **对象变量 = 类名()**创建一个对象

初始化方法
self.属性名 = 属性的初始值

当使用 类名() 创建对象时,会 自动 执行以下操作:
1.为对象在内存中 分配空间 —— 创建对象
2.为对象的属性 设置初始值 —— 初始化方法(_init_) _init_ 是对象的内置方法,用于定义一个类中具有的属性
初始化的同时设置初始值
在定义__init__的时候,传入形参,就可以通过该形参来在创建对象的同时,灵活的自定义该对象的属性
self.属性 = 形参
在创建对象时,使用 类名(属性1, 属性2…) 调用

class Student():
	def __init__(self,name):
		self.name = name
	def work(self):
		print('%s 正在写作业...' % self.name)
stu1 = Student('Alen')
stu2 = Student('Lisa')
stu1.work()
stu2.work()

在这里插入图片描述
内置方法和属性
_del_ 为方法 作用是对象被从内存中销毁前,会被 自动 调用
当使用 类名() 创建对象时,为对象 分配完空间后,自动 调用 init 方法
当一个 对象被从内存中销毁 前,会 自动 调用 del 方法
一个对象从调用 类名() 创建,生命周期开始
一个对象的 del 方法一旦被调用,生命周期结束
在对象的生命周期内,可以访问对象属性,或者让对象调用方法
_str_ 方法 为方法 作用是返回对象的描述信息,print 函数输出使用

class Student1():
	def __init__(self,name):
		self.name = name
	
class Student2():
	def __init__(self,name):
		self.name = name
		
	def __str__(self):
		return '我是%s' % self.name
		
stu1 = Student1('Alen')
stu2 = Student2('Lisa')
print(stu1)
print(stu2)

在这里插入图片描述
封装
封装 是面向对象编程的一大特点
面向对象思维是— 将 属性 和 方法 封装 到一个抽象的 类 中
外界 通过 类 创建 对象,然后 让对象调用方法
对象方法的细节 都被 封装 在 类的内部
注意:
1在 对象的方法内部,是可以 直接访问对象的属性 的
2同一个类 创建的 多个对象 之间,属性 互不干扰
None关键字
当定义属性初始值时,若未确定初始值,可以考虑定义为None
None可以赋值给任何一个变量,表示什么都没有
None 赋值使用“=”,判断使用身份运算符“is”
身份运算符
身份运算符用于 比较两个对象的 内存地址 是否一致 —— 是否是对同一个对象的引用
is 是判断两个标识符是不是引用同一个对象 x is y,类似 id(x) == id(y)
is not 是判断两个标识符是不是引用不同对象 x is not y,类似 id(a) != id(b)
is 与 == 区别:
is 用于判断 两个变量 引用对象是否为同一个
== 用于判断 引用变量的 是否相等
在这里插入图片描述
私有属性和私有方法
即 对象 不希望公开的 属性/方法,在 属性名或者方法名前 增加 两个下划线,定义的就是 私有 属性或方法
私有属性和方法在外部不能直接访问/调用,但在 对象方法的内部可以直接访问(女孩的年龄是秘密^)
在这里插入图片描述
继承
面向对象三大特性
封装 根据 职责 将 属性 和 方法 封装 到一个抽象的 类 中
继承 实现代码的重用,相同的代码不需要重复的编写
多态 不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度
单继承
继承的概念:子类 拥有 父类 的所有 方法 和 属性

# 基本语法
class 类名(父类名):
	pass

子类 继承自 父类,可以直接 享受 父类中已经封装好的方法和属性,通俗点讲,若C 类从 B 类继承,B 类又从 A 类继承,那么 C 类就具有 B 类和 A 类的所有属性和方法继承具有传递性
重写(override)
重写 父类方法有两种情况:
覆盖 父类的方法
若父类的方法实现 和 子类的方法实现,完全不同,就可以使用 覆盖 的方式,在子类中定义和父类方法同名的方法 重新编写 父类的方法实现
重写之后,在运行时,只会调用 子类中重写的方法,而不再会调用 父类封装的方法
在这里插入图片描述
对父类方法进行 扩展
若子类的方法实现 中 包含 父类的方法实现,即父类原本封装的方法实现 是 子类方法的一部分,就需要对父类方法进行扩展
在需要的位置使用 super().父类方法 来调用父类方法的执行
在这里插入图片描述
python中,super() 就是使用 super 类创建出来的对象
最常 使用的场景就是在 重写父类方法时,调用 在父类中封装的方法实现
父类的 私有属性 和 私有方法
子类对象 不能 在自己的方法内部,直接 访问 父类的 私有属性 或 私有方法
子类对象 可以通过 父类 的 公有方法 间接 访问到 私有属性 或 私有方法

在这里插入图片描述在这里插入图片描述
多继承
子类 可以拥有 多个父类,并且具有 所有父类 的 属性 和 方法

# 语法
class 子类名(父类名1, 父类名2...)
	pass

**注意:**若父类1和父类2中,出现同名方法,则需要避免使用多继承

新式类与旧式(经典)类
object 是 Python 为所有对象提供的 基类,提供有一些内置的属性和方法,可以使用 dir 函数查看

新式类:以 object 为基类的类,推荐使用
经典类:不以 object 为基类的类,不推荐使用

在 Python 3.x 中定义类时,如果没有指定父类会 默认使用 object 作为该类的 基类 —— Python 3.x 中定义的类都是 新式类
在 Python 2.x 中定义类时,如果没有指定父类,则
不会以 object 作为 基类

若没有父类,建议统一继承自 object:class 类名(object):
多态
封装
根据 职责 将 属性 和 方法 封装 到一个抽象的 类 中
定义类的准则
继承
实现代码的重用,相同的代码不需要重复的编写
设计类的技巧
子类针对自己特有的需求,编写特定的代码
多态
不同的 子类对象 调用相同的 父类方法,产生不同的执行结果
多态 可以 增加代码的灵活度
以 继承 和 重写父类方法 为前提
是调用方法的技巧,不会影响到类的内部设计

类属性和类方法
使用 类名() 创建对象,创建对象 的动作有两步:

  1. 在内存中为对象 分配空间
  2. 调用初始化方法_init_ 为 对象初始化

对象创建后,内存 中就有了一个对象的 实实在在 的存在 —— 实例
创建出来的 对象 叫做 类 的 实例
创建对象的 动作 叫做 实例化
对象的属性 叫做 实例属性
对象调用的方法 叫做 实例方法

每一个对象 都有自己 独立的内存空间,保存各自不同的属性
多个对象的方法,在内存中只有一份,在调用方法时,需要把对象的引用 传递到方法内部
Python 中 一切皆对象:
class AAA: 定义的类属于 类对象
obj = AAA() 属于 实例对象
在程序运行时,类 同样 会被加载到内存
在 Python 中,类 是一个特殊的对象 —— 类对象
在程序运行时,类对象 在内存中 只有一份,使用 一个类 可以创建出 很多个对象实例
除了封装 实例 的 属性 和 方法外,类对象 还可以拥有自己的 属性 和 方法,即类属性类方法
通过 类名. 的方式可以 访问类的属性 或者 调用类的方法
在这里插入图片描述
类属性和实例属性
类属性 就是给 类对象 中定义的 属性
通常用来记录 与这个类相关 的特征
类属性 不会用于记录 具体对象的特征

class Fruit(object):
    # 使用赋值语句,定义类属性,记录创建对象的总数
    count = 0
    def __init__(self, name):
        self.name = name
        # 针对类属性做一个计数+1
        Fruit.count += 1
# 创建对象
fruit_1 = Fruit("苹果")
fruit_2 = Fruit("香蕉")
fruit_3 = Fruit("葡萄")
print("现在有 %d 种水果" % Fruit.count)  # 现在有3种水果

类方法和静态方法
类方法
类属性 就是针对 类对象 定义的属性
使用 赋值语句 在 class 关键字下方可以定义 类属性
类属性 用于记录 与这个类相关 的特征
类方法 就是针对 类对象 定义的方法
在 类方法 内部可以直接访问 类属性 或者调用其他的 类方法

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

类方法需要用 装饰器(修饰器)@classmethod 来标识 ,告诉解释器这是一个类方法
类方法的 第一个参数 应该是 cls
由 哪一个类 调用的方法,方法内的 cls 就是 哪一个类的引用
这个参数和 实例方法 的第一个参数是 self 类似
提示 使用其他名称也可以,不过习惯使用 cls
通过 类名. 调用 类方法,调用方法时,不需要传递 cls 参数
在方法内部
可以通过 cls. 访问类的属性
也可以通过 cls. 调用其他的类方法
在类方法内部,可以直接使用 cls 访问 类属性 或者 调用类方法

class Fruit(object):
    # 使用赋值语句,定义类属性,记录创建对象的总数
    count = 0
    def __init__(self, name):
        self.name = name
        # 针对类属性做一个计数+1
        Fruit.count += 1

	# 定义一个类方法
	@classmethod
	def total_num(cls):
		print('一共有%d种水果' % cls.count)
# 创建对象
fruit_1 = Fruit("苹果")
fruit_2 = Fruit("香蕉")
fruit_3 = Fruit("葡萄")
Fruit.total_num() # 一共有3中水果

静态方法
如果需要在 类 中封装一个方法,这个方法:

  • 既 不需要 访问 实例属性 或者调用 实例方法 也 不需要 访问 类属性 或者调用 类方法
    这个时候,可以把这个方法封装成一个 静态方法
# 语法如下
@staticmethod
def 静态方法名():
    pass
class News(object):
    # 新闻数量计数
    new_count = 0
    
    @staticmethod
    def right():
        # 不需要访问实例属性也不需要访问类属性的方法
        print("xx独家报道")
    def __init__(self, title):
        self.title = title
new = News('今日热点')
new.right() # xx独家报道
print('*'*50)
# 静态方法调用可以通过类名.直接调用
News.right()  # xx独家报道

异常
异常 指程序在运行时,如果 Python 解释器 遇到 到一个错误并停止执行,提示的一些错误信息
提示错误信息的这个动作称作抛出(raise)异常
若 对某些代码的执行不能确定是否正确,可以增加 try捕获异常

# 语法格式:
try:
    尝试执行的代码(不确定是否能够正常执行的代码)
except:
	出现错误的处理

当 Python 解释器 抛出异常 时,最后一行错误信息的第一个单词,就是错误类型
在这里插入图片描述
在这里插入图片描述

try:
    num = int(input("请输入整数:"))
    result = 8 / num
    print(result)
except ValueError:
    print("变量类型错误,请输入正确的整数!")
except ZeroDivisionError:
	print("分母不能为0!")

捕获未知错误

# 语法如下:
except Exception as result:
	print("未知错误 %s" % result)

在这里插入图片描述
异常捕获完整语法

try:
    # 尝试执行的代码
    pass
except 错误类型1:
    # 针对错误类型1,对应的代码处理
    pass
except 错误类型2:
    # 针对错误类型2,对应的代码处理
    pass
...
except Exception as result:
    # 打印错误信息
    print(result)
else:
    # 没有异常才会执行的代码
    pass
finally:
    # 无论是否有异常,都会执行的代码
    print("无论是否有异常,都会执行的代码")

在这里插入图片描述
异常的传递性
当 函数/方法 执行 出现异常,会 将异常传递 给 函数/方法 的 调用一方
如果 传递到主程序,仍然 没有异常处理,程序才会被终止
利用这一特性,可以在主函数中增加 异常捕获
而在主函数中调用的其他函数,只要出现异常,都会传递到主函数的 异常捕获 中
如果满足 特定业务需求时,希望 抛出异常,可以:

  • 创建 一个 Exception 的 对象
  • 使用 raise 关键字 抛出 异常对象
    案例:密码输入异常捕获
def input_password():
	pwd = input('请输入密码:')
	if len(pwd) < 8:
		# 若密码长度不足8位,则抛出异常
		ex = Exception('密码长度不够')
		raise ex
	return pwd		
pwd = input_password()
print(pwd)

在这里插入图片描述

def input_password():
	pwd = input('请输入密码:')
	if len(pwd) < 8:
		# 若密码长度不足8位,则抛出异常
		ex = Exception('密码长度不够')
		raise ex
	return pwd		
try:
	pwd = input_password()
except Exception as result:
	print('发现错误:',result)
else:
	print(pwd)

在这里插入图片描述
模块
每一个以扩展名 py 结尾的 Python 源代码文件都是一个 模块
模块名 同样也是一个 标识符,需要符合标识符的命名规则
模块名 同样也是一个 标识符,需要符合标识符的命名规则
模块 就好比是 工具包,要想使用这个工具包中的工具,就需要先 导入 这个模块
模块的两种导入方式

  • import 模块名1, 模块名2
    import 模块名 是 一次性 把模块中 所有工具全部导入
    使用 as 可以指定模块的别名
    如:import numpy as np
    导入之后,需要通过模块名. 使用 模块提供的工具 —— 全局变量、函数、类
  • from…import 导入
    从某一个模块 中,导入 部分 工具
    导入之后 不需要 通过 模块名. 就可以直接使用 模块提供的工具 —— 全局变量、函数、类

注意
如果 两个模块,存在 同名的函数,那么 后导入模块的函数,会覆盖掉先导入的函数

Python 的解释器在 导入模块 时,会:

  • 搜索 当前目录 指定模块名的文件,如果有就直接导入
  • 如果没有,再搜索 系统目录

Python 中每一个模块都有一个内置属性 _file_ 可以 查看模块 的 完整路径
_name_ 属性
Python使用缩进对齐组织代码的执行,所有没有缩进的代码,都会在载入时自动执行。每个文件(模块)都可以任意写一些没有缩进的代码,并在载入时自动执行。为了区分 主执行代码和被调用文件,Python引入了: __name__变量
1)当文件是被调用时,__name__的值为模块名;
2)当文件被执行时,__name__的值为 _main_

基于此特性,为测试驱动开发提供了很好的支持,我们可以在每个模块中写上测试代码,这些测试代码仅当模块被Python直接执行时才会运行。
包(Package)
包 是一个 包含多个模块 的 特殊目录
目录下有一个 特殊的文件 _init_.py
包名的 命名方式 和变量名一致,小写字母 + _

文件操作
1打开文件
2读、写文件
·读 将文件内容读入内存
·写 将内存内容写入文件
3关闭文件
open 打开文件,并且返回文件操作对象
read 将文件内容读取到内存
write 将指定内容写入文件
close 关闭文件
open 函数负责打开文件,并且返回文件对象
read/write/close 三个方法都需要通过 文件对象 来调用

文件指针
·文件指针 标记 从哪个位置开始读取数据
·第一次打开 文件时,通常 文件指针会指向文件的开始位置
·当执行了 read 方法后,文件指针 会移动到 读取内容的末尾
默认情况下会移动到 文件末尾
打开文件的方式
open 函数默认以 只读方式 打开文件,并且返回文件对象

# 语法如下:
f = open("文件名", "访问方式")
f.read()/write('写入内容')
f.close()

访问方式参数
r 以只读方式打开文件。文件的指针将会放在文件的开头,这是默认模式。如果文件不存在,抛出异常
w 以只写方式打开文件。如果文件存在会被覆盖。如果文件不存在,创建新文件
a 以追加方式打开文件。如果该文件已存在,文件指针将会放在文件的结尾。如果文件不存在,创建新文件进行写入
r+ 以读写方式打开文件。文件的指针将会放在文件的开头。如果文件不存在,抛出异常
w+ 以读写方式打开文件。如果文件存在会被覆盖。如果文件不存在,创建新文件
a+ 以读写方式打开文件。如果该文件已存在,文件指针将会放在文件的结尾。如果文件不存在,创建新文件进行写入
按行读取文件内容
read 方法
默认会把文件的 所有内容 一次性读取到内存
·如果文件太大,对内存的占用会非常严重
readline 方法
·readline 方法可以一次读取一行内容
·方法执行后,会把 文件指针 移动到下一行,准备再次读取

# 按行读取大文件
f = open(file_path)
while True:
	# 按行读取
	text = f.readline()
	# 判断是否读取到内容
	if not text:
		break
	# 输出读取都的内容
	print(text,end='')
f.close()	

还有一种读取方式是采用上下文管理器的with open()

with open(file_path, "访问方式") as f:
f.read()/write()

with open 和open区别

os 模块
在 终端中可以通过os模块进行常规的 文件 / 目录 管理操作

rename 重命名文件 os.rename(源文件名, 目标文件名)
remove 删除文件 os.remove(文件名)
listdir 目录列表 os.listdir(目录名)
mkdir 创建目录 os.mkdir(目录名)
rmdir 删除目录 os.rmdir(目录名)
getcwd 获取当前目录 os.getcwd()
chdir 修改工作目录 os.chdir(目标目录)
path.isdir 判断是否是文件 os.path.isdir(文件路径)
文本文件的编码格式
Python 2.x 默认使用 ASCII 编码格式
Python 3.x 默认使用 UTF-8 编码格式
ASCII 编码
计算机中只有 256 个 ASCII 字符
一个 ASCII 在内存中占用 1 个字节 的空间
8 个 0/1 的排列组合方式一共有 256 种,也就是 2 ** 8
在这里插入图片描述
UTF-8 编码格式
计算机中使用 1~6 个字节 来表示一个 UTF-8 字符,涵盖了 地球上几乎所有地区的文字
大多数汉字会使用 3 个字节 表示
UTF-8 是 UNICODE 编码的一种编码格式
在 Python 2.x 文件的 第一行 增加以下代码,解释器会以 utf-8 编码来处理 python 文件

  • #*-* coding:utf8 *-*
    在这里插入图片描述
    在 Python 2.x 中,即使指定了文件使用 UTF-8 的编码格式,但是在遍历字符串时,仍然会 以字节为单位遍历 字符串
    要能够 正确的遍历字符串,在定义字符串时,需要 在字符串的引号前,增加一个小写字母 u,告诉解释器这是一个 unicode 字符串(使用 UTF-8 编码格式的字符串)
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值