一、面向对象
命名规则:python中,包名,模块名均小写;类名每个单词首字母大写;方法名除首个单词小写外其他单词首写字母大写。
面向对象的三大特征:封装、继承、多态。
1、类和对象
- 类:是一类具有相同属性和方法的对象的集合。
- 对象:实例化即可得到一个具体的对象,这个对象就可以调用类的属性和方法。
- 类的组成
(1)类名 (给这多个事物起一个名字, 在代码中 满足大驼峰命名法(每个单词的首字母大写)) 。
(2)属性 (事物的特征, 即有什么, 一般文字中的名词) 。
(3) 方法 (事物的行为, 即做什么事, 一般是动词)。 - 类的抽象(类的设计)
类的抽象,其实就是找到 类的 类名, 属性 和方法
2、属性
- 属性:对象的属性特征。
- 属性的划分:实例属性和类属性。
2.1 实例属性
概念: 是实例对象 具有的属性
-
定义和使用
在 init 方法中, 使用 self.属性名 = 属性值 定义
在方法中是 使用 self.属性名 来获取(调用) -
内存
实例属性,在每个实例中 都存在一份。
-
使用时机
(1)基本上 99% 都是实例属性,即通过 self 去定义。
(2)找多个对象,来判断这个值是不是都是一样的, 如果都是一样的, 同时变化,则一般定义为 类属性, 否则定义为 实例属性。
2.2 类属性
概念: 是 类对象 具有的属性。
-
定义和使用
在类内部,方法外部,直接定义的变量 ,就是类属性。
使用: 类对象.属性名 = 属性值 or 类名.属性名 = 属性值
类对象.属性名 or 类名.属性名 -
内存
只有 类对象 中存在一份
3、方法
- 方法:对象所具有的能力动作。
- 方法划分:实例方法、类方法和静态方法。
3.1 实例方法(最常用)
- 定义
在类中直接定义的方法 就是 实例方法。
class Demo:
def func(self): # 参数一般写作 self,表示的是实例对象
pass
-
定义时机(什么时候用)
如果在方法中需要使用实例属性(即需要使用 self), 则这个方法必须定义为 实例方法 。
-
调用
对象.方法名() # 不需要给 self 传参
3.2 类方法(会用)
- 定义
在方法名字的上方书写 @classmethod 装饰器(使用 @classmethod 装饰的方法)
class Demo:
@classmethod
def func(cls): # 参数一般写作 cls, 表示的是类对象(即类名) class
pass
-
定义时机(什么时候用)
前提, 方法中不需要使用 实例属性(即 self)
用到了类属性, 可以将这个方法定义为类方法,(也可以定义为实例方法) -
调用
# 1. 通过类对象调用
类名.方法名() # 也不需要给 cls 传参, python 解释器自动传递
# 2. 通过实例对象调用
实例.方法名() # 也不需要给 cls 传参, python 解释器自动传递
3.3 静态方法(基本不用)
- 定义
#在方法名字的上方书写 @staticmethod 装饰器(使用 @staticmethod 装饰的方法)
class Demo:
@staticmethod
def func(): # 一般没有参数
pass
-
定义时机(什么时候用)
前提, 方法中不需要使用 实例属性(即 self)
也不使用 类属性, 可以将这个方法定义为 静态方法 -
调用
# 1. 通过类对象调用
类名.方法名()
# 2. 通过实例对象调用
实例.方法名()
4、魔法方法
python 中有一类方法, 以两个下划线开头,两个下划线结尾,并且在满足某个条件的情况下, 会自动调用, 这类方法称为 魔法方法。
4.1__init__ 方法 (构造方法)
init 方法, 创建对象之后,会自动调用 (构造方法)
- 什么情况下自动调用
创建对象之后会自动调用。
- 有什么用, 用在哪
(1) 给对象添加属性的, (初始化方法, 构造方法) 。
(2) 某些代码, 在每次创建对象之后, 都要执行,就可以将这行代码写在 init 方法。 - 书写的注意事项
(1)不要写错了。
(2)如果 init 方法中,存在出了 self 之外的参数, 在创建对象的时候必须传参。
class Cat:
# 定义添加属性的方法
def __init__(self, name, age): # 这个方法是创建对象之后调用
self.name = name # 给对象添加 name 属性
self.age = age # 给对象添加 age 属性
# 输出属性信息
def show_info(self):
print(f'小猫的名字是: {self.name}, 年龄是: {self.age}')
# 创建对象,不要在自己类缩进中创建
# Cat() # 创建对象 ,会输出
blue_cat = Cat('蓝猫', 2)
blue = blue_cat
blue.show_info()
# 创建黑猫
black_cat = Cat('黑猫', 3)
black_cat.show_info()
4.2__str__ 方法
- 什么情况下自动调用
使用 print(对象) 打印对象的时候 会自动调用。
- 有什么用, 用在哪
在这个方法中一般书写对象的 属性信息的, 即打印对象的时候想要查看什么信息,在这个方法中进行定义的。
如果类中没有定义 str 方法, print(对象) ,默认输出对象的引用地址。 - 书写的注意事项
这个方法必须返回 一个字符串。
class Cat:
# 定义添加属性的方法
def __init__(self, n, age): # 这个方法是创建对象之后调用
self.name = n # 给对象添加 name 属性
self.age = age # 给对象添加 age 属性
def __str__(self):
# 方法必须返回一个字符串, 只要是字符串就行,
return f'小猫的名字是: {self.name}, 年龄是: {self.age}'
# 创建对象,不要在自己类缩进中创建
# Cat() # 创建对象 ,会输出
blue_cat = Cat('蓝猫', 2)
print(blue_cat)
# 创建黑猫
black_cat = Cat('黑猫', 3)
print(black_cat)
4.3__del__ 方法 (析构方法)
del 方法, 对象被删除销毁时, 自动调用的(遗言, 处理后事) (析构方法)
- 调用场景
(1)程序代码运行结束, 所有对象都被销毁。
(2)直接使用 del 删除对象(如果对象有多个名字(多个对象引用一个对象),需要吧所有的对象都删除才行 )。
class Demo:
def __init__(self, name):
print('我是 __init__, 我被调用了 ')
self.name = name
def __del__(self):
print(f'{self.name} 没了, 给他处理后事...')
# Demo('a')
a = Demo('a')
b = Demo('b')
del a # 删除销毁 对象,
print('代码运行结束')
二、封装
1、封装定义
概念:将数据和操作封装为一个有机的整体,由于类中私有成员都是隐藏的,只向外部提供有限的接口,所以能保证内部的高内聚性与外部的低耦合性。使用者不必了解具体的实现细节,而只是要通过外部接口,以特定的访问权限来使用类的成员,能顾增强安全性和简化编程。
class Person:#定义类,类名为Person
name = 'zhangsan'#类的属性
age = 18
def study(self):#类的方法
print('study')
def sleep(self):
print('sleep')
if __name__ == '__main__':
p = Person()#实例化类得到一个对象p
print(p.name)#调用类的属性,对象.属性
p.study()#调用类的方法
2、私有化
私有化:私有化只有属性和方法,在类的外部将不能访问,只能在类的内部访问
class Person:#定义类,类名为Person
name = 'zhangsan'#类的属性
__age = 18
def study(self):#类的方法
print('study')
print(self.name)
print(self.__age)
self.__sleep()#调用私有化方法
def __sleep(self):
print('sleep')
if __name__ == '__main__':
# p = Person()#实例化类得到一个对象p
# print(p.name)#调用类的属性,对象.属性
# p.study()#调用类的方法
print(Person().name)
Person().study()
注意:
(1)私有化属性,名称前加两个下划线。
(2) 私有化方法,名称前加两个下划线。
(3)调用私有化属性,类的内部无论私有化或非私有化的属性和方法,想住在类的内部的其它方法中调用的话,必须使用关键字self
。
三、继承
什么是继承?答:至少基于两个类之间才有继承。
概念:继承性更符合认知规律,使程序更易于理解,同时节省不必要的重复代码。类与类之间才能继承。
继承子类:派生类/衍生类;继承父类:基类/超类,子类可以继承父类的属性和方法。
class Father:#父亲类
name = "大张"
def eat(self):
print('Father:eat!')
class Son(Father):#儿子类(继承父亲类)
name1 = "小张"
def eat(self):
print('Son:eat!')
if __name__ == '__main__':
s = Son()
s.eat()
print(s.name)
继承调用规则:从左到右,先深度(纵向)再广度(横向)。
通俗讲:比如说要用钱,子类先看自己有没有,有的话就用自己的;如果没有找自己父亲要,父亲没有找自己的爷爷要,爷爷要是没有的话找i自己的妈妈要。
继承可以避免重复造轮子。如果父类当中的方法子类都要使用,推荐使用继承;如果子类中只是使用父类的部分方法,不推荐使用继承,建议使用导包。
- 多继承
class GrandFather:#爷爷类
name = "老张"
def eat(self):
print('GrandFather:eat!')
class Father(GrandFather):#父亲类(继承爷爷类)
name = "大张"
def eat(self):
print('Father:eat!')
class Mother:#母亲类
name = "李姐"
def eat1(self):
print('Mother:eat!')
class Son(Mother,Father):#多继承,儿子类(继承父亲类,母亲类)
name = "小张"
def eat1(self):
print('Son:eat!')
if __name__ == '__main__':
s =Son()
print(s.name)
s.eat()#鼠标点到方法调用的名称上,按ctrl+b可以直接跳到方法定义的地方,在方法定义的地方同样方式可以调回方法调用的地方
- 如何在子类当中调用父类方法
子类当中调用父类同名方法使用关键子super()
方式一:推荐,不管子类当中有误父类同名的方法,都会始终调用父类方法。
super().study()
方式二:不推荐,因为子类当中如果有同名的方法,将会优先调用自己的;如果没有的话,采用调用父类的方法。
self.study()
class Father():#定义类方法一
class Father:
def study(self):
print('Father:study!')
class Son(Father):
def study(self):#重写:父类方法不能满足子类需求,在子类当中重新定义同名的父类方法叫做重写
print('Son:study!')
def sleep(self):
print('Son:sleep!')
super().study()#方式一
self.study()#方式二
if __name__ == '__main__':
s = Son()
s.sleep()
四、多态
多态:使用相同名称的方法,传入不同的对象,展现处不同的结果。
class Father:
def study(self):
print('Father:study!')
class Son:
def study(self):
print('Son:study!')
if __name__ == '__main__':
def study(obj):
obj.study()
f =Father()
s = Son()
study(f)
study(s)
1、重写
重写: 在子类中定义了和父类中名字相同的方法, 就是重写。
- 重写的原因
父类中的方法,不能满足子类对象的需求,所以重写。
- 重写之后的特点:
调用子类字节的方法, 不再调用父类中的方法。
- 重写的方式:
(1)覆盖(父类中功能完全抛弃,不要,重写书写)
(2)扩展(父类中功能还调用,只是添加一些新的功能) (使用较多)
2、覆盖
(1)直接在子类中 定义和父类中名字相同的方法。
(2)直接在方法中书写新的代码。
3、扩展父类中的功能
(1)直接在子类中 定义和父类中名字相同的方法。
(2) 在合适的地方调用 父类中方法 super().方法()。
(3)书写添加的新功能。
class Dog:
def bark(self):
print('汪汪汪叫.....')
print('汪汪汪叫.....')
class XTQ(Dog):
# XTQ 类bark 方法不再是汪汪汪叫, 改为
# 1. 先 嗷嗷嗷叫(新功能) 2, 汪汪汪叫(父类中功能) 3. 嗷嗷嗷叫 (新功能)
def bark(self):
print('嗷嗷嗷叫...')
# 调用父类中的代码
super().bark() # print() 如果父类中代码有多行呢?
print('嗷嗷嗷叫...')
xtq = XTQ()
xtq.bark()
4、重载
重载:Python没有重载,Java中有重载。