活动地址:CSDN21天学习挑战赛
学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。各位小伙伴,如果您:
想系统/深入学习某技术知识点…
一个人摸索学习很难坚持,想组团高效学习…
想写博客但无从下手,急需写作干货注入能量…
热爱写作,愿意让自己成为更好的人…
目录
一、私有化
xxx:公有变量
_x:前置下划线,私有属性或方法,from somemodule import*禁止导入,但在类对象和子类里面可以访问
__xx:双前置下划线,避免与子类中的属性命名冲突,无法在外部直接访问(名字重整所以访问不到)
__xx__:双前后下划线,用户名字空间的魔法对象或属性。如__init__
xx_:单后置下划线,用于避免与python关键词的冲突
a.访问私有属性
class Test:
def __init__(self):
self.__name = "zzh"
x = Test()
print(x._Test__name) # zzh---访问私有属性的方法
总结: _类名__属性名
二、import导入模式
from 模块 import 类
import 模块
from 模块 import *
import 模块1, 模块2
from 模块 import 类1,类2
import 模块 as 给模块起名字 # 如:import tkinter as tk
a.获取import的导入顺序
import sys
a = sys.path
print(a)
"""
['D:\\python学习\\就业班\\06.私有属性、封装继承多态',
'D:\\python学习\\就业班',
'D:\\python学习\\python解释器3.10\\python310.zip',
'D:\\python学习\\python解释器3.10\\DLLs',
'D:\\python学习\\python解释器3.10\\lib',
'D:\\python学习\\python解释器3.10',
'D:\\python学习\\python解释器3.10\\lib\\site-packages']
"""
b.向列表添加搜索路径
import sys
sys.path.append('/home/itcast/xxx') # 路径添加到最后面
sys.path.insert(0, '/home/itcast/xxx') # 可以确保先搜索这个路径,优先搜索
a = sys.path
print(a)
"""
['/home/itcast/xxx',
'D:\\python学习\\就业班\\04.python高级语法知识\\3.私有属性、封装继承多态',
'D:\\python学习\\就业班',
'D:\\python学习\\python解释器3.10\\python310.zip',
'D:\\python学习\\python解释器3.10\\DLLs',
'D:\\python学习\\python解释器3.10\\lib',
'D:\\python学习\\python解释器3.10',
'D:\\python学习\\python解释器3.10\\lib\\site-packages',
'/home/itcast/xxx']
"""
c.对于多个模块导入的注意点
对于模块来说本质上是数据共享,想改变模块的数据并把改变的数据进行共享要注意的核心点还是要明白你通过这个方法是改变了指向没有
三、再议封装继承多态
python里面的类里面的方法的self只是一个形参,它对于面向对象的好处:面向对象相当于有一个模板共享里面的函数代码只是数据进行改变
a.多继承中的MRO顺序
print("******多继承使用类名.__init__ 发生的状态******")
class Parent(object):
def __init__(self, name):
print('parent的init开始被调用')
self.name = name
print('parent的init结束被调用')
class Son1(Parent):
def __init__(self, name, age):
print('Son1的init开始被调用')
self.age = age
Parent.__init__(self, name)
print('Son1的init结束被调用')
class Son2(Parent):
def __init__(self, name, gender):
print('Son2的init开始被调用')
self.gender = gender
Parent.__init__(self, name)
print('Son2的init结束被调用')
class Grandson(Son1, Son2):
def __init__(self, name, age, gender):
print('Grandson的init开始被调用')
Son1.__init__(self, name, age) # 单独调用父类的初始化方法
Son2.__init__(self, name, gender)
print('Grandson的init结束被调用')
gs = Grandson('grandson', 12, '男')
print('姓名:', gs.name)
print('年龄:', gs.age)
print('性别:', gs.gender)
print("******多继承使用类名.__init__ 发生的状态******\n\n")
"""
******多继承使用类名.__init__ 发生的状态******
Grandson的init开始被调用
Son1的init开始被调用
parent的init开始被调用
parent的init结束被调用
Son1的init结束被调用
Son2的init开始被调用
parent的init开始被调用
parent的init结束被调用
Son2的init结束被调用
Grandson的init结束被调用
姓名: grandson
年龄: 12
性别: 男
******多继承使用类名.__init__ 发生的状态******
"""
每个子类都继承自父类导致父类多次调用此次方式导致占用资源过度浪费
最后的结果是每一个son类都会调用Pardent类的初始化方法,导致了资源的浪费。
print("******多继承使用super().__init__ 发生的状态******")
class Parent(object):
def __init__(self, name, *args, **kwargs): # 为避免多继承报错,使用不定长参数,接受参数
print('parent的init开始被调用')
self.name = name
print('parent的init结束被调用')
class Son1(Parent):
def __init__(self, name, age, *args, **kwargs): # 为避免多继承报错,使用不定长参数,接受参数
print('Son1的init开始被调用')
self.age = age
super().__init__(name, *args, **kwargs) # 为避免多继承报错,使用不定长参数,接受参数
# 直接调用<class '__main__.Son2'>,
print('Son1的init结束被调用')
class Son2(Parent):
def __init__(self, name, gender, *args, **kwargs): # 为避免多继承报错,使用不定长参数,接受参数
print('Son2的init开始被调用')
self.gender = gender
super().__init__(name, *args, **kwargs) # 为避免多继承报错,使用不定长参数,接受参数
print('Son2的init结束被调用')
class Grandson(Son1, Son2):
def __init__(self, name, age, gender):
print('Grandson的init开始被调用')
# 多继承时,相对于使用类名.__init__方法,要把每个父类全部写一遍
# 而super只用一句话,执行了全部父类的方法,这也是为何多继承需要全部传参的一个原因
# super(Grandson, self).__init__(name, age, gender)
super().__init__(name, age, gender) # 直接跳到调用<class '__main__.Son1'>,
print('Grandson的init结束被调用')
gs = Grandson('grandson', 12, '男')
print('姓名:', gs.name)
print('年龄:', gs.age)
print('性别:', gs.gender)
print("******多继承使用super().__init__ 发生的状态******\n\n")
# super()避免了重复调用最顶尖的类
# super(Grandson, self).__init__(name, age, gender)拿到Grandson去找其子类进行调用
# super().__init__(name, age, gender)调用本类的下一个
1>结果
******多继承使用super().__init__ 发生的状态******
Grandson的init开始被调用
Son1的init开始被调用
Son2的init开始被调用
parent的init开始被调用
parent的init结束被调用
Son2的init结束被调用
Son1的init结束被调用
Grandson的init结束被调用
姓名: grandson
年龄: 12
性别: 男
******多继承使用super().__init__ 发生的状态******
2>讲解
print(Grandson.__mro__)
# 当在一个类里面调用super()的时候会有mro算法计算调用哪个父类,调用本类的下一个
"""
(<class '__main__.Grandson'>,<class '__main__.Son1'>,<class '__main__.Son2'<class '__main__.Parent'>,<class 'object'>)
"""所以从以上的结果来看先调用Son1再调用Son2最后调用Partent
3>总结
super()避免了重复调用最顶端的代码,节省了资源
super().__init__(name, age, gender)调用本类的下一个类里面的__init__方法
多继承时,相对于使用类名.__init__方法,要把每个父类全部写一遍
而super只用一句话,执行了全部父类的方法,这也是为何多继承需要全部传参的一个原因。
b.单继承里面的ROM
print("******单继承使用super().__init__ 发生的状态******")
class Parent(object):
def __init__(self, name):
print('parent的init开始被调用')
self.name = name
print('parent的init结束被调用')
class Son1(Parent):
def __init__(self, name, age):
print('Son1的init开始被调用')
self.age = age
super().__init__(name) # 单继承不能提供全部参数
print('Son1的init结束被调用')
class Grandson(Son1):
def __init__(self, name, age, gender):
print('Grandson的init开始被调用')
super().__init__(name, age) # 单继承不能提供全部参数
print('Grandson的init结束被调用')
gs = Grandson('grandson', 12, '男')
print('姓名:', gs.name)
print('年龄:', gs.age)
# print('性别:', gs.gender)
print("******单继承使用super().__init__ 发生的状态******\n\n")
1>结果
"""
******单继承使用super().__init__ 发生的状态******
Grandson的init开始被调用
Son1的init开始被调用
parent的init开始被调用
parent的init结束被调用
Son1的init结束被调用
Grandson的init结束被调用
姓名: grandson
年龄: 12
******单继承使用super().__init__ 发生的状态******
"""
四、拆包
def test1(a, b, *args, **kwargs):
print("-----1------")
print(a)
print(b)
print(args)
print(kwargs)
def test(a, b, *args, **kwargs):
print(a)
print(b)
print(args)
print(kwargs)
test1(a, b, *args, **kwargs)
test(11, 22, 33, 44, 55, name="zzh", age=18)
"""
11
22
(33, 44, 55)
{'name': 'zzh', 'age': 18}
"""
a、b分别拆出11和22,*args其余的数值以元组的形式打包,**kwargs将有key和value的以字典形式打包
五、面试题
以下代码会输出什么
class Parent(object):
x = 1 # 类属性class Child1(Parent):
passclass Child2(Parent):
passprint(Parent.x, Child1.x, Child2.x)
Child1.x = 2 # 对1添加一个类属性
print(Parent.x, Child1.x, Child2.x)
Parent.x = 3 # 对父类的进行更改
print(Parent.x, Child1.x, Child2.x)
a.结果
1 1 1
1 2 1
3 2 3
b.分析
第一个print(Parent.x, Child1.x, Child2.x)时因为只有Parent有x类属性,而Child1、Child2继承自Parent类所以首先在Child1、Child2里面找不到x属性就自动往其父类找并打印
第二个print(Parent.x, Child1.x, Child2.x)时因为在其之前对Child1进行定义了x类方法,所以在Child1里面找到了就不会继续往其父类寻找,而Child2依然找父类
第三个因为Parent.x导致Child2.x时访问父类的也跟着更改了
六、结束语
这个礼拜忙于考驾驶证,不过索性是考完了,之后可以安心学一会了。
一起追寻梦想哈!