第一章 面向对象初识
面向对象的三大特性是什么? 抽象、继承、多态。
面向对象第一个优点:*
对相似功能的函数,同一个业务的函数进行归类,分类,使你的代码更清晰化,更合理化。
什么是面向对象。
面向对象的程序设计的核心是对象(上帝式思维),要理解对象为何物,必须把自己当成上帝,上帝眼里世间存在的万物皆为对象,不存在的也可以创造出来。
那什么是类?什么是对象?
类:就是具有相同属性和功能的一类事物。
对象:就是类的具体表现。对象一定是不一样的
面向对象的第二个优点:
面向对象,要拥有上帝的视角看问题,类其实就是一个公共模板(厂房),对象就是从具体的模板实例化出来,得对象,得一切
1. 面向对象的结构
class Human:
"""
类的具体结构
"""
#第一部分:静态属性
mind = "思想"
language ="语言"
#第二部分:动态方法
def work(self):
print("工作")
def eat(self):
print("吃饭")
class 是关键字与def用法相同,定义一个类。
Human是此类的类名,类名使用驼峰(CamelCase)命名风格,首字母大写,私有类可用一个下划线开头。
类的结构从大方向来说就分为两部分:
静态变量。
动态方法。
1. 从类名的角度研究类
1.类名操作类中的属性
class Human:
"""
类的具体结构
"""
#第一部分:静态属性
mind = "思想"
language ="语言"
#第二部分:动态方法
def work(self):
print("工作")
def eat(self):
print("吃饭")
1.类名查看类中所有的内容
print(Human.__dict__)
2.类名操作类中的静态属性
1.增加
Human.body="有头发"
print(Human.__dict__)
2.删除
del Human.mind
3.改
Human.mind ="个性"
print(Human.__dict__)
4.查
print(Human.language)
# print(Human.__dict__)
2.类名操作动态方法
除了两个特殊方法:静态方法,类方法之外,一般不会通过类名操作一个类中的方法.
Human.work(123)
总结:一般类名
3. 从对象的角度研究类
1.什么是对象
对象是从类中出来的,只要是类名加上(),这就是一个实例化过程,这个就会实例化一个对象。**
实例化一个对象总共发生了三件事:
1,在内存中开辟了一个对象空间。
2,自动执行类中的____init____方法,并将这个对象空间(内存地址)传给了__init__方法的第一个位置参数self。
3,在____init__ _方法中通过self给对象空间添加属性。
class Human:
"""
类的具体结构
"""
mind = "思想"
language ="语言"
def __init__(self,name,age):
# self 和 obj 指向的是同一个内存地址同一个空间,下面就是通过self给这个对象空间封装四个属性。
self.n=name
self.a=age
def work(self):
print("工作")
def eat(self):
print("吃饭")
obj=Human("zbb",18) #实例化过程
#得到一个返回值,这个返回值就是对象,实例
print(obj.n)
print(obj.a)
print(obj.__dict__)
#zbb
#{'n': 'zbb'}
2.对象操作对象空间属性
1.对象查看对象的空间的所有属性
obj = Human('zbb',18)
print(obj.__dict__)
2. 对象操作对象空间的属性
obj = Human('zbb',18)
增:
obj.sex = 'laddy_boy'
删:
del obj.a
改:
obj.a = 1000
查:
print(obj.n)
print(obj.__dict__)
3.对象查看类中的属性
obj = Human('zbb',18)
# print(obj.mind)
obj.mind = '无脑的'
print(obj.mind)
print(Human.mind)
4.对象调用类中的方法
class Human:
mind = '有思想'
language = '实用语言'
def __init__(self,name,sex,age,hobby):
self.n = name
self.s = sex
self.a = age
self.h = hobby
def work(self):
print(self)
print('人类会工作')
def tools(self):
print('人类会使用工具')
obj = Human('barry','男',18,'运动')
obj.work()
obj.tools()
5.self 是什么?
self其实就是类中方法(函数)的第一个位置参数,只不过解释器会自动将调用这个函数的对象传给self。所以咱们把类中的方法的第一个参数约定俗成设置成self, 代表这个就是对象。
一个类可以实例化多个对象
obj1= Human('小胖','男',20,'美女')
obj2= Human('相爷','男',18,'肥女')
print(obj1,obj2)
print(obj1.__dict__)
print(obj2.__dict__)
第二章 类空间问题以及类之间的关系
1.何处可以添加对象属性
class A:
def __init__(self,name):
self.name = name
def func(self,sex):
self.sex = sex
# 类外面可以:
obj = A('barry')
obj.age = 18
print(obj.__dict__) # {'name': 'barry', 'age': 18}
# 类内部也可以:
obj = A('barry') # __init__方法可以。
obj.func('男') # func 方法也可以。
2.何处可以添加类的静态属性
class A:
def __init__(self, name):
self.name = name
def func(self, sex):
self.sex = sex
def func1(self):
A.bbb = 'ccc'
# 类的外部可以添加
A.aaa = 'djb'
print(A.__dict__)
# 类的内部也可以添加。
A.func1(111)
print(A.__dict__)
3. 对象如何找到类的属性
对象查找属性的顺序:先从对象空间找 ------> 类空间找 ------> 父类空间找 ------->.....
类名查找属性的顺序:先从本类空间找 -------> 父类空间找--------> ........
上面的顺序都是单向不可逆,类名不可能找到对象的属性。
4.类与类之间的关系
- 依赖关系
- 关联关系
- 组合关系
- 聚合关系
- 实现关系
- 继承关系(类的三大特性之一:继承。)
1.依赖关系
主从之分
依赖关系:将一个类的对象或者类名传到另一个类的方法使用。
2.关联,组合,聚合关系
- 关联关系. 两种事物必须是互相关联的. 但是在某些特殊情况下是可以更改和更换的.
- 聚合关系. 属于关联关系中的⼀种特例. 侧重点是xxx和xxx聚合成xxx. 各⾃有各⾃的声明周期. 比如电脑. 电脑⾥有CPU, 硬盘, 内存等等. 电脑挂了. CPU还是好的. 还是完整的个体
- 组合关系. 给对象封装一个属性,属性值是另一个类的对象
class Boy:
def __init__(self,name,girl=None):
self.name = name
self.girl=girl
def hava_diner(self):
if self.girl:
print(f"{self.name}请{self.girl}吃饭")
else:
print("单身狗")
live=Boy("qw")
# live.hava_diner()
live.girl="zxy"
live.hava_diner()
class Boy:
def __init__(self,name,girl=None):
self.name = name
self.girl=girl
def hava_diner(self):
if self.girl:
print(f"{self.name}请{self.girl}吃饭")
else:
print("单身狗")
def girl_skill(self):
self.girl.skill()
class Girl:
def __init__(self,name):
self.name=name
def skill(self):
print(f"{self.name}能吃")
zbb=Boy("zbb")
# live.hava_diner()
zxy =Girl("zxy")
zbb.girl=zxy
zbb.girl_skill()
class Game_role:
def __init__(self,name,ad,hp):
self.name=name
self.ad=ad
self.hp=hp
def equipment(self,wea):
self.weapon =wea #组合关系
class Weapon:
def __init__(self,name,ad):
self.name = name
self.ad = ad
def weapon_attack(self,p1,p2): #依赖关系
p2.hp-=self.ad
print(f"{p1.name}利用{self.name}给了{p2.name}一枪,{p2.name}掉了{self.ad}血,还剩{p2.hp}")
gailun =Game_role("盖伦",10,100)
yasuo =Game_role("剑豪",20,80)
Sword = Weapon("大保健",16)
Musket = Weapon('菊花枪',20)
# 给游戏人物封装武器属性
gailun.equipment(Sword)
gailun.weapon.weapon_attack(gailun,yasuo)
第三章 继承
1.什么是面向对象的继承
比较官方的说法就是:
继承(英语:inheritance)是面向对象软件技术当中的一个概念。如果一个类别A“继承自”另一个类别B,就把这个A称为“B的子类别”,而把B称为“A的父类别”也可以称“B是A的超类”。继承可以使得子类别具有父类别的各种属性和方法,而不需要再次编写相同的代码。在令子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能。另外,为子类别追加新的属性和方法也是常见的做法。 一般静态的面向对象编程语言,继承属于静态的,意即在子类别的行为在编译期就已经决定,无法在执行期扩充
专业说法: 如果B类继承A类
B类就称为子类,派生类
A类称为父类,基类,超类
通俗一点就是 子承父业
# 继承的用法:
class Aniaml:
live = "123"
def __init__(self,name,sex,age):
self.name = name
self.age = age
self.sex = sex
class Cat(Aniaml):
pass
class Dog(Aniaml):
pass
优点: 减少重复代码 .
增加类之间的耦合度(耦合性不宜多,宜精)
2.继承的分类
在python2x版本中存在两种类.:
⼀个叫经典类. 在python2.2之前. ⼀直使⽤的是经典类. 经典类在基类的根如果什么都不写.
⼀个叫新式类. 在python2.2之后出现了新式类. 新式类的特点是基类的根是object类。
python3x版本中只有一种类:
python3中使⽤的都是新式类. 如果基类谁都不继承. 那这个类会默认继承 object
3.单继承
1.类名,对象执行父类的方法
class Animal:
live = "有生命"
def __init__(self,name,sex,age):
self.name =name
self.sex =sex
self.age =age
def eat(self):
print("chi")
class Human(Animal):
body = "有思想"
#类名执行父类属性的方法(不常用)
print(Human.live)
Human.eat(1213)
#子类执行父类的方法
obj = Human("zbb","男","23") #相当于实例化
print(obj.live)
2.执行顺序
p1 = Person('barry','男',18)
# 实例化对象时必须执行__init__方法,类中没有,从父类找,父类没有,从object类中找。
p1.eat()
# 先要执行自己类中的eat方法,自己类没有才能执行父类中的方法。
3.同时执行子类以及父类方法
第一种方法(不常用)
class Animal:
def eat(self):
print("chi")
class Human:
def __init__(self,name):
self.name =name
def eat(self):
print(f"{self.name}需要吃饭")
Animal.eat(self.name)
obj = Human("zbb")
obj.eat()
第二种方法
class Animal:
def eat(self):
print("chi")
class Human(Animal):
def __init__(self,name):
self.name =name
def eat(self):
print(f"{self.name}需要吃饭")
super().eat()
obj = Human("zbb")
obj.eat()
super() 重构父类的方法
解决多重继承问题
不需要明确给出任何基类的名字,它会自动找到所有直接基类,及其对应的方法.用于继承.
super()的好处就是可以避免直接使用父类的名字.主要用于多重继承
4.多继承
在python2x版本中存在两种类.:
⼀个叫经典类. 在python2.2之前. ⼀直使⽤的是经典类. 经典类在基类的根如果什么都不写.
⼀个叫新式类. 在python2.2之后出现了新式类. 新式类的特点是基类的根是object类。
python3x版本中只有一种类:
python3中使⽤的都是新式类. 如果基类谁都不继承. 那这个类会默认继承 object
1.经典类的多继承
经典类: 深度优先.从左至右,深度优先.
不继承object类
2.新式类的多继承
继承object类
class O:
name = '1'
class D(O):
pass
class E(O):
name = '2'
# pass
class F(O):
name = '3'
class B(D,E):
pass
class C(E,F):
pass
class A(B,C):
pass
obj = A()
print(obj.name)
# mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )
# mro(A(B,C)) = [A] + merge(mro(B),mro(C),[B,C])
总结:直接print 不需要什么算法
print(A.mro())
mro是继承付父类方法时的顺序表
第四章 封装
封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。
所以,在使用面向对象的封装特性时,需要:
- 将内容封装到某处
- 从某处调用被封装的内容
第一步:将内容封装到某处
self 是一个形式参数,当执行 obj1 = Foo( ) 时,self 等于 obj1
第二步:从某处调用被封装的内容
调用被封装的内容时,有两种情况:
- 通过对象直接调用
- 通过self间接调用
1、通过对象直接调用被封装的内容
上图展示了对象 ojb1在内存中保存的方式,根据保存格式可以如此调用被封装的内容:对象.属性名
class Foo:
def __init__(self,name,age):
self.name = name
self.age = age
obj1 = Foo("zbb",18)
print(obj1.name) # 直接调用obj1对象的name属性
print(obj1.age) # 直接调用obj1对象的age属性
2、通过self间接调用被封装的内容
执行类中的方法时,需要通过self间接调用被封装的内容
class Foo:
def __init__(self,name,age):
self.name = name
self.age = age
def func(self):
print(self.name)
print(self.age)
obj1 = Foo("zbb",18)
obj1.func() ## Python默认会将obj1传给self参数
综上所述,对于面向对象的封装来说,其实就是使用构造方法将内容封装到 对象 中,然后通过对象直接或者self间接获取被封装的内容。
第五章 多态
多态,同一个对象,多种形态。python默认支持多态。
鸭子类型
python中有一句谚语说的好,你看起来像鸭子,那么你就是鸭子。
对于代码上的解释其实很简答:
class A:
def f1(self):
print('in A f1')
def f2(self):
print('in A f2')
class B:
def f1(self):
print('in A f1')
def f2(self):
print('in A f2')
obj = A()
obj.f1()
obj.f2()
obj2 = B()
obj2.f1()
obj2.f2()
# A 和 B两个类完全没有耦合性,但是在某种意义上他们却统一了一个标准。
# 对相同的功能设定了相同的名字,这样方便开发,这两个方法就可以互成为鸭子类型。
# 这样的例子比比皆是:str tuple list 都有 index方法,这就是统一了规范。
# str bytes 等等 这就是互称为鸭子类型。
鸭子类型
第六章 类的约束
class Payment:
def pay(self,money):
raise Exception("你的子类需要定义pay方法")
#pass
class QQpay(Payment):
def pay(self,money):
print(f"使用qq支付了{money}")
class Alipay(Payment):
def pay(self,money):
print(f"使用阿里支付了{money}")
class Wechat(Payment):
def fuqian(self,money):
print(f"使用微信支付了{money}")
def pay(obj,money): #统一接口
obj.pay(money) # 这个函数就是统一支付规则,这个叫做: 归一化设计。
obj1 = QQpay()
obj2 = Alipay()
obj3 = Wechat()
pay(obj1,100)
pay(obj2,200)
# pay(obj3,200) # 会直接找到父类 并发出错误
from abc import ABCMeta,abstractmethod
class Payment(metaclass=ABCMeta):
#抽象类 接口类 规范和约束 metaclass指定的是一个元类
@abstractmethod
def pay(self,money):
pass #抽象方法
class QQpay(Payment):
def pay(self,money):
print(f"使用qq支付了{money}")
class Alipay(Payment):
def pay(self,money):
print(f"使用阿里支付了{money}")
class Wechat(Payment):
def fuqian(self,money):
print(f"使用微信支付了{money}")
# def pay(self,money):#强制定义 不定义会报错
# pass
def pay(obj,money): #统一接口
obj.pay(money)
obj3 = Wechat() #实例化过程 就报错了
总结: 约束. 其实就是⽗类对⼦类进⾏约束. ⼦类必须要写xxx⽅法. 在python中约束的⽅式和⽅法有两种:
1. 使⽤抽象类和抽象⽅法, 由于该⽅案来源是java和c#. 所以使⽤频率还是很少的
2.使⽤⼈为抛出异常的⽅案. 并且尽量抛出的是NotImplementError. 这样比较专业, ⽽且错误比较明确.(推荐)
第七章 super()深入了解
super是严格按照类的继承顺序执行!!!
# super可以下一个类的其他方法
# 严格按照类的mro顺序执行
class A:
def f1(self):
print('in A')
class Foo(A):
def f1(self):
super().f1()
print('in Foo')
class Bar(A):
def f1(self):
print('in Bar')
class Info(Foo,Bar):
def f1(self):
super(Foo,self).f1()
#super(Info,self).f1() #()默认是
print('in Info f1')
obj = Info()
obj.f1()
第八章 带颜色的print
书写格式: 开头部分: 33[显示方式;前景色;背景色m + 结尾部分: