不在压力与疲惫中沉浮,
不在良辰与美景中迷失。
不在奋斗与竞争中麻木,
不在辉煌与腾飞中失足。
文章目录
一、Python中的类与对象
1.类与对象的概念
类 和 对象 是 面向对象编程的 两个 核心概念
物以类聚,人以群分
人类
鸟类
植物类
超人类
.....
划分类的标准是?拥有共同的特性?动作?
类 英文单词: class
他们有相似点。共同之处
- 类 是对一群具有 相同特征 或者 行为 的事物的一个统称,是抽象的,不能直接使用
- 特征 被称为 属性
- 它是什么样的
- 特征 被称为 属性
什么是属性???
表示的是类/对象的特征。
特征是别人不具备的。
类属性(类变量):
这个类的特征,这个群体的特征, 别的类(别的群体)可能不具备
实例属性(实例变量) :
这个个体的特征,类当中的其他成员可能不具备。
类属性的获取:
类名.属性
类属性:可以先天定义也可以 后天学习(手工添加)
class Man:
# 定义类属性
gender = '男'
power = "强"
handsome = 'very very'
print(Man.power) # Man类的power属性
print(Man.gender) # Man类的gender属性
# 后天学习(手工添加的)
Man.hello = 'hello world'
print(Man.hello)
# 实例属性的后天学习获取
yuz = Man()
# yuz.handsome = 'very very'
print(yuz.handsome)
kaishi = Man()
kaishi.handsome = '一丢丢'
print(kaishi.handsome)
# 类属性和实例属性:
# 类属性:所有的成员都是一样的。
# 实例属性:不是每个成员都一样
# 第二个区别:
#类属性,可以被实例、对象访问
# 实例属性, 不可以被类获取
print(Man.eye)
class Man:
# 定义类属性
gender = '男'
power = "强"
handsome = 'very very'
yuz = Man()
kaishi = Man()
print(yuz.gender)
print(kaishi.gender)
yuz.eye = '蓝色'
# AttributeError, 属性错误。
# print(kaishi.eye)
print(Man.eye)
**行为** 被称为 **方法**
- 它可以做什么
方法:表示类 、 对象的行为。
方法本质上是函数。
属性名称:名词。
方法:动词,
方法 vS 函数:
1, self
2, 放在类里面,缩进的。
3, 调用过程不一样。 方法需要加前缀,类名或者对象名。
函数前面要么不加,要么加的模块名。
# 对象.方法()
Man().drink()
# 实例方法,对象方法:
1, 第一个参数名称,规定是 self,
2, 实例方法在调用的时候,前缀是对象,不能是类
# 类方法:
1, 在方法的上面添加 @classmethod
2, 把实例方法当中的 self 改成 cls,
# 静态方法
静态方法表示: 方法的上面加上一个 @staticmethod
不需要用 self, cls 作为固定参数
是刚刚好放在一个类当中的普通函数而已。
除了放在类当中,和普通函数没什么区别。
没有实际作用,和类或者对象没有关系(联系),
为什么要用静态方法、为什么要把普通的函数放到类当中去??
方便管理
调用静态方法。
静态方法,(普通函数) 只需要在调用静态方法,前面加上类名或者对象名
类外面的普通函数:普通函数不需要加类,模块
实际使用当中:
实例方法: 98% , 实例方法占大多数情况。
不知道用什么方法,就用实例方法。
类方法:后面会有特殊情况
静态方法: 可以用普通函数代替,不是必须的。(管理方便。)
"""
class Man:
# 定义类属性
gender = '男'
power = "强"
handsome = 'very very'
@staticmethod
def tianqiyubao():
print("天气预报:今天是晴天。")
@classmethod
def eat(cls):
print("正在吃饭")
return "hello world"
def drink(self):
"""喝。。。"""
pass
def play_game(self):
"""玩游戏"""
pass
# # 对象.方法()
# Man().drink()
#
# yuz = Man()
# yuz.drink()
# 行为是属于某一个人的。不能被类调用的
# 不 OK, Man.drink()
# 打印函数的调用打印出来的是函数的返回值。
# def run():
# pass
#
# print(run())
# print(Man.eat())
# print(Man().eat())
# 静态方法的使用
Man.tianqiyubao()
Man().tianqiyubao()
- 类 就相当于建造房子时的施工图纸(blueprint),是一个模板,是负责创建**房子(对象)**的
对象 object: 东西
什么是对象 object
又被称为 实例 instance
- 对象 是 由类创建出来的一个具体存在,可以直接使用
- 由 哪一个类 创建出来的 对象,就拥有在 哪一个类 中定义的:
- 属性
- 方法
- 对象 就相当于用 施工图纸 建造 的房子
在程序开发中,应该 先有类,再有对象
2. 类与对象的关系
- 类是模板,对象 是根据 类 这个模板创建出来的
- 先有类,再有对象
- 类 只有一个,而 对象 可以有很多个
- 不同的对象 之间 属性 可能会各不相同
- 类 中定义了什么 属性和方法,对象 中就有什么属性和方法,不可能多,也不可能少
3.类的设计
在使用面相对象开发前,应该首先分析需求,确定一下,程序中需要包含哪些类!
类的设计要素
在程序开发中,要设计一个类,通常需要满足一下三个要素:
- 类名
- 满足大驼峰命名法
- 属性
- 这类事物具有什么样的特征
- 方法
- 这类事物具有什么样的行为
大驼峰命名法
-
每一个单词的首字母大写
-
单词与单词之间没有下划线
确定类名
名词提炼法 分析 整个业务流程,出现的 名词,通常就是找到的类
确定属性和方法
- 对 对象的特征描述,通常可以定义成 属性
- 对象具有的行为(动词),通常可以定义成方法
类的定义:
class 类名:
类的组成部分
类的调用:
print(类名)
变量 = 类名
<class '__main__.Man'>
<__main__.Man object at 0x0000022ABEE74670>
看到有尖括号的,一般来说就是一个类 / 对象。
4. 定义类
- 在
Python
中要定义一个只包含方法的类,语法格式如下:
class 类名:
def 方法1(self, 参数列表):
pass
def 方法2(self, 参数列表):
pass
- 方法 的定义格式和之前学习过的函数 几乎一样
- 区别在于第一个参数必须是
self
创建对象
- 当一个类定义完成之后,要使用这个类来创建对象,语法格式如下:
对象变量 = 类名()
self
使用 self
在方法内部输出每个人的名字
由 哪一个对象 调用的方法,方法内的
self
就是 哪一个对象的便利贴
-
在类封装的方法内部,
self
就表示 当前调用方法的对象自身 -
调用方法时,程序员不需要传递
self
参数 -
在方法内部
- 可以通过
self.
访问对象的属性 - 也可以通过
self.
调用其他的对象方法
- 可以通过
- 在
Python
中要定义带属性的类,语法格式如下:
初始化方法
-
当使用
类名()
创建对象时,会 自动 执行以下操作:-
为对象在内存中 分配空间 —— 创建对象
-
为对象的属性 设置初始值 —— 初始化方法(
init
)
-
-
这个 初始化方法 就是
__init__
方法,__init__
是对象的内置方法
__init__
方法是 专门 用来定义一个类 具有哪些属性的方法
在初始化方法内部定义属性
- 在
__init__
方法内部使用self.属性名 = 属性的初始值
就可以 定义属性 - 定义属性之后,再使用
Person
类创建的对象,都会拥有该属性
"""
什么是初始化??
要通过定义的类得到一个具体的对象。 生出来,造出来。
对象个体,初始化过程保证生出来是不一样的。
我们自己给东西进行出厂设置。
特定的方法中去控制:
__init__
实例属性的定义2:
1, 类外面: 对象名.属性
2, 类里面: self.属性
__init__ 定义的形式参数 和 对象的实例化 a = Man() 的实际参数,是一一对应的。
1. 必须 return None
2. 传入的参数必须要设置成实例属性,才能被被对象访问到。
self: 在 **类里面** ,表示一个 **对象** 他自己。自我, this
cls, : 在 **类里面** ,表示一个 **类** 他自己。自我, this
实例方法当中,可不可以去定义实例属性。??
"""
# def run():
# pass
class Man:
# 定义类属性
gender = '男'
power = "强"
handsome = 'very very'
def __init__(self, name, face_shape='圆脸'):
"""对象的初始化过程。 让对象之间长得不太一样。"""
# 定义, 在类里面,定义实例属性使用 self.属性 = ...
self.face = face_shape
self.name = name
@staticmethod
def tianqiyubao():
print("天气预报:今天是晴天。")
@classmethod
def eat(cls):
print("正在吃饭")
print(cls.power)
return "hello world"
def drink(self, brand):
"""喝。。。"""
print("{} 正在喝 {} 酒".format(self.name, brand))
# self.play_game()
self.eat()
# 定义实例属性
self.single = False
def play_game(self):
"""玩游戏"""
print("玩游戏")
yuz = Man('yuz', '方脸')
# print(yuz.face)
# print(yuz.name)
# yuz.drink('茅台')
# 整容的权利,可以后天改变属性
# yuz.face = "帅脸"
# print(yuz.face)
# 初始化以后 。 single 属性是后天定义的,
yuz.drink('五粮液')
print(yuz.single)
yuz.single = True
print(yuz.single)
# print(a)
5. __str__
方法
- 在
Python
中,使用print
输出 对象变量,默认情况下,会输出这个变量 引用的对象 是 由哪一个类创建的对象,以及 在内存中的地址(十六进制表示) - 如果在开发中,希望使用
print
输出 对象变量 时,能够打印 自定义的内容,就可以利用__str__
这个内置方法了
注意:
__str__
方法必须返回一个字符串
二、身份运算符
身份运算符用于 比较 两个对象的 内存地址 是否一致 —— 是否是对同一个对象的引用
- 在
Python
中针对None
比较时,建议使用is
判断
运算符 | 描述 | 实例 |
---|---|---|
is | is 是判断两个标识符是不是引用同一个对象 | x is y,类似 id(x) == id(y) |
is not | is not 是判断两个标识符是不是引用不同对象 | x is not y,类似 id(a) != id(b) |
is 与 == 区别
is
用于判断 两个变量 引用对象是否为同一个
==
用于判断 引用变量的值 是否相等
三、 类属性和实例属性
1.概念
- 类属性 就是给 类 定义的 属性
- 通常用来记录 与这个类相关 的特征
- 类属性 不会记录具体对象的特征
动态属性设置
class Phone:
def __init__(self, number):
self.number = number
phone = Phone('137')
# # 对象.属性
# print(phone.number)
#
# # 动态获取属性
# print(getattr(phone, 'number'))
# 动态获取不存在的属性
# print(phone.brand)
# 可以加上 default 参数,设置默认值。当没有该属性的属性,不会报错。
# 而是返回默认值。
# print(getattr(phone, 'brand', default='苹果'))
# 动态属性,属性名 == 变量
prop_name = 'brand'
# phone.prop_name
# phone.brand
print(getattr(phone, prop_name, '苹果'))
print(phone.brand)
# 设置 set 属性。
# print(phone.number)
# setattr(phone, 'number', '155')
# # phone.number = 155
# phone.color = '白色'
# print(phone.number)
四、类方法和静态方法
1.类方法
- 类属性 就是针对 类 定义的属性
- 使用 赋值语句 在
class
关键字下方可以定义 类属性 - 类属性 用于记录 与这个类相关 的特征
- 使用 赋值语句 在
- 类方法 就是针对 类 定义的方法
- 在 类方法 内部可以直接访问 类属性 或者调用其他的 类方法
语法如下
@classmethod
def 类方法名(cls):
pass
-
类方法需要用 修饰器
@classmethod
来标识,告诉解释器这是一个类方法 -
类方法的 第一个参数 应该是
cls
- 由 哪一个类 调用的方法,方法内的
cls
就是 哪一个类的引用 - 这个参数和 实例方法 的第一个参数是
self
类似 - 提示 使用其他名称也可以,不过习惯使用
cls
- 由 哪一个类 调用的方法,方法内的
-
通过 类名. 调用 类方法,调用方法时,不需要传递
cls
参数 -
在方法内部
-
可以通过
cls.
访问类的属性 -
也可以通过
cls.
调用其他的类方法
在类方法内部,可以直接使用
cls
访问 类属性 或者 调用类方法
2.静态方法
- 在开发时,如果需要在 类 中封装一个方法,这个方法:
- 既 不需要 访问 实例属性 或者调用 实例方法
- 也 不需要 访问 类属性 或者调用 类方法
- 这个时候,可以把这个方法封装成一个 静态方法
语法如下
@staticmethod
def 静态方法名():
pass
- 静态方法 需要用 修饰器
@staticmethod
来标识,告诉解释器这是一个静态方法 - 通过 类名. 调用 静态方法
4.总结
-
实例方法 —— 方法内部需要访问 实例属性
-
实例方法 内部可以使用 类名. 访问类属性
-
类方法 —— 方法内部 只 需要访问 类属性
-
静态方法 —— 方法内部,不需要访问 实例属性 和 类属性
提问
如果方法内部 即需要访问 实例属性,又需要访问 类属性,应该定义成什么方法?
答案
- 应该定义 实例方法
- 因为,类只有一个,在 实例方法 内部可以使用 类名. 访问类属性
五、继承
1.概念
- 子类 拥有 父类 的所有 方法 和 属性
- 可以单继承和多继承
2.语法
class 类名(父类名):
pass
- 子类 继承自 父类,可以直接 享受 父类中已经封装好的方法,不需要再次开发
- 子类 中应该根据 职责,封装 子类特有的 属性和方法
3.专业术语
Dog
类是Animal
类的子类,Animal
类是Dog
类的父类,Dog
类从Animal
类继承Dog
类是Animal
类的派生类,Animal
类是Dog
类的基类,Dog
类从Animal
类派生
4.继承的传递性
C
类从B
类继承,B
类又从A
类继承- 那么
C
类就具有B
类和A
类的所有属性和方法
子类 拥有 父类 以及 父类的父类 中封装的所有 属性 和 方法
提问: 哮天犬 能够调用 Cat
类中定义的 catch
方法吗?
5.方法的重写
- 子类 拥有 父类 的所有 方法 和 属性
- 子类 继承自 父类,可以直接 享受 父类中已经封装好的方法,不需要再次开发
应用场景
- 当 父类 的方法实现不能满足子类需求时,可以对方法进行 重写(override)
重写 父类方法有两种情况:
-
覆盖 父类的方法
-
对父类方法进行 扩展
6.覆盖父类的方法
- 如果在开发中,父类的方法实现 和 子类的方法实现,完全不同
- 就可以使用 覆盖 的方式,在子类中 重新编写 父类的方法实现
具体的实现方式,就相当于在 子类中 定义了一个 和父类同名的方法并且实现
重写之后,在运行时,只会调用 子类中重写的方法,而不再会调用 父类封装的方法
7.对父类方法进行 扩展
-
如果在开发中,子类的方法实现 中 包含 父类的方法实现
- 父类原本封装的方法实现 是 子类方法的一部分
-
就可以使用 扩展 的方式
-
在子类中 重写 父类的方法
-
在需要的位置使用
super().父类方法
来调用父类方法的执行 -
代码其他的位置针对子类的需求,编写 子类特有的代码实现
-
"""继承。
父类 子类
继承如何表示:
class 子类名(父类名):
pass
子类可以实现自己独有的方法。
子类可以覆盖父类的方法。 ==》 重写
super() 超继承: 使用父类当中的方法。
"""
class Phone:
"""手机"""
def __init__(self, number):
self.number = number
def call(self, to, recorded=False):
"""打电话"""
print(" {} 给 {} 打电话。。".format(self.number, to))
if recorded:
self.record()
def record(self):
"""录音"""
print("{} 正在录音".format(self.number))
class SmartPhone(Phone):
"""智能手机"""
def __init__(self, number, brand):
self.number = number
self.brand = brand
def watch_movie(self, name):
print("正在看电影{}".format(name))
class Iphone(SmartPhone):
# brand = '苹果'
def __init__(self, number):
super().__init__(number, '苹果')
# self.number = number
# self.brand = "苹果"
def face_time(self):
"""录屏,直播"""
print("{} 正在直播".format(self.number))
def call(self, to, recorded=False, face=False):
"""打电话既可以录音,也可以facetime"""
# print(" {} 给 {} 打电话。。".format(self.number, to))
#
# if recorded:
# self.record()
super().call(to, recorded=False)
if face:
self.face_time()
# normal_phone = Phone('1')
# print(normal_phone.record())
#
# # 父类当中不能调用子类方法。
# # normal_phone.watch_movie("红海行动")
#
# smart_phone = SmartPhone("2")
# print(smart_phone.record())
# print(smart_phone.number)
# smart_phone.watch_movie('小偷家族')
# 当子类和父类具有同样的方法或者属性的时候。
# 父类还是用父类的, 子类不再有父类的,而是用自己的。
# normal = Phone("1")
# smart = SmartPhone(2, '华为')
# 重写例子2
iphone = Iphone('苹果5')
iphone.call('开始', face=True)
# smart = SmartPhone("123", '华为')
# smart.call('李三', face=True)
8.关于 super
- 在
Python
中super
是一个 特殊的类 super()
就是使用super
类创建出来的对象- 最常 使用的场景就是在 重写父类方法时,调用 在父类中封装的方法实现
# super默认会调用第一个父类的方法(适用于单继承 或者只想使用第一个父类的方法) # 02 方式 适用于新式类 # 格式: super(子类类名, self).父类方法名()
总结
类的命名:大驼峰命名: 两个单词的首字母大写。
class PerfectManHelp
函数的命名:下划线命名:perfect_man_help
变量命名:下划线命名.