面向对象1
面向过程和面向对象概念
- 面向过程:根据业务逻辑从上到下写代码(每一步都自己去实现)
- 面向对象:将数据与函数绑定到一起,进行封装,这样能够更快速的开发程序,减少了重复代码的重写过程(不用具体到每一步,会调用就行。面向对象是基于面向过程的)
面向对象有三种特性:1.封装 2.继承 3.多态
C语言和C++语言都是编译过后才能生成(.exe)可执行程序后才可运行。
python语言是直接运行,直到运行到出错地方才停止
一、 类和对象
A、 类
类的概念
类是抽象的,在使用的时候通常会找到这个类的一个具体的存在,使用这个具体的存在。一个类可以找到多个对象
B、 对象
对象的概念
某一个具体事物的存在,在现实世界中可以是看得见摸得着的。
C、 类和对象之间的关系
类就是创建对象的模板
二、 __init__() 方法
方法类似于C++中的成员函数
- __init__() 方法,在创建一个对象时默认被调用,不需要手动调用,与C++中的构造函数类似
- __init__(self) 中,默认有1个参数名字为self,如果在创建对象时传递了2个实参,那么 __init__(self) 中除了self作为第一个形参外还需要2个形参,例如 __init__(self, x, y)
- __init__(self) 中的self参数,不需要开发者传递,python解释器会自动把当前的对象引用传递进去
三、 str() 方法
- 在 python 中方法名如果是 (__xxx__()) ,那么就有特殊的功能,因此叫做"魔法"方法
- 当使用print输出对象的时候,只要自己定义了 (__str__(self)) 方法,那么就会打印从在这个方法中 return 的数据。
四、 self
- 可以把 self 当做C++中类里面的this指针一样理解,就是对象本身的意思
- 某个对象调用其方法是,python 解释器会把这个对象作为第一个参数传递给 self ,所以开发者只需要传递后面的参数即可。
五、 隐藏数据
修改对象属性(数据)有两种办法
A、 直接通过对象名修改
B、 通过方法间接修改
应用题:老王开枪
class Human:
def __init__(self, name):
self.name = name
self.blood = 100
self.gun = None
def __str__(self):
return self.name + "剩余血量为:" + str(self.blood)
def install_ball(self, clip, ball):
clip.reserve_ball(ball)
def install_clip(self, gun, clip):
gun.link_clip(clip)
def with_gun(self, gun):
self.gun = gun
def shoot(self, rob):
self.gun.shoot(rob)
def injured(self, hurt):
self.blood -= hurt
class Ball:
def __init__(self, hurt):
self.hurt_l = hurt
def hurt(self, rob):
rob.injured(self.hurt_l)
class Clip:
def __init__(self, capacity):
self.capacity = capacity
self.capacity_list = []
def __str__(self):
return "弹夹里面的数量为:" + str(len(self.capacity_list)) + "/" + str(self.capacity)
def reserve_ball(self, ball):
if len(self.capacity_list) < self.capacity:
self.capacity_list.append(ball)
def balls(self):
# 判断当前弹夹中是否还有子弹
if len(self.capacity_list) > 0:
ball = self.capacity_list[-1]
self.capacity_list.pop()
return ball
else:
return None
class Gun:
def __init__(self):
self.clip = None
def __str__(self):
if self.clip:
return "枪里面装有弹夹"
else:
return "枪里面没有弹夹"
def link_clip(self, clip):
if not self.clip:
self.clip = clip
def shoot(self, rob):
ball = self.clip.balls()
if ball:
ball.hurt(rob)
else:
print("没有子弹了...")
# 创建一个人对象
laowang = Human("laowang")
print(laowang)
# 创建一个弹夹
clip = Clip(20)
print(clip)
# 装子弹
i=0
while i<5:
ball = Ball(5)
laowang.install_ball(clip, ball)
i += 1
# 打印子弹个数
print(clip)
# 创建一个枪对象
gun = Gun()
print(gun)
# 把弹夹装进枪里面
laowang.install_clip(gun, clip)
print(gun)
# 创建一个敌人
rob = Human("rob")
print(rob)
laowang.with_gun(gun)
laowang.shoot(rob)
print(rob)
print(clip)
面向对象2
一、 保护对象的属性
如果有一个对象,当需要对其进行修改属性时,有两种方法
- 对象名.属性名 = 数据 ----->直接修改
- 对象名.方法名() ----->间接修改
为了更好的保护属性安全,即不能随意修改,一般处理方式为
- 将属性定义为私有属性,然后添加一个可以调用的方法提供调用
- python 中没有像C++中public和private这些关键字来区别公有属性和私有属性
- 它是以属性命名方式来区分,如果在属性名前面加了2个下划线,则表明该属性是私有属性,否则为公有属性(方法也是一样,方法名前面加2个下划线的话表示该方法是私有的)
注意:如果直接使用( print(laowang.__age)会报错 ),可直接修改虽然不会报错,但是这个值不会被真正的写入
二、 __del__() 方法
- 创建对象后,python解释器默认调用 __init__() 方法; 当删除一个对象时,python解释器也会默认调用一个方法,这个方法为 __del__() 方法
注意:当使用 del 删除变量指向的对象时,如果对象的引用计数不为1,那么此时只会让这个引用计数减1,只有当这个引用计数器变为1时再次调用del,此时才会把对象进行删除
三、 继承
- 子类在继承的时候,在定义时,小括号中为父类的名字
注意:私有的属性、方法,不会被子类继承,也不能被访问
四、 重写父类方法与调用父类方法
所谓重写,就是子类中有一个和父类相同名字的方法,在子类中方法会覆盖掉父类中同名的方法
五、 多态
概念:定义时的类型和运行时的类型不一样,此时就成为了多态(同一条执行语句,不同的执行结果)
注意1: 与 C 和 C++ 这些强类型语言不同的是,而python这类弱类型语言不用指定传入的参数类型,只要各类中含有被调用的方法,就能被执行
注意2: 多态必须得重写
补充:
若类中有一个方法为 __test() 的私有方法, 那么我们可以如何访问呢?
六、 类属性和实例属性
- 实例属性: 也叫对象属性,归对象管理
- 类属性: 它被类和对象所共有,和 C++ 中的静态成员变量类似。对于共有的类属性可以通过类或者对象直接访问
注意1:当实例属性和类属性名相同时,用对象访问的属性将是实例属性(有实例属性就以实例属性为主,没有就访问类属性)
问:既然能够通过对象名获取类属性的值,那能不能通过对象名向类属性修改呢?
注意2:类属性的值不能通过对象名进行修改,如果修改本质是创建了一个和类属性同名的实例属性
七、 类方法和静态方法
概念:1.类方法需要用修饰器(@classmethod) 来标识其为类方法,第一个参数必须是类,一般以cls作为第一个参数。2.静态方法需要通过修饰器(@staticmethod)来进行修饰,静态方法不需要定义参数
- 1.实例方法:用于修改实例属性
- 2.类方法:用于修改类属性
- 3.静态方法:用于打印菜单等工作
面向对象3
一、 工厂模式
二、 __new__ 方法
注意:在 (__init__)初始化之前还有一个 (__new__) 对象的创建,并且必须要有返回值
三、 单例模式
就是一个类只能创建出一个对象
四、 异常
概念:当 python 检测到一个错误时,解释器就无法继续执行了,反而出现了一些错误的提示,这就是异常(意料之中的错误)。
A、 捕获异常
注意:当 try 内部出现异常后,后面的语句将不会被执行
B、 捕获多个异常
注意:当捕获多个异常时,可以把要捕获的异常的名字放在 except 后,并使用元组的方式进行存储
C、获取异常的信息描述
result 存储异常的基本信息
D、 捕获所有异常
1 捕获所有异常
2 捕获所有异常并存储异常信息
E、 else
注意:如果未出现异常才执行else的语句,如果try里面出现的异常没有被捕获则执行系统默认的异常
F、 finally
概念:在程序中,如果一个代码必须要执行,即无论是否产生异常都要执行,那么此时就需要使用finally。
G、异常的传递
H、 抛出自定义的异常
概念:可以用 raise 语句来引发一个异常。异常对象必须有一个名字,并且是 Exception 类的子类。
I、 异常处理中抛出异常
五、 模块
概念:python 中的模块就是一个py文件中整体的代码,与C语言的头文件类似
A、 模块的制作
概念:在 python 中每个python文件都可以作为一个模块,模块的名字就是文件名字。
自己定义的test模块
在main中调用test模块中的函数
运行结果:
注意:当使用 (import test) 的时候,会执行 test.py 中的所有函数。等价于直接执行 (python3 test.py)
解决方案:使用 (__name__) 变量。若直接执行 (python3 test.py) 时,(__name__)变量值为(__main__), 若在 main.py 文件中含有 (import test) 时,(__name__)变量值为(test)
自己定义的test模块
main.py中的代码不变
运行结果:
B、 import
在 python 中用关键字 import 来引入某个模块。比如要要引用模块 math ,就可以在文件最开始的地方用 import math 来引入
引入模块:import module1, module2 ...
调用函数:module1.函数名
C、 form...import
从模块中导入一个指定的部分到当前的命名空间中,不仅可以引入函数,还可以引入一些全局变量、类等。
格式:from fbi import fbifuction 导入fbi模块的fbifuction的函数到当前命名空间
注意:通过这种方式引入的时候,如果两个模块中的含有相同名称函数的时候,后面一次引用会覆盖前一次引入。
D、 from...import *
把一个模块的所有内容全部导入到当前的命名空间
格式:from module import *
E、 定位模块
- 当导入一个模块,python解释器对模块位置的搜索顺序是:
- 当前目录
- python搜索在 shell 变量PATH下的每个目录
可以使用:echo $PATH
- python 会查看默认路径, /usr/local/lib/python/
在交互模式下使用os模块
- 模块搜索路径存储在 sys 模块的 sys.path 变量中。变量包含当前目录。
在交互模式下使用sys模块的path
例:当被调用的模块文件和执行文件不在同一个目录下,如何调用自定义模块
/work/practice/python/008_module/TEST目录下的 test.py
/work/practice/python/008_module目录下的 001_main.py
执行结果:
F、 __pycache__
__pycache__ 里面存储的是缓存文件,即为了效率会把编译好的内容存放在 __pycache__ 目录下的 (.pyc)文件中。根据时间戳来决定被 import 后的文件是否被编译
注意:只要 import 就有编译缓存
G、 __all__
注意:__all__只对 * 有效。 当没有 __all__ 的时候 使用 (from module import *) 会把模块中的函数都导入;当有 __all__时,只导入all里边的函数。----->用列表的方式赋值
test.py 中的内容:
main.py 中的内容:
执行结果:
六、 Python 中的包
包的概念:将有联系的模块组织在一起,即放在同一个文件夹下,并且在这个文件夹下创建一个名字为 __init__.py 文件,那么这个文件夹就称为包。
A、 使用(import 文件.模块) 的方式导入
B、 使用(from 文件夹 import 模块) 的方式导入
解决方法:在 msg 文件夹下创建 __init__.py 文件,并在文件中写入如下内容
__init__ 文件内容:
再次执行:
注意: __init__.py 的作用:控制导入的模块
七、 给程序传参数
例:通过传入的参数来执行不同的函数
八、 列表推导式
所谓的列表推导式,就是轻量级循环创建列表。
A、 基本的方法
B、 再循环过程中使用if
C、 2个for循环
本质:双重for循环,用元组保存
D、 3个for循环
本质:三重for循环
九、 set(集合)、list(列表)、tuple(元组)
注意:set(集合) 中没有重复
set、list、tuple之间的相互转换
作用:使用 set ,可以快速的完成对列表或者元组中的元素去重复的功能。
<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">