1. 面向对象认识
1.1 面向过程
核心:怎么做
- 把需要完成的业务逻辑,所有步骤从头到尾逐步实现
- 将某些功能独立的代码封装成函数
- 最后,就是顺序调用不同的函数
注重步骤与过程,不注重职责分工。
1.2 面向对象
核心:谁来做
- 在做业务之前,首先确定职责 - 要做的事情
- 根据职责创建不同的对象,在对象内部封装不同的对象方法
- 最后,顺序地让不同的对象调用不同的方法
注重对象和职责,不同的对象承担不同的职责。
2. 类和对象
2.1 类
类是对一群具有相同特征或者行为的事物的一个统称。
相当于是制造汽车的图纸。
类的设计
- 类名:一类事物的统称,采用大驼峰命名法(单词首字母大写,单词之间没有下划线)
- 属性:这类事物具有什么样的特征
- 方法:这类事物具有什么样的行为
2.2 对象
对象是由抽象的类创建出来的一个具体的存在。
相当于是根据图纸制造出来的真的汽车。
2.3 类与对象的关系
- 先有类,后有对象
- 类只有一个,对象可以创建多个
- 类中定义了什么属性和方法,对象中就有什么属性和方法
3. 面向对象基础语法
3.1 内置函数
__方法名__ 格式的方法是python提供的内置属性/方法,如:
3.2 定义类
class 类名:
def 方法1(self, 参数列表):
pass
def 方法2(self, 参数列表):
pass
创建一个猫对象
class Cat:
"""这是一个猫类"""
def eat(self):
print("小猫爱吃鱼")
def drink(self):
print("小猫在喝水")
- 在类的外部,通过 变量名. 访问对象的属性和方法
- 在类封装的方法中,通过 self. 访问对象的属性和方法
3.3 创建对象
对象变量 = 类名()
创建小猫对象
tom = Cat()
tom.drink()
tom.eat()
3.4 对象初始化
在创建对象的同时,设置对象的属性,相当于java的构造函数
class Cat:
def __init__(self, name):
print("初始化方法 %s" % name)
self.name = name
...
tom = Cat("Tom")
...
lazy_cat = Cat("大懒猫")
...
3.5 私有属性和私有方法
在有些业务中,对象的某些属性或方法,只希望在对象的内部使用,不希望在外部访问。即对象不希望公开的属性和方法。
定义方式:在定义属性或方法时,在属性名或者方法名前增加两个下划线。
示例:女生的年龄你不要问
class Women:
def __init__(self, name):
self.name = name
self.__age = 18
def __secret(self):
print("我的年龄是 %d" % self.__age)
xiaofang = Women("小芳")
# 私有属性,外部不能直接访问
# print(xiaofang.__age)
# 私有方法,外部不能直接调用
# xiaofang.__secret()
但是,在python中并没有真正意义上的匿名,你可以通过某些方式访问,如:
# 访问私有属性
print(xiaofang._Women__age)
# 访问私有方法
xiaofang._Women__secret()
3.6 类属性和类方法
- 每一个对象都有自己独立的内存空间,保存各自不同的属性
- 多个对象的方法,在内存中只有一份,在调用方法时,需要把对象的引用传递到方法内部
类属性
类属性就是给类对象中定义的属性,通常用来记录与这个类相关的特征,不会用于记录具体对象的特征。
示例
class Tool(object):
# 使用赋值语句,定义类属性,记录创建工具对象的总数
count = 0
def __init__(self, name):
self.name = name
# 针对类属性做一个计数+1
Tool.count += 1
# 创建工具对象
tool1 = Tool("斧头")
tool2 = Tool("榔头")
tool3 = Tool("铁锹")
# 知道使用 Tool 类到底创建了多少个对象?
print("现在创建了 %d 个工具" % Tool.count)
类方法
类方法就是针对类对象定义的方法,在类方法内部可以直接访问类属性或者调用其他的类方法。
语法:
@classmethod
def 类方法名(cls):
pass
- 类方法需要用修饰器 @classmethod 来标识
- 第一个参数是cls
- 在方法内部,可以通过cls.访问类的属性,通过cls.调用其他类方法
静态方法
如果既不需要访问实例属性或者调用实例方法,也不需要访问类属性或者调用类方法,这个时候就可以把这个方法封装成一个静态方法。
语法:
@staticmethod
def 静态方法名():
pass
- 静态方法用修饰器 @staticmethod来标识
- 通过类名.调用静态方法
示例
class Game(object):
# 游戏最高分,类属性
top_score = 0
@staticmethod
def show_help():
print("帮助信息:让僵尸走进房间")
@classmethod
def show_top_score(cls):
print("游戏最高分是 %d" % cls.top_score)
def __init__(self, player_name):
self.player_name = player_name
def start_game(self):
print("[%s] 开始游戏..." % self.player_name)
# 使用类名.修改历史最高分
Game.top_score = 999
# 1. 查看游戏帮助
Game.show_help()
# 2. 查看游戏最高分
Game.show_top_score()
# 3. 创建游戏对象,开始游戏
game = Game("小明")
game.start_game()
# 4. 游戏结束,查看游戏最高分
Game.show_top_score()
4 继承
4.1 继承的基本概念
实现代码的重用,相同的代码不需要重复编写。
子类拥有父类的所有方法和属性。
语法:
class 类名(父类名):
pass
4.2 方法的重写
子类继承自父类,可以直接享受父类中已经封装好的方法。
当父类的方法实现不能满足子类的需求时,可以对方法进行重写。
重写父类方法的两种情况:
- 覆盖父类的方法
- 对父类方法进行扩展
覆盖父类的方法:
如果在开发中,父类方法的实现和子类的方法实现,完全不同,可以采用覆盖的方式,在子类中重新编写父类的方法实现。在程序调用时,会直接调用之类中的重写方法。
对父类方法进行扩展:
在子类中重写父类的方法,在特定的位置上使用 super().父类方法 来调用父类方法的执行,相当于是父类原本的方法实现是子类方法其中的一部分。
4.3 多继承
子类可以拥有多个父类,并且具有所有父类的属性和方法。
语法:
class 子类名(父类名1, 父类名2...)
pass
4.4 基类
object是python为所有对象提供的基类,提供有一些内置的属性和方法。
在python3中,定义类时,如果没有指定父类,会默认使用object类作为该类的基类。
5. 多态
不同的子类对象调用相同的父类方法,产生不同的执行结果,增加代码的灵活度。
示例
class Dog(object):
def __init__(self, name):
self.name = name
def game(self):
print("%s 蹦蹦跳跳的玩耍..." % self.name)
class XiaoTianDog(Dog):
def game(self):
print("%s 飞到天上去玩耍..." % self.name)
class Person(object):
def __init__(self, name):
self.name = name
def game_with_dog(self, dog):
print("%s 和 %s 快乐的玩耍..." % (self.name, dog.name))
# 让狗玩耍
dog.game()
# 1. 创建一个狗对象
wangcai = XiaoTianDog("飞天旺财")
# 2. 创建一个小明对象
xiaoming = Person("小明")
# 3. 让小明调用和狗玩的方法
xiaoming.game_with_dog(wangcai)
person类只需要让狗对象调用game方法,不用关心具体是什么狗,在程序执行时,传入不同的狗对象实参,就会产生不同的执行效果。
6. 单例
让类创建的对象,在系统中只有唯一的一个实例,每一次执行类名()返回的对象,内存地址是相同的。让初始化动作只被执行一次
如:打印机、回收站、音乐播放器。
正常情况
class MusicPlayer(object):
def __new__(cls, *args, **kwargs):
# 如果不返回任何结果,
return super().__new__(cls)
def __init__(self):
print("初始化音乐播放对象")
player = MusicPlayer()
print(player)
单例情况
class MusicPlayer(object):
# 定义类属性记录单例对象引用
instance = None
def __new__(cls, *args, **kwargs):
# 1. 判断类属性是否已经被赋值
if cls.instance is None:
cls.instance = super().__new__(cls)
# 2. 返回类属性的单例引用
return cls.instance
7. 异常
异常基础
- 程序在运行时,如果遇到了错误,会停止程序的执行,并且提示一些错误信息,这就是异常
- 程序停止执行并且提示错误信息这个动作,我们通常称之为:抛出异常
- 程序开发时,很难将所有的情况都处理到,通过异常捕获可以针对突发事件做集中的处理,从而保证程序的稳定性和健壮性
自定义异常
class TooLongExceptin(Exception):
"this is user's Exception for check the length of name "
def __init__(self,leng):
self.leng = leng
def __str__(self):
print("姓名长度是"+str(self.leng)+",超过长度了")
异常捕获语法示例
try:
# 尝试执行的代码
pass
except 错误类型1:
# 针对错误类型1,对应的代码处理
pass
except 错误类型2:
# 针对错误类型2,对应的代码处理
pass
except (错误类型3, 错误类型4):
# 针对错误类型3 和 4,对应的代码处理
pass
except Exception as result:
# 打印错误信息
print(result)
else:
# 没有异常才会执行的代码
pass
finally:
# 无论是否有异常,都会执行的代码
print("无论是否有异常,都会执行的代码")
else 只有在没有异常时才会执行的代码
finally 无论是否有异常,都会执行的代码
之前一个演练的 完整捕获异常 的代码如下:
try:
num = int(input("请输入整数:"))
result = 8 / num
print(result)
except ValueError:
print("请输入正确的整数")
except ZeroDivisionError:
print("除 0 错误")
except Exception as result:
print("未知错误 %s" % result)
else:
print("正常执行")
finally:
print("执行完成,但是不保证正确")
raise抛出异常
在业务开发中,除了代码执行错误,python会抛出异常之外,还需要主动抛出异常,由其他需要处理的函数捕获异常。相当于java 中的throw
示例
def input_password():
# 1. 提示用户输入密码
pwd = input("请输入密码:")
# 2. 判断密码长度,如果长度 >= 8,返回用户输入的密码
if len(pwd) >= 8:
return pwd
# 3. 密码长度不够,需要抛出异常
# 1> 创建异常对象 - 使用异常的错误信息字符串作为参数
ex = Exception("密码长度不够")
# 2> 抛出异常对象
raise ex
try:
user_pwd = input_password()
print(user_pwd)
except Exception as result:
print("发现错误:%s" % result)