拓展:经典类和旧式类
经典类
不由任意内置类型派生出的类,称之为经典类(python2默认)
class 类名:
代码
......
新式类
class 类名(object):
代码
概念
python面向对象的继承指的是多个类之间的所属关系,即子类默认继承父类的所有属性和方法
体验
# 定义父类
class A(object):
def __init__(self):
self.num = 1
def info_print(self):
print(self.num)
# 定义子类 继承父类
class B(A):
pass
# 创建对象 验证
result = B()
注意
在python中,所有类默认继承object类,object类是顶级类或基类;其他子类叫做派生类
单继承
多继承
代码示例
# 定义父类
class A(object):
def __init__(self):
self.num = "A类"
def info_print(self):
print(self.num)
class C(object):
def __init__(self):
self.num = "C类"
def info_print(self):
print(self.num)
# 定义子类 继承多个父类
class B(A, C):
pass
class D(C, A):
pass
# 创建对象 验证
result = B()
print(result.num)
result.info_print()
result = D()
print(result.num)
result.info_print()
结论
当一个类有多个父类的时候,默认使用第一个父类的同名属性和方法
子类重写父类同名方法和属性
代码示例
# 定义父类
class A(object):
def __init__(self):
self.num = "A父类"
def info_print(self):
print(f"这是{self.num}")
class C(object):
def __init__(self):
self.num = "C父类"
def info_print(self):
print(f"这是{self.num}")
# 定义子类
class B(A, C):
def __init__(self):
self.num = "B子类"
def info_print(self):
print(f"这是{self.num}")
# 创建对象 验证
result = B()
print(result.num)
result.info_print()
结论
如果子类和父类拥有同名属性和方法,子类创建对象调用属性和方法的时候,调用的是子类里面的同名属性和方法
拓展-mro顺序
代码示例
# 定义父类
class A(object):
def __init__(self):
self.num = "A父类"
def info_print(self):
print(f"这是{self.num}")
class C(A):
def __init__(self):
self.num = "C父类"
def info_print(self):
print(f"这是{self.num}")
# 创建对象 验证
result = C()
print(result.num)
result.info_print()
print(C.__mro__)
输出
C父类
这是C父类
(<class 'main.C'>, <class 'main.A'>, <class 'object'>)
子类调用父类的同名方法和属性
代码示例
# 定义父类
class A(object):
def __init__(self):
self.num = "A父类"
def info_print(self):
print(f"我是{self.num}")
class B(object):
def __init__(self):
self.num = "B父类"
def info_print(self):
print(f"我是{self.num}")
class LaiFu(A, B):
def __init__(self):
self.num = "来福子类"
def info_print(self):
# 如果是先调用了父类的属性和方法,父类属性会覆盖子类属性,故在调用属性前,先调用自己子类的初始化
self.__init__()
print(f"我是{self.num}")
# 子类调用父类的同名方法和属性
def a_info_print(self):
# 调用父类方法,为保证调用到的也是父类的属性,必须在调用方法前调用父类的初始化
A.__init__(self)
A.info_print(self)
def b_info_print(self):
B.__init__(self)
B.info_print(self)
# 创建对象 验证
lianglaifu = LaiFu()
lianglaifu.info_print()
lianglaifu.a_info_print()
lianglaifu.b_info_print()
lianglaifu.info_print()
输出
我是来福子类
我是A父类
我是B父类
我是来福子类
多层继承
代码示例
# 定义父类
class A(object):
def __init__(self):
self.num = "A父类"
def info_print(self):
print(f"我是{self.num}")
class B(object):
def __init__(self):
self.num = "B父类"
def info_print(self):
print(f"我是{self.num}")
# 来福子类,继承A类和B类
class LaiFu(A, B):
def __init__(self):
self.num = "来福子类"
def info_print(self):
# 如果是先调用了父类的属性和方法,父类属性会覆盖子类属性,故在调用属性前,先调用自己子类的初始化
self.__init__()
print(f"我是{self.num}")
# 子类调用父类的同名方法和属性
def a_info_print(self):
# 调用父类方法,为保证调用到的也是父类的属性,必须在调用方法前调用父类的初始化
A.__init__(self)
A.info_print(self)
def b_info_print(self):
B.__init__(self)
B.info_print(self)
# 徒孙类,继承来福子类
class Tusun(LaiFu):
pass
# 使用徒孙类创建对象 验证
lianglaifu = Tusun()
lianglaifu.info_print()
lianglaifu.a_info_print()
lianglaifu.b_info_print()
输出
我是来福子类
我是A父类
我是B父类
super()调用父类方法
有参数super
代码示例
# 定义父类
class A(object):
def __init__(self):
self.num = "A父类"
def info_print(self):
print(f"我是{self.num}")
class B(A):
def __init__(self):
self.num = "B父类"
def info_print(self):
print(f"我是{self.num}")
# 2.1 super()带参数写法
super(B, self).__init__()
super(B, self).info_print()
class Laifu(B):
def __init__(self):
self.num = "梁来福"
def info_print(self):
print(f"我是{self.num}")
# 子类调用父类的同名方法和属性
def a_info_print(self):
# 调用父类方法,为保证调用到的也是父类的属性,必须在调用方法前调用父类的初始化
A.__init__(self)
A.info_print(self)
def b_info_print(self):
B.__init__(self)
B.info_print(self)
# 需求:一次性调用父类A和B的方法
def new_info_print(self):
# 方法一:代码冗余;父类类名如果变化,这里代码需要频繁修改
#B.__init__(self)
#B.info_print(self)
#A.__init__(self)
#A.info_print(self)
# 方法二:super()
# 方法2.1 super(当前类名, self).函数()
super(Laifu, self).__init__()
super(Laifu, self).info_print()
lianglaifu = Laifu()
lianglaifu.new_info_print()
输出
我是B父类
我是A父类
无参数super
代码示例
# 定义父类
class A(object):
def __init__(self):
self.num = "A父类"
def info_print(self):
print(f"我是{self.num}")
class B(A):
def __init__(self):
self.num = "B父类"
def info_print(self):
print(f"我是{self.num}")
# 2.1 super()带参数写法
# super(B, self).__init__()
# super(B, self).info_print()
# 2.2 super()无参数写法
super().__init__()
super().info_print()
class Laifu(B):
def __init__(self):
self.num = "梁来福"
def info_print(self):
print(f"我是{self.num}")
# 子类调用父类的同名方法和属性
def a_info_print(self):
# 调用父类方法,为保证调用到的也是父类的属性,必须在调用方法前调用父类的初始化
A.__init__(self)
A.info_print(self)
def b_info_print(self):
B.__init__(self)
B.info_print(self)
# 需求:一次性调用父类A和B的方法
def new_info_print(self):
# 方法一:代码冗余;父类类名如果变化,这里代码需要频繁修改
#B.__init__(self)
#B.info_print(self)
#A.__init__(self)
#A.info_print(self)
# 方法二:super()
# 方法2.1 带参数:super(当前类名, self).函数()
# super(Laifu, self).__init__()
# super(Laifu, self).info_print()
# 方法2.2 无参数:super
super().__init__()
super().info_print()
lianglaifu = Laifu()
lianglaifu.new_info_print()
输出
我是B父类
我是A父类
注意
使用super()可以自动查找父类。调用顺序遵循__mro__类属性的顺序,比较适合单继承使用
私有权限
定义私有属性和方法
在python中,可以为实例属性和方法设置私有权限,即设置某个实例属性或实例方法不继承给子类
设置方法
设置私有权限的方法:在属性名和方法名前面加上两个下划线__
代码示例
......
class Laifu(B):
def __init__(self):
self.num = "梁来福"
# 定义私有属性
self.__money = 20000000000
def info_print(self):
print(f"我是{self.num}")
# 定义私有方法
def __info_print(self):
print("这是私有方法")
......
获取和修改私有属性值
代码示例
# 定义父类
class A(object):
def __init__(self):
self.num = "A父类"
def info_print(self):
print(f"我是{self.num}")
class B(A):
def __init__(self):
self.num = "B父类"
def info_print(self):
print(f"我是{self.num}")
# 2.1 super()带参数写法
# super(B, self).__init__()
# super(B, self).info_print()
# 2.2 super()无参数写法
super().__init__()
super().info_print()
class Laifu(B):
def __init__(self):
self.num = "梁来福"
# 定义私有属性
self.__money = 20000000000
def info_print(self):
print(f"我是{self.num}")
# 定义函数:获取私有属性值
def get_money(self):
return self.__money
# 定义函数:修改私有属性值
def set_money(self):
self.__money = 500
# 定义私有方法
def __info_print(self):
print("这是私有方法")
# 子类调用父类的同名方法和属性
def a_info_print(self):
# 调用父类方法,为保证调用到的也是父类的属性,必须在调用方法前调用父类的初始化
A.__init__(self)
A.info_print(self)
def b_info_print(self):
B.__init__(self)
B.info_print(self)
# 需求:一次性调用父类A和B的方法
def new_info_print(self):
# 方法一:代码冗余;父类类名如果变化,这里代码需要频繁修改
#B.__init__(self)
#B.info_print(self)
#A.__init__(self)
#A.info_print(self)
# 方法二:super()
# 方法2.1 带参数:super(当前类名, self).函数()
# super(Laifu, self).__init__()
# super(Laifu, self).info_print()
# 方法2.2 无参数:super
super().__init__()
super().info_print()
class Tusun(Laifu):
pass
lianglaifu = Tusun()
print(lianglaifu.get_money())
# 修改完私有属性再次打印
lianglaifu.set_money()
print(lianglaifu.get_money())
输出
20000000000
500