面向对象三大特性、类的约束、print带颜色输出及super补充
简述:
python面向对象的三大特性:
1.继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类,继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。抽象只是分析和设计的过程中,一个动作或者说一种技巧,通过抽象可以得到类
2.封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。
3.多态指的是一类事物有多种形态
继承
上篇博客已做阐述
封装
在使用面向对象封装特性时,大致分两个步骤:
1.将内容封装到某处;
class Foo:
def __init__(self,name,age): # 称为构造方法,根据类创建对象自动执行
self.name = name
self.age = age
obj1 = Foo("alex",18) # 将alex 和18 分别封装到obj1的name和age属性中
obj2 = Foo("taibai",30) # 将taibai 和30分别封装到obj2的name和age属性中
class Foo:
def __init__(self,name,age): # 称为构造方法,根据类创建对象自动执行
self.name = name
self.age = age
obj1 = Foo("alex",18) # 将alex 和18 分别封装到obj1的name和age属性中
obj2 = Foo("taibai",30) # 将taibai 和30分别封装到obj2的name和age属性中
self为一个形式参数,接收obj1和obj2对象内存地址,当实例化对象时,对象属性内容被封装到obj1和obj2中,每个对象中都有name和age属性
2.从某处调用被封装的内容
调用封装内容时,有两种情况:
1.通过对象直接调用
class Foo:
def __init__(self,name,age):
self.name = name
self.age = age
obj1 = Foo("alex",18)
print(obj1.name)
print(obj1.age)
obj2 = Foo("taibai",20)
print(obj2.name)
print(obj2.age)
# 通过对象直接调用被封装的内容
class Foo:
def __init__(self,name,age):
self.name = name
self.age = age
obj1 = Foo("alex",18)
print(obj1.name)
print(obj1.age)
obj2 = Foo("taibai",20)
print(obj2.name)
print(obj2.age)
# 通过对象直接调用被封装的内容
2.通过self间接调用
执行类中的方法时,需要self间接调用被封装的内容
class Foo:
sef __init__(self,name,age):
self.name =name
self.age = age
def detail(self):
print(self.name)
print(self.age)
obj1 = Foo("alex",18)
obj1.detail() # python默认会将obj1传给self参数,此时detail中的self为obj1
obj2 = Foo("taibai",30)
obj1.detail() # python默认会将obj1传给self参数,此时detail中的self为obj2
class Foo:
sef __init__(self,name,age):
self.name =name
self.age = age
def detail(self):
print(self.name)
print(self.age)
obj1 = Foo("alex",18)
obj1.detail() # python默认会将obj1传给self参数,此时detail中的self为obj1
obj2 = Foo("taibai",30)
obj1.detail() # python默认会将obj1传给self参数,此时detail中的self为obj2
综上所述,对于面向对象的封装来说,其实就是使用构造方法将内容封装到 对象 中,然后通过对象直接或者self间接获取被封装的内容。
多态
多态,同一个对象,多种形态。python默认支持多态。
# 在java或者c#定义变量或者给函数传值必须定义数据类型,否则就报错。
def func(int a):
print('a必须是数字')
# 而类似于python这种弱定义类语言,a可以是任意形态(str,int,object等等)。
def func(a):
print('a是什么都可以')
# 再比如:
class F1:
pass
class S1(F1):
def show(self):
print 'S1.show'
class S2(F1):
def show(self):
print 'S2.show'
# 由于在Java或C#中定义函数参数时,必须指定参数的类型
# 为了让Func函数既可以执行S1对象的show方法,又可以执行S2对象的show方法,所以,定义了一个S1和S2类的父类
# 而实际传入的参数是:S1对象和S2对象
def Func(F1 obj):
"""Func函数需要接收一个F1类型或者F1子类的类型"""
print obj.show()
s1_obj = S1()
Func(s1_obj) # 在Func函数中传入S1类的对象 s1_obj,执行 S1 的show方法,结果:S1.show
s2_obj = S2()
Func(s2_obj) # 在Func函数中传入Ss类的对象 ss_obj,执行 Ss 的show方法,结果:S2.show
Python伪代码实现Java或C # 的多态
# 在java或者c#定义变量或者给函数传值必须定义数据类型,否则就报错。
def func(int a):
print('a必须是数字')
# 而类似于python这种弱定义类语言,a可以是任意形态(str,int,object等等)。
def func(a):
print('a是什么都可以')
# 再比如:
class F1:
pass
class S1(F1):
def show(self):
print 'S1.show'
class S2(F1):
def show(self):
print 'S2.show'
# 由于在Java或C#中定义函数参数时,必须指定参数的类型
# 为了让Func函数既可以执行S1对象的show方法,又可以执行S2对象的show方法,所以,定义了一个S1和S2类的父类
# 而实际传入的参数是:S1对象和S2对象
def Func(F1 obj):
"""Func函数需要接收一个F1类型或者F1子类的类型"""
print obj.show()
s1_obj = S1()
Func(s1_obj) # 在Func函数中传入S1类的对象 s1_obj,执行 S1 的show方法,结果:S1.show
s2_obj = S2()
Func(s2_obj) # 在Func函数中传入Ss类的对象 ss_obj,执行 Ss 的show方法,结果:S2.show
Python伪代码实现Java或C # 的多态
鸭子类型
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()
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两个类完全没有耦合性,但在某种意义上却统一了一个标准
相同的功能设定了相同的名字,这样便于开发,这两个方法就互为鸭子类型
类的约束
这里所指的约束是对类的约束
对类的约束的两种方法:
- 提取⽗类. 然后在⽗类中定义好⽅法. 在这个⽅法中什么都不⽤⼲. 就抛⼀个异常就可以了. 这样所有的⼦类都必须重写这个⽅法. 否则. 访问的时候就会报错.
- 使⽤元类来描述⽗类. 在元类中给出⼀个抽象⽅法. 这样⼦类就不得不给出抽象⽅法的具体实现. 也可以起到约束的效果.
第一种方法:
class Payment:
def pay(self,money):
raise Exception("你没有实现pay方法") # 下面几个类的父类,指定标准,继承该基类的子类中必须定义pay方法,否则继承此基类pay方法主动抛出异常
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)
a = Alipay()
b = QQpay()
c = Wechatpay()
pay(a,100)
pay(b,200)
pay(c,300)
class Payment:
def pay(self,money):
raise Exception("你没有实现pay方法") # 下面几个类的父类,指定标准,继承该基类的子类中必须定义pay方法,否则继承此基类pay方法主动抛出异常
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)
a = Alipay()
b = QQpay()
c = Wechatpay()
pay(a,100)
pay(b,200)
pay(c,300)
第二种方法:引入抽象类的概念进行处理
from abc import ABCMeta,abstractmeethod
class Payment(metaclass = ABCMeta): # 抽象类 接口类 规范和约束 metaclass指定的是一个元类
@abstractmethod
def pay(self):
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)
w = Wechatpay()
pay(w,100)
from abc import ABCMeta,abstractmeethod
class Payment(metaclass = ABCMeta): # 抽象类 接口类 规范和约束 metaclass指定的是一个元类
@abstractmethod
def pay(self):
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)
w = Wechatpay()
pay(w,100)
super补充
class A: # 1
def f1(self): # 2
print('in A f1')
def f2(self): # 3
print('in A f2') # 9
class Foo(A): # 4
def f1(self): # 5
super().f2() # 8 super(Foo,self).f2() obj对象内无f2 方法,在其父类A中查找
print('in A Foo') # 10
obj = Foo() # 6 实例化对象obj,并将obj的内存地址传给self
obj.f1() # 7
# 结果:
'in A f2'
'in A Foo'
class A: # 1
def f1(self): # 2
print('in A f1')
def f2(self): # 3
print('in A f2') # 9
class Foo(A): # 4
def f1(self): # 5
super().f2() # 8 super(Foo,self).f2() obj对象内无f2 方法,在其父类A中查找
print('in A Foo') # 10
obj = Foo() # 6 实例化对象obj,并将obj的内存地址传给self
obj.f1() # 7
# 结果:
'in A f2'
'in A Foo'
class A: # 1
def f1(self): # 2
print('in A')
class Foo(A): # 3
def f1(self): # 4
super().f1() # 12 super(Foo,self).f1()
print('in Foo') # 14
class Bar(A): # 5
def f1(self): # 6
print('in Bar') # 13
class Info(Foo,Bar): # 7
def f1(self): # 8
super().f1() # 11 self为Info,对象空间f1方法,按照mro算法执行Info下一个Foo super(Info,self).f1()
print('in Info f1') # 15
obj = Info() # 9 实例化对象
obj.f1() # 10
# 结果:
'in Bar'
'in Foo'
'in Info f1'
class A: # 1
def f1(self): # 2
print('in A')
class Foo(A): # 3
def f1(self): # 4
super().f1() # 12 super(Foo,self).f1()
print('in Foo') # 14
class Bar(A): # 5
def f1(self): # 6
print('in Bar') # 13
class Info(Foo,Bar): # 7
def f1(self): # 8
super().f1() # 11 self为Info,对象空间f1方法,按照mro算法执行Info下一个Foo super(Info,self).f1()
print('in Info f1') # 15
obj = Info() # 9 实例化对象
obj.f1() # 10
# 结果:
'in Bar'
'in Foo'
'in Info f1'
class A: # 1
def f1(self): # 2
print('in A')
class Foo(A): # 3
def f1(self): # 4
super().f1()
print('in Foo')
class Bar(A): # 5
def f1(self): # 6
print('in Bar') # 12
class Info(Foo,Bar): # 7
def f1(self): # 8
super(Foo,self).f1() # 11 按照mro算法执行Foo下一个Bar.f1()
print('in Info f1') # 13
obj = Info() # 9
obj.f1() # 10
# 结果:
'in Bar'
'in Info f1'
class A: # 1
def f1(self): # 2
print('in A')
class Foo(A): # 3
def f1(self): # 4
super().f1()
print('in Foo')
class Bar(A): # 5
def f1(self): # 6
print('in Bar') # 12
class Info(Foo,Bar): # 7
def f1(self): # 8
super(Foo,self).f1() # 11 按照mro算法执行Foo下一个Bar.f1()
print('in Info f1') # 13
obj = Info() # 9
obj.f1() # 10
# 结果:
'in Bar'
'in Info f1'
print带颜色输出
书写格式: 开头部分:\033[显示方式;前景色;背景色m + 结尾部分:\033[0m
开头部分的三个参数:显示方式,前景色,背景色是可选参数,可以只写其中的某一个;另外由于表示三个参数不同含义
的数值都是唯一的没有重复的,所以三个参数的书写先后顺序没有固定要求,系统都能识别;但是,建议按照默认的格式
规范书写。对于结尾部分,其实也可以省略,但是为了书写规范,建议\033[***开头,\033[0m结尾。
字体色 | 背景色 | 颜色描述 |
30 | 40 | 黑色 |
31 | 41 | 红色 |
32 | 42 | 绿色 |
33 | 43 | 黃色 |
34 | 44 | 蓝色 |
35 | 45 | 紫红色 |
36 | 46 | 青蓝色 |
37 | 47 | 白色 |
显示方式 | 效果 |
0 | 终端默认设置 |
1 | 高亮显示 |
4 | 使用下划线 |
5 | 闪烁 |
7 | 反白显示 |
8 | 不可见 |
22 | 非粗体 |
24 | 非下划线 |
25 | 非闪烁 |
27 | 非反显 |
常见开头格式:
\033[0m 默认字体正常显示,不高亮
\033[32;0m 红色字体正常显示
\033[1;32;40m 显示方式: 高亮 字体前景色:绿色 背景色:黑色
\033[0;31;46m 显示方式: 正常 字体前景色:红色 背景色:青色