面向对象三大特性、类的约束、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两个类完全没有耦合性,但在某种意义上却统一了一个标准

相同的功能设定了相同的名字,这样便于开发,这两个方法就互为鸭子类型

类的约束

这里所指的约束是对类的约束

对类的约束的两种方法:

  1. 提取⽗类. 然后在⽗类中定义好⽅法. 在这个⽅法中什么都不⽤⼲. 就抛⼀个异常就可以了. 这样所有的⼦类都必须重写这个⽅法. 否则. 访问的时候就会报错.
  2. 使⽤元类来描述⽗类. 在元类中给出⼀个抽象⽅法. 这样⼦类就不得不给出抽象⽅法的具体实现. 也可以起到约束的效果.

第一种方法:

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 显示方式: 正常 字体前景色:红色 背景色:青色