记录python面向对象开发笔记
面向对象(OOP)基本概念
面向对象编程:Object oriented programming 简写OOP
一. 目标
了解面向对象基本概念
1. 面向对象基本概念
之前学习的python变成方式是 面向过程的,而面向过程与面向对象,是两种不同的编程方式。
1.1 过程和函数
-
过程是早期的变成概念
-
过程类似于函数,只能执行,但是没有返回值
-
函数不仅能执行,还可以返回结果
1.2 面向过程和面向对象的基本概念
1)面向过程怎么做?
- 把完成某一个需求的所有步骤从头至尾逐步骤实现
- 根据开发需求,将某些功能独立的代码封装为函数
- 最后完成代码,就是顺序的调用不同函数
特点
- 注重步骤和过程,不注重职责分工
- 如果需求复杂,代码会很复杂
- 开发复杂项目,没有固定的套路,开发难度大
2)面向对象
相比函数,面向对象是更大的封装,职责在一个对象中封装多个方法
- 在完成某一个需求前,首先确定职责,也就是要做的事情
- 根据职责确定不同的对象,在对象内部封装不同的方法
- 最后完成的代码,就是顺序的让不同的对象调用不同的方法
特点
- 注重对象和职责,不同的对象承担不同的职责
- 适合复杂的需求变化,专门应对复杂项目开发,提供固定套路
- 需要在面向过程基础上,再学一些面向对象的语法
二. 类和对象
目标
- 类和对象的概念
- 类和对象的关系
- 类的设计
2. 类和对象的概念
类和对象是面向对象编程的两个核心概念
2.1 类
-
类 是对一群有相同特征或者行为的事物的一个统称,是抽象的,不能直接使用
- 特征被称为属性
- 行为被称为方法
- 类 相当于制造飞机的图纸,是负责创建对象的
类一般需要满足以下三个要素:
- 类名:这类事物的名字
- 属性:这类事物的特征
- 方法:这类事物的行为
2.2 对象
- 对象 是由类创建出来的一个具体存在,可以直接使用
- 由哪一个类创建出来的对象,就拥有在哪一个类中定义的:
- 属性
- 方法
- 对象相当于用图纸制造的飞机
- 在程序开发中,应该先有类,再有对象。
3. 面向对象基础语法
面向对象是更大的封装,在一个类中封装多个方法,这样通过这个类创建出来的对象,就可以直接调用这些方法
3.1 定义一个简单的类
在python中要定义一个只包含方法的类,语法格式如下:
class 类名:
def 方法1(self, 参数列表):
pass
def 方法2(self,参数列表):
pass
- 方法的定义格式和之前学习过的函数一样
- 区别在于第一个参数必须是self
3.2 创建对象
当一个类定义完成之后,要使用这个类来创建对象,语法格式如下:
对象变量 = 类名()
3.3 第一个面向对象程序
需求
- 小猫爱吃鱼,小猫爱喝水
分析
- 定义一个猫类Cat
- 定义两个方法eat和drink
- 按照需求不需要定义属性
class Cat:
def eat(self):
print("小猫爱吃鱼")
def drink(self):
print("小猫爱喝水")
# 创建猫对象
tom = Cat()
tom.drink()
tom.eat()
案例进阶 使用Cat类再创建个对象
# 再创建个猫对象
lazy_cat = Cat()
lazy_cat.drink()
lazy_cat.eat()
其中lazy_cat与tom两个不是一个对象,但属于同一类中
3.4 方法中的self参数
案例改造
- 在python中,要给对象设置属性,非常的容易,但是不推荐使用
- 因为:对象属性的封装应该直接在类的内部
- 只需要在类的外部的代码中直接通过
.
设置一个属性即可
class Cat:
def eat(self):
print("%s 爱吃鱼" % self.name)
def drink(self):
print("%s 爱喝水" % self.name)
# 创建猫对象
tom = Cat()
# 访问对象的属性
tom.name = "Tom"
tom.drink()
tom.eat()
# 再创建个猫对象
lazy_cat = Cat()
# 访问对象的属性
lazy_cat.name = "大懒猫"
lazy_cat.drink()
lazy_cat.eat()
3.5 初始化方法
- 当使用
类名()
创建对象时,会自动执行以下操作:
- 为对象在内存中分配空间:创建对象
- 为对象的属性设置初始值:初始化方法
- 这个**初始化方法就是
__init__
方法,它时对象的内置方法
__init__
方法时专门用来定义一个类具有哪些属性的方法!
在Cat
中增加__init__
方法,验证该方法在创建对象时会被自动调用
class Cat:
def __init__(self):
print("这是一个初始化方法")
# 没有调用对象的属性,但是仍然会输出
tom = Cat()
3.6 在初始化方法内部定义属性
- 在
__init__
方法内部使用self.属性名=属性的初始值
就可以定义属性 - 定义属性之后,再使用
Cat
类创建的对象都会拥有该属性
class Cat:
def __init__(self):
print("这是一个初始化方法")
# self.属性名 = 属性的初始值
self.name = "Tom"
3.7 改造初始化方法,初始化的同时设置初始值
- 在开发中,如果希望在创建对象的同时设置对象的属性,可以对
__init__
方法进行改造
- 把希望设置的属性值,定义成
__init__
方法的参数 - 把方法内部使用
self.属性=形参
接受外部传递的参数 - 在创建对象时,使用
类名(属性1,属性2,...)
调用
class Cat:
def __init__(self, new_name):
print("这是一个初始化方法")
# self.属性名 = 属性的初始值
self.name = new_name
3.8 内置方法和属性
序号 | 方法名 | 类型 | 作用 |
---|---|---|---|
01 | __del__ |
方法 | 对象从内存中销毁时,自动调用 |
02 | __str__ |
方法 | 返回对象的描述信息,print函数输出使用 |
-
__del__
方法- 在python中
- 当使用
类名()
创建对象时,为对象分配完空间后,会自动调用__init__
方法 - 当一个对象从内存中销毁前,会自动调用
__del__
方法
- 当使用
- 应用场景
-
__init__
改造初始化方法,可以让创建对象更加灵活 -
__del__
如果希望在对象被销毁前,再做一些事情,可以考虑一下__del__
方法
-
- 生命周期
- 一个对象从调用
类名()
创建,生命周期开始 - 一个对象的
__del__
方法一旦被调用,生命周期结束 - 再对象的生命周期内,可以访问对象属性,或者让对象调用方法
- 一个对象从调用
class Cat: def __init__(self, new_name): print("这是一个初始化方法") # self.属性名 = 属性的初始值 self.name = new_name def __del__(self): print("%s 删了" % self.name) tom = Cat("Tom") print("-" * 50)
这样tom删了的字样会在打印分割线之下才能输出
class Cat: def __init__(self, new_name): print("这是一个初始化方法") # self.属性名 = 属性的初始值 self.name = new_name def __del__(self): print("%s 删了" % self.name) tom = Cat("Tom") # 使用del关键字删除一个对象 del tom print("-" * 50)
这样tom删了的字样会在分割线之上就已经输出
- 在python中
-
__str__
方法- 在python中,使用print输出对象变量,默认情况下,会输出这个变量引用的对象是由哪一个类创建的对象,以及在内存中的地址
- 如果在开发中,希望使用
pring
输出变量对象时,能够打印自定义内容,就可以利用__str__
方法
class Cat: def __init__(self, new_name): print("这是一个初始化方法") # self.属性名 = 属性的初始值 self.name = new_name def __del__(self): print("%s 删了" % self.name) def __str__(self): # 必须返回一个字符串 return "我是小猫 %s" % self.name # 创建猫对象 tom = Cat("Tom") print(tom)
-
案例
需求:
- 小明体重
75
公斤 - 小明每次跑步会减肥
0.5
公斤 - 小明每次吃东西体重增加
1
公斤
封装:
- 封装面向对象编程的一大特点
- 面向对象编程的第一步将属性和方法封装到一个抽象的类中
- 外界使用类创建对象,然后让对象调用方法
- 对象方法的细节都被封装在类的内部
- 同一个类内,不同对象的属性是不会互相干扰的
Code:
class Person(): def __init__(self, name, weight): # self.属性 = 形参 self.name = name self.weight = weight def __str__(self): return "我的名字叫 %s 我的体重是 % .2f 公斤" % (self.name, self.weight) def run(self): print("%s 爱跑步,跑步锻炼身体" % self.name) self.weight -= 0.5 def eat(self): print("%s 爱吃,吃完再减肥" % self.name) self.weight += 1 xiaoming = Person("小明", 75) xiaoming.eat() xiaoming.run() print(xiaoming)
- 小明体重
3.9 私有属性和私有方法
应用场景
- 在实际开发中,对象的某些属性或方法可能只希望在对象内部被使用,而不希望在外部被访问到
- 私有属性就是对象不希望公开的属性
- 私有方法就是对象不希望公开的方法
定义方式
- 在定义属性或方法时,在属性名或方法名前加两个下划线,定义的就是私有属性或方法
class Women():
def __init__(self, name, weight):
# self.属性 = 形参
self.name = name
# weight就是表示women类的私有属性,无法被调用输出
self.__weight = weight
def secret(self):
print("%s 的年龄是 %d" % (self.name, self.__weight))
def __msecret(self):
print("%s 的年龄是 %d" % (self.name, self.__weight))
xiaomei = Women("小明", 75)
xiaomei.secret()
# 私有方法,在外界也无法被直接访问
xiaomei.__msecret()
# 私有属性,在外界无法被直接访问
print(xiaomei.__weight)
4 继承
目标
- 单继承
- 多继承
面向对象三大特性
- 封装根据职责将属性和方法封装到一个抽象的类中
- 继承实现代码的重用,相同的代码不需要重复的编写
- 多态不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度
4.1 单继承
继承的概念、语法和特点
继承的概念:子类拥有父类的所有方法和属性
1. 继承的语法
class 类名(父类名):
pass
- 子类 继承自 父类,可以直接享受父类中已经封装好的方法,不需要再次开发
- 子类 中应该根据职责,封装子类特有的属性和方法
2. 继承的传递性
-
c
类从b
类继承,b
类由从a
类继承 - 那么
c
类就具有b
类和a
类的所有属性和方法
子类拥有父类以及父类的父类中封装的所有属性和方法
3.方法的重写
- 当父类的方法实现不能满足子类需求时,可以对方法进行重写*(override)
- 重写父类方法有两种情况:
-
覆盖父类的方法
- 如果在开发中,父类的方法实现和子类的方法实现,完全不同
- 可以使用覆盖的方式,在子类中重新编写父类的方法实现
具体的实现方式,相当于在子类中定义了一个和父类同名的方法并实现,重写之后,在 运行时只会调用子类中重写的方法,而不再调用父类封装的方法
-
对父类方法进行扩展
- 如果在开发中,子类的方法实现中包含父类的方法实现
- 父类原本封装的方法实现是子类方法的一部分
可以使用扩展的方式:
-
在子类中重写父类的方法
-
在需要的位置使用
super().父类方法
来调用父类方法的执行 -
代码其他的位置针对子类的需要,编写子类特有的代码实现
关于super
- 在
python
中super
是一个特殊的类 -
super()
就是使用super
创建的对象 - 最常用的使用场景就是在重写父类方法时,调用父类中封装的方法实现
4.父类的私有属性和私有方法
- 子类对象不能在自己的方法内部,直接访问父类的私有属性或私有方法
-
子类对象可以通过父类的公有方法间接访问到私有属性或私有方法
- 私有属性、方法是对象的隐私,不对外公开,外界以及子类都不能直接访问
- 私有属性、方法通常用于做一些内部的事情
4.2 多继承
-
概念:
- 子类可以拥有多个父类,并且具有所有父类的属性和方法
- 例:孩子会继承自己父亲和母亲的特性
-
语法:
clsaa 子类名(父类名1, 父类名2,...) pass
-
注意事项: 如果不同的父类中存在同名的方法,在开发时,应该尽量避免这种容易混淆的情况
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()
# 创建一个狗对象
# wangcai = Dog("旺财") # 引用的是父类中的方法
wangcai = XiaoTianDog("飞天旺财") # 引用的Dog子类的方法
# 创建一个小明对象
xiaoming = Person("小明")
# 让小明与狗玩耍
xiaoming.game_with_dog(wangcai)
6. 类方法和静态方法
1 类方法
-
类属性是针对类对象定义的属性
- 使用赋值语句在
class
关键字下方可以定义类属性 - 类属性用于记录这个类相关的特征
- 使用赋值语句在
-
类方法就是针对类对象定义的方法
- 在类方法内部可以直接访问类属性或者调用其他的类方法
语法如下
@classmethod
def 类方法名(cls):
pass
- 类方法需要修饰器
@classmethod
来标识,告诉解释器这是一个类方法 - 类方法的第一个参数应该是
cls
- 由哪一个类调用的方法,方法内的
cls
就是哪一个类的引用 - 这个参数和实例方法的第一个参数是
self
类似
- 由哪一个类调用的方法,方法内的
- 通过
类名.
调用类方法,调用方法时,不需要传递cls
参数 - 在方法内部
- 可以通过
cls.
访问类的属性 - 也可以通过
cls.
调用其他的类方法
- 可以通过
class Tool(object):
# 使用赋值语句定义类属性,记录所有工具对象的数量
count = 0
@classmethod
def show_tool_count(cls):
print("工具对象的数量 %d" % cls.count)
def __init__(self, name):
self.name = name
# 让类属性的值+1
Tool.count += 1
# 创建工具对象
tool1 = Tool("斧头")
# 调用类方法
Tool.show_tool_count()
2. 静态方法
- 在开发时,如果需要在类中封装一个方法,这个方法:
- 既不需要访问实例属性,或者调用实例方法
- 也不需要访问类属性或者调用类方法
- 这个时候,可以把这个方法封装成一个静态方法
语法如下
@staticmethod
def 静态方法名():
pass
-
静态方法需要使用修饰器
@staticmethod
来进行标识,告诉解释器这是一个静态方法 - 通过
类名.
调用静态方法
class Dog(object):
@staticmethod
def run():
print("小狗要跑...")
# 通过类名.调用静态方法
Dog.run()
本文地址:https://blog.csdn.net/qq_37000789/article/details/107338048
上一篇: C# 打印PPT幻灯片
下一篇: C#左移运算符