Python 进阶 - 面向对象
Python 面向对象
面向过程
- 把完成某个需求的所有步骤,从头到尾逐步实现
- 根据开发需求,将某些功能独立的代码封装成一个又一个函数
- 最后完成的代码,就是顺序地调用不同的函数
面向过程特点:
- 注重步骤过程,不注重职责份工
- 如果需求复杂,代码很复杂
- 开发复杂项目,没有固定套路,开发难度大
面向对象特点
- 注重对象和职责,不同的对象承担不同的职责
- 更加适合对复杂需求变化,时专门应对复杂项目开发,提供的固定套路
- 需要在面向过程基础上,再学习一些面向对象语法
类,对象
- 类是图纸,是模板
- 对象是根据图纸制作的飞机
设计类满足的三要素:
- 类名
- 属性
- 方法
基础语法
目标
dir内置函数- 定义简单的类(只包含方法)
- 方法中的 self 参数
- 初始化方法
- 内置方法和属性
01 dir 内置函数
- 提示:
__方法名__格式的方法是 Python 提供的 内置方法/属性,.
| 方法名 | 类型 | 作用 |
|---|---|---|
__new__ |
方法 | 创建对象时,会被自动调用 |
__init__ |
方法 | 对象被初始化时,会被调用 |
__del__ |
方法 | 对象被从内存中销毁前,会被调用 |
__str__ |
方法 | 返回对象的描述信息, print 函数输出使用 |
例子
# coding=utf-8
class Demo:
# 如果存在 __new__ 则接下来的函数都不会进行.
def __init__(self,name):
self.name = name
print('init---%s :'% name)
def __del__(self):
print('del---')
def __str__(self):
return '123'
hehe = Demo('guagua')
print(hehe)
del hehe
"""
打印结果:
init---guagua :
123
del---
"""
1) __str__ 方法
- 在 Python 中,使用 print 输出 对象变量,默认情况下,会输出这个变量 引用的对象 是 由哪一个类创建的对象,以及在内存中的地址(十六进制表示)
- 如果在开发中,希望使用 print 输出 对象变量 时,能够打印 自定义的内容,就可以利用
__str__这个内置方法了 __str__必须返回一个字符串
私有属性和私有方法
应用场景及定义方式
- 私有属性就是对象不希望公开的属性
- 私有方法就是对象不希望公开的方法
定义方式:
- 在定义属性或方法时,在 属性名或者方法名前 增加 两个下划线,定义的就是 私有 属性或者方法
class Women:
def __init__(self,name):
self.name = name
self.__age = 18 #私有属性
#私有方法
def __get_age():
pass
def secret(self):
print('年龄是%s' % self.__age)
xiaofang = Women('小芳')
print(xiaofang.age)# 私有属性不可外部直接调用,报错
xiaofang.__get_age()# 私有方法不可外部直接调用,报错
xiaofang.secret()#
伪私有属性和私有方法
Python 中,并没有 真正意义 的 私有,以上讲的私有其实都是伪私有
- 在给属性、方法命名时,实际时对名称左了一些特殊处理,使得,外界无法访问到
- 处理方式:在名称前面加上
_类名 => _类名__名称 - 处理之后使得能够直接调用私有方法
提示:在日常开发中,不要使用这种方式去访问 定义好的 私有的属性和方法
经过改造的上面的例子:
print(xiaofang._Women__age)# 私有被直接调用
xiaofang.Women.__get_age()# 私有被直接调用
引用概念的强调
- Python 使用类创建对象之后,tom 变量中记录的是 对象在内存中的地址。
- 也就是 tom 变量引用了 新建的对象
- 使用 print 输出对象变量,默认情况下,是能够输出这个变量 引用的对象 是 由哪一个类创建的对象,以及在内存中的地址(十六进制表示)
提示:在计算机中,通常使用 十六进制 表示 内存地址
%d可以以 10进制 输出数字%x可以以 16进制 输出数字
<__main__.Cat object at 0xi9asdiaxxxxx>
tom = Cat()
addr = id(tom)
print("%x" % addr)
print("%d" % addr)
继承
- 单继承
- 多继承
- 面向对象三大特性
- 封装 根据 职责 将 属性 和 方法 封装 到一个抽象的 类 中
- 继承 实现代码的重用,相同的代码不需要重复的编写
- 多态 不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活性
单继承
继承的概念、语法和特点
继承的概念:子类 拥有 父类 的所有 方法 和 属性
class 类名(父类名):
...
- 子类 是 父类的 继承类
- 子类 是 父类的 派生类
- 父类 是 子类的 基类
- 子类 从 父类 派生
方法的重写
- 当父类 的 方法实现不能满足子类需求时,可以对方法 进行重写 override
多继承
- 子类 可以拥有 多个父类,并且具有 所有父类 的属性 和方法
class 子类名(父类名1,父类名2...)
...
注意:
开发时候,应尽量避免不同父类 中存在 同名的方法,容易产生混淆。如果父类之间存在同名,尽量避免使用多继承。
Python 中的 MRO -- 发给发搜索顺序
- Python 中针对 类提供了一个内置属性
__mro__可以查看 方法 搜索顺序 - MRO 是 method resolution order ,主要用于 在多继承时判断 方法、属性的调用 路径
print(C.__mro__)
输出结果:
(<class '__main__.C'>,<class '__main__.A'>,<class '__main__.B'>,<class 'object'>)
- 在搜索方法时,是按照
__mro__的输出结果从左至右的顺序查找的 - 如果在当前类中 找到方法,就直接执行,不再搜索
- 如果没有找到,就查找下一个类中是否有对应的方法,如果找到,就直接执行,不再搜索
- 如故宫找到最后一个类,还没有找到方法,程序报错
新式类与旧式
object 是 Python 为所有对象提供的基类,提供有一些内置的属性和方法,可以使用
dir函数查看
多态
- 不同的 子类对象调用相同的父类方法,产生不同的执行结果
- 增加代码灵活度
- 继承 和 重写父类方法为前提
- 时调用方法的技巧,不会影响到类的内部设计
类--特殊对象
- 程序运行时,类 同样会被加载到内存
- 在 Python 中,类 是一个图书的对象 -- 类对象
- 在程序运行时,类对象(模板)在内存中 只有一份,一个类可以创建多个对象示例
- 模板 创建 实例对象,类对象只有一个,实例对象可以创建多个
类属性和实例属性
- 类属性就是给 类对象中 定义的熟悉感
- 通常记录 与这个类相关的特征
- 类属性 不会用于记录 具体对象的特征
属性的获取机制
- 属性的获取存在一个向上查找机制
访问类属性有两种
- 类名.类属性
- 对象.类属性(不推荐)
class Tool(object):
count = 0
def __init__(self,name):
self.name = name
Tool.count += 1 #类属性
tool1 = Tool("a")
tool2 = Tool("b")
tool3 = Tool("c")
tool3.count == 99 #对象属性 赋值
print(tool3.count)# 打印99
print(Tool.count) # 打印3 tool1,tool2,tool3,
# 因为类声明,Python 解释器会为其在内存开辟空间,它也是个对象。--类对象。
类方法 和 静态方法
- 针对 类对象 定义的方法
- 类方法需要用 修饰器
@classmethod来标识,告诉解释器这是一个类方法 - 类方法的第一个参数 应该是
cls- 由 哪个类 调用的方法,方法内的
cls就是 哪一个类的引用 - 这个参数和 实例方法 的第一个参数是
self类似 - 使用其他名称也可以,不过习惯使用
cls
- 由 哪个类 调用的方法,方法内的
- 通过
类名调用 类方法,调用方法时,不需要传递cls参数 - 在方法内部
- 可以通过
cls,访问类的属性 - 也可以通过
cls,调用其他的类方法
- 可以通过
class Tool(object):
count = 0
@classmethod
def show_tool_count(cls):
print(cls.count)
def __init__(self,name):
self.name = name
Tool.count += 1 #类属性
tool1 = Tool("a")
print(Tool.show_tool_count) # 打印 1
# 因为类声明,Python 解释器会为其在内存开辟空间,它也是个对象。--类对象。
静态方法
- 在开发时,如果需要在 类 中封装一个方法,这个方法:
- 既不需要访问实例属性,调用实例方法
- 也不需要访问类属性,类方法
@staticmethod
def 静态方法名():
pass
- 静态方法 需要使用装饰器
@staticmethod来标识,告诉解释器这是一个静态方法 - 通过类名.直接调用静态方法,不需要创建 实例对象
案例:
- 设计一个 Game 类
- 属性
- 定义一个类属性
top_score记录游戏的 历史最高分 - 定义一个实例属性
player_name记录 当前游戏的玩家姓名
- 定义一个类属性
- 方法:
- 静态方法
show_help显示游戏帮助信息 - 类方法
show_top_score显示历史最高分- 类方法内部调用类属性
cls.top_score
- 类方法内部调用类属性
- 实例方法
start_game开始当前玩家的游戏self.player_name
__init__类设置名称:self.player_name = player_name
- 静态方法
小结:
- 实例方法 内部需要访问 实例属性
- 实例方法 内部可以使用 类名.访问类属性
- 类方法 内部只需要访问类属性
- 静态方法 内部,不需要访问,实例属性和类属性
单例
单例设计模式
- 目的:为了让 类 创建的对象,在系统中 只有 唯一的一个实例
- 每一次执行类名() 返回的对象,内存地址是相同的
__new__ 方法(内部方法)
- 使用 类名() 创建对象时,Python 的解释器 首先 会调用
__new__方法为对象 分配空间 __new__是一个 由 object 基类提供的 内置的静态方法,主要作用有两个:- 在内存中为对象 分配空间
- 返回 对象的引用
重写
__new__方法的代码非常固定
- 重写
__new__一定要return super().__new__(cls) - 否则 Python 的解释器 得不到 分配了空间的对象引用,就不会调用对象的初始化方法
- 注意:
__new__是一个静态方法,在调用时需要主动传递 cls 参数
重写例子:
class MusicPlayer(object):
def __new__(cls,*args,**kwargs):
# 1.创建对象时,new 方法会被自动调用
# 2.为对象分配空间
instance = super().__new__(cls)
# 3.返回对象的引用
return instance
def __init(self):
print('初始化播放器')
player = MusicPlayer()
print(player)
Python 中的单例
class MusicPlayer(object):
#记录第一个被创建对象的引用
instance = None
#记录是否执行过初始化动作
init_flag = False
def __new__(cls,*args,**kwargs):
if cls.instance is None:
cls.instance = super().__new__(cls)
return cls.instance
def __init__(self):
# 1. 判断是否执行过初始化动作
if MusicPlayer.init_flag:
return
# 2. 如果没有执行过开始初始化
print("初始化播放器")
# 3.修改类属性的标记
MusicPlayer.init_flag = True
player1 = MusicPlayer()
player2 = MusicPlayer()
异常
- 异常的概念
- 捕获异常
- 异常的传递
- 自定义异常
01 异常的概念
- 通过异常捕获 可以针对突发事件做集中的处理,从而保证程序的稳定性和健壮性
02 捕获异常
基本格式:
try:
尝试执行代码
except:
出现错误处理
错误类型捕获:
try:
pass
except 错误类型1:
pass
except (错误类型2,错误类型3):
pass
except Exception as result:
print(位置错误)
- 当Python 解释器 抛出异常时,最后一行错误信息的第一个单词,就是错误类型
- 如果希望程序 无论出现任何错误,都不会因为 Python 解释器 抛出异常而被终止,可以再增加一个except (即最后一个Exception)
异常捕获完整语法
try:
# 尝试执行的代码
except 错1:
pass
except 错2:
pass
except (错3,错4):
pass
except Exception as result:
print(result)
else:
# 没有异常才会执行的代码
pass
finally:
print("无论是否有异常都会执行")
03 异常的传递
- 异常的传递 -- 当 函数/方法 执行 出现异常,会 将异常传递 给 函数/方法 的调用以方
- 如果 传递到主程序,仍然没有异常处理,程序才会被终止
提示:
- 在开发中,可以在主函数中增加异常捕获
- 而在主函数中调用的其他函数,只要出现异常都会传递到主函数进行异常捕获
04 抛出 raise 异常
- 开发时,如果满足 特定业务需求时,希望抛出异常,可以:
- 创建一个 Exception 对象
- 使用 raise 关键字抛出
- 但不进行捕获,由其他函数捕获异常
def input_password():
pwd = input("请输入密码:")
if len(pwd)>=8:
returen pwd
raise Exception("密码长度不够")#主动抛出异常
try:
print(inptu_password())
except Exception as result:
print(result)
模块
模块时 Python 程序架构的一个核心概念
- 每一个扩展名 py 结尾的 Python 源码文件 都是一个模块
- 模块名 同样时一个标识符,需要符合命名规则
- 在模块中定义的 全局变量、函数、类 都是提供给外界直接使用的工具
- 模块就好比是工具包。
01 导入模块的方式
1) import 导入
import 模块1,模块2 #不推荐使用,需要单独行导入
# 推荐
import 模块1
import 模块2
模块别名:需要符合大驼峰命名
import 模块名1 as 模块别名
2) 局部导入
- 如果希望从某一个模块中,导入部分工具,就可以使用
from ... import的方式 - 导入后 不需要通过 模块名
- 可以直接使用 模块提供的工具--全局变量、函数、类
注意:
- 如果两个模块,存在同名函数,那么后导入的函数会覆盖先导入的。
- 新增别名,可避免
导入全部工具模块:
from 模块名1 import *
3) 模块的搜索顺序
- 当前目录搜索指定模块,如果有就直接导入
- 如果没有,再搜索系统目录
Python 中每一个模块都有一个内置属性 __file__ 可以查看模块的完整路径
4) 原则
__name__
- 如果直接执行模块
__name__(即不是外部使用该模块),永远是执行__main__ - 是一个 Python 的内置熟属性,记录着一个字符串
- 如果 是被其他文件导入的,
__name__就是模块名
所以:
if __name__ = "__main__":
main() # 进行测试
包 (Package)
- 包即目录,是一个包含多个模块的特殊目录
- 目录下有一个特殊文件
__init__.py- 在
__init__.py文件中 设置from . import .... - 导入模块可直接导入模块
- 在
发布模块 (重要)
01 制作发布压缩包步骤
以 hm_message 为例:
1) 创建setup.py
from distutils.core import setup
setup(name="hm_message",# 包名
version="1.0", #版本
description="描述信息",
long_description="完整的描述信息",
author="作者",
url="主页",
py_modules=["hm_message.send_message",
"hm_message.receive_message"])
)
可以参阅官方网站:
https://docs.python.org/2/distutils/apiref.html
2) 构建模块
python3 setup.py build
3) 生成发布压缩包
python3 setup.py sdist
生成 hm_message-1.0.tar.gz
02 安装模块
tar -zxvf xxxxxx.tar.gz
sudo python3 setup.py install
03 卸载模块
直接到安装目录把模块目录删除即可
04 pip 安装 pygame 游戏开发模块
sudo apt install ipython3 # Linux 下安装 iPython
sudo pip install pygame
eval 函数
eval() 函数十分强大 -- 将字符串 当成 有效的表达式 来求值 并 返回计算结果
# 基本的数学计算
eval("1 + 1") # 结果: 2
# 字符串重复
eval("*" * 10)
输出 :**********
# 字符串转换成列表
type(eval("[1,2,3,4,5]"))
输出: list
# 将字符串转换成字典
type(eval("{'name':'xiaoming','age':18}"))
输出 dict
安全 - 不要滥用 eval (重要)
开发时千万不要使用
eval直接转换input的结果
__import__('os').system('ls') # 会有安全问题,可以看到你的东西
等价于:
import os
os.system("终端命令")
直接操作文件有很大的安全问题
Python 进阶 - 面向对象的更多相关文章
- Python进阶---面向对象的程序设计思想
Python的面向对象 一.面向过程与面向对象的对比 面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. 优 ...
- Python进阶(面向对象编程基础)(三)
6.类属性和实例属性名字冲突怎么办 修改类属性会导致所有实例访问到的类属性全部都受影响,但是,如果在实例变量上修改类属性会发生什么问题呢? class Person(object): address ...
- Python进阶(面向对象编程基础)(二)
1.初始化实例属性 #!/usr/bin/env python # -*- coding:utf-8 -*- __author__ = 'ziv·chan' #定义Person类的__init__方法 ...
- Python进阶(面向对象编程基础)(一)
鉴于昨天被类和函数折腾得晕头转向,今特把类的知识翻出来温习. 1.定义类并创建实力对象 #!/usr/bin/env python # -*- coding:utf-8 -*- __author__ ...
- Python进阶---面向对象第三弹(进阶篇)
Python对象中一些方法 一.__str__ class Teacher: def __init__(self,name,age): self.name=name self.age=age self ...
- Python进阶---面向对象第二弹
python类的继承原理 一.类的继承顺序 class A(object): def test(self): print('from A') passclass B(A): # def test(se ...
- Python进阶-面向对象
类的成员 类的成员可以分为三类:字段.方法.属性 一:字段: 普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同 普通字段属于对象 静态字段属于类 字段的定义和使用 ...
- Python进阶(面向对象编程基础)(四)
1.方法也是属性 我们在 class 中定义的实例方法其实也是属性,它实际上是一个函数对象: class Person(object): def __init__(self, name, score) ...
- python基础——面向对象进阶下
python基础--面向对象进阶下 1 __setitem__,__getitem,__delitem__ 把对象操作属性模拟成字典的格式 想对比__getattr__(), __setattr__( ...
随机推荐
- POJ 1039:Pipe 计算几何
Pipe Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 9773 Accepted: 2984 Description ...
- Android群英传知识点回顾——第十章:Android性能优化
10.1 布局优化 10.1.1 Android UI渲染机制 10.1.2 避免Overdraw 10.1.3 优化布局层级 10.1.4 避免嵌套过多无用布局 10.1.5 Hierarchy V ...
- pandas dataframe取差集:删掉已存在的数据,保留未插入的数据
适用场景: 插入数据到mysql中,中途中断,导致部分数据未插入成功.避免下次插入时插入了重复的数据. 思路: 1.读取已插入的数据, 2.读取全部数据(包含已插入和未插入的), 3.将已插入的数据添 ...
- 题解 P1220 【关路灯】
区间DP, 考虑设\(dp[i][j][t]\)为已经关掉了\([i,j]\)的电灯, 人在t端点处时的最小代价 可以推出方程: \[ dp[i+1][j][0]+(p[n]-p[j]+p[i])*( ...
- LeetCode随想------Single Number-----关于异或的性质
异或满足交换律,结合律 任何数X^X=0,X^0=X 自反性 A XOR B XOR B = A xor 0 = A 设有A,B两个变量,存储的值分别为a,b,则以下三行表达式将互换他们的值 表达 ...
- 应用架构的演进--MVC,RPC,SOA,微服务架构
MVC架构:垂直应用架构 当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率. 当业务规模很小时,将所有功能都部署在同一个进程中,通过双机或者前置负载均衡 ...
- Spring框架-IOC和AOP
IOC:它并不是一种技术实现,而是一种设计思想.在任何一个有实际开发意义的程序项目中,我们会使用很多类来描述它们特有的功能,并且通过类与类之间的相互协作来完成特定的业务逻辑.这个时候,每个类都需要负责 ...
- django_filter的values / values_list
from django.db import models class Blog(models.Model): name = models.CharField(max_length=100) tagli ...
- Servlet过滤器基础及使用场景
Servlet过滤器详解 一.过滤器基础 1.Servlet过滤器是Servlet的一种特殊用法,主要用来完成一些通用的操作.比如编码的过滤,判断用户的登陆状态等等.Servlet过滤器的适用场合: ...
- winform集成cefSharp,与页面进行交互
/// <summary> /// 为了使网页能够与winForm交互 将 com 的可访问性设置为 true /// </summary> [System.Runtime.I ...