这里写目录标题
- 一、继承
- (一)mro和c3算法
- (二)py2和py3区别(了解即可)
- 二、内置函数补充
- (一)callable:是否可以在后面加括号执行
- (二)super():按照mro继承关系向上找成员
- (三)type():获取一个对象的类型
- (四)isinstance():判断对象是否是某个类或其子类的实例
- (五)issubclass():判断是否是某个类的子孙类
- 三、异常处理
- 四、反射
一、继承
继承存在的意义:将公共的方法提取到父类中,有利于增强代码的重用性。调用类中成员时应遵循:优先在自己所在的类中找,没有的话就去父类中找;吐过存在多个父类时,则先找左边的再找右边的。
(一)mro和c3算法
1、mro
如果类中存在继承关系,则可以通过mro()获取当前类的继承关系(找成员的顺序)。
class C():
pass
class B():
pass
class A(B, C):
pass
print(A.mro())#[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class 'object'>]
print(A.__mro__) #(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class 'object'>)
2、c3算法
对于上述这个继承关系来说,C3算法的计算规则是:
mro(A) = [A] + merge(mro(B), mro©, [B, C] )
接着要把B和C的继承关系填写出来
mro(A) = [A] +merge([B,object], [C,object], [B, C] )
C3算法是:先把先读取第一个B,然后查阅B和后面两个参数(C,object),[B, C] 里面除了第一个参数以外的其他参数(object和C)的关系,结果发现(object和C)中都不含B,所以就把B单独提取出来,并把其他参数中包含的B剔除。
mro(A) = [A] + [B] + merge(mro(object), mro(C,object), [C] )
接着按照算法的规则进行判别:
mro(A) = [A] + [B, C] + merge(mro(object), mro(object) )
mro(A) = [A] + [B, C, object]
mro(A) = [A, B, C, object]
mro(A) = [A, B, C]
mro(A) = [A] +mro(mro(B) +mro[C], [B, C])
mro(A) = [A] +mro([B], [C, D] , [B, C])
mro(A) = [A] +[B] + mro( [C, D] , [C])
mro(A) = [A] +[B, C]+ mro( [D] )
mro(A) = [A] +[B, C, D]
mro(A) = [A, B, C, D]
mro(A) = [A] +mro(mro(B) +mro[C], [B, C])
mro(A) = [A] +mro([B, D] , [C], [B, C])
mro(A) = [A] , [B], mro([D] , [C], [C])
mro(A) = [A] , [B, D], mro([C], [C])
**mro(A) = [A] , [B, D, C] **
**mro(A) = [A, B, D, C] **
mro(A) = [A] +mro(mro(B) +mro[C], [B, C])
mro(A) = [A], mro([B, D], [C, D], [B, C])
mro(A) = [A], [B], mro([D], [C, D], [C])
此时,我们就需要找D了,寻找其他参数中除了第一个参数以外的参数是否包含D,由于存在【C, D】,所以D不能提取出来,接着只能对比C,发现其他参数中不含有C,所以把C提出来
mro(A) = [A], [B, C], mro([D], [D])
**mro(A) = [A], [B, C, D] **
**mro(A) = [ A, B, C, D] **
mro(A) = [A], mro(mro(B), mro[C], mro[P], [B, C, P])
mro(B) = [B], mro(mro[D], mro[E], [D, E])
mro(D) = [D], mro(mro[G], mro[H], [G, H])
mro(D) = [D], mro([G], [H, K], [G, H])
mro(D) = [D], [G], mro([H,k], [H])
mro(D) = [D], [G, H], mro([k] ])
mro(D) = [D], [G, H, K ]
mro(D) = [D, G, H, K ]
mro(E) = E + mro(M)
mro(E) = [E, M]
mro(B) = [B], mro([D, G, H, K ], [E, M], [D, E])
mro(B) = [B], [D], mro([G, H, K ], [E, M], [E])
mro(B) = [B], [D, G], mro([H, K ], [E, M], [E])
mro(B) = [B], [D, G, H], mro([K], [E, M], [E])
mro(B) = [B], [D, G, H, K], mro([E, M], [E])
mro(B) = [B, D, G, H, K, E, M]
mro© =[C], mro(mro(E), mro(F), [E,F])
mro© =[C], mro([E, M], mro([F], mro[mor[M], mro[H], [M, H]), [E,F])
mro© =[C], mro([E, M], [F, M, N], [E,F])
mro© =[C], [E], mro([M], [F, M, N], [F])
mro© =[C], [E, F], mro([M], [M, N])
mro© =[C, E, F, M, N]
mro(A) = [A], mro([B, D, G, H, K, E, M], [C, E, F, M, N], [B, C, P])
mro(A) = [A], [B], mro([D, G, H, K, E, M], [C, E, F, M, N], [C, P])
mro(A) = [A], [B, D, G, H, K, C, E, F, M, N, H, P]
mro(A) = [A, B, D, G, H, K, C, E, F, M, N, P, object]
特别补充,继承父类关系:从左到右、深度优先,大小钻石,留住顶端
(二)py2和py3区别(了解即可)
在py2.2之前,只支持经典类(从左到右,深度优先,大小钻石,不留顶端),后来python希望所有类都默认继承object类,此时发现会有Bug,所以就再次创建了一个新式类支持这个功能:从左到右,深度优先,大小钻石,保留顶端。
在py2.2及之前,就有了经典类(不继承object)和新式类(直接或间接继承object)两种。
#经典类
class Foo():
pass
#新式类
class base(object):
pass
class Foo(base):
pass
最终在py3中丢弃了经典类,只保留了新式类。
二、内置函数补充
类方法:classmethod、 静态方法:statisticmethod、属性:property
(一)callable:是否可以在后面加括号执行
一般来说,可以加括号执行的有:函数、类和带有__call__方法的实例对象
#1、函数
def func():
pass
print(callable(func)) #True
#2、类
class Foo():
pass
print(callable(Foo)) #True
#3、类中具有__call__方法的对象
class Foo(object):
def __call__(self, *args, **kwargs):
pass
v1 = Foo()
print(callable(v1)) #True
(二)super():按照mro继承关系向上找成员
class Base(object):
def message(self, num):
print("Base.message", num)
class Foo(Base):
def message(self, num):
print("Foo.message", num)
super().message(num+100)
obj = Foo()
print(obj.message(1))
'''
Foo.message 1
Base.message 101
'''
根据上下述代码可以看出来,Foo类的父类是Base和Bar,先找到Base的父类中的message方法,执行该方法,由于有super方法,所以会向上找Base父类的message方法,但是由于这里的self是Foo()方法的实例对象,因此会向Foo()父类中找,Base方法没有,Bar方法中有message,于是继续调用Bar中的message方法。
class Base(object):
def message(self, num):
print("Base.message", num)
super().message(1000)
class Bar(object):
def message(self, num):
print("Bar.message", num)
class Foo(Base, Bar):
pass
obj = Foo()
print(obj.message(1))
'''
Base.message 1
Bar.message 1000
'''
应用场景:假设有一个类,他原本已经实现了某些功能,但我们想在原有代码基础上实现某些功能,此时就不必再次重写代码,只需要使用super()方法调用上游方法。
比如,我们可以改写字典中的get()函数功能:
info = dict()
info['name'] = "高宇星"
info['age'] = 18
print(info)
#{'name': '高宇星', 'age': 18}
value = info.get('age')
print(value) #18
#此时我们想在原有字典功能的基础上改写get功能
class Mydict(dict):
def get(self, k):
print("自定义功能")
return super().get(k)
info = Mydict()
info['name'] = "高宇星"
info['age'] = 18
print(info)
value = info.get('age')
print(value)
'''
自定义功能
18
'''
在实际开发的过程中,可以通过super()函数来寻找上游的方法。
(三)type():获取一个对象的类型
v1 = "高宇星今年18岁"
result = type(v1)
print(result)
#<class 'str'> 这里的str其实是类名称
#定义一个类
class Foo():
pass
#实例化一个对象
v3 = Foo()
#查询该对象的类型
print(type(v3))
#<class '__main__.Foo'>
(四)isinstance():判断对象是否是某个类或其子类的实例
class Top(object):
pass
class Base(Top):
pass
class Foo(Base):
pass
v_ = Foo()
print(isinstance(v_, Foo)) #True
print(isinstance(v_, Base))#True
print(isinstance(v_, Top)) #True
应用场景:简化代码
class Animal(object):
def run(self):
print("123456")
class Dog(Animal):
pass
class Cat(Animal):
pass
data_list = ['alex', Dog(), Cat(), 'root']
#在不使用isinstance方法时:
for item in data_list:
if type(item) == Cat:
item.run()
elif type(item) == Dog:
item.run()
else:
pass
#在使用isinstance函数时:
for item in data_list:
if isinstance(item, Animal):
item.run()
else:
pass
(五)issubclass():判断是否是某个类的子孙类
class Top(object):
pass
class Base(Top):
pass
class Foo(Base):
pass
print(issubclass(Foo, Top)) #True
print(issubclass(Foo, Base))#True
三、异常处理
当我们在执行代码时,可能会出现一些不可知的错误,当我们不想让它报错,继续执行下面的代码时,可以选择用异常处理来做。
while True:
url = input("请输入要下载的网页地址")
try:
res = requests.get(url=url)
except Exception as e:
print("请求失败的原因是:{}".format(str(e)))
with open('content.txt', mode='wb') as f:
f.write(res.content)
当运行无误时:
请输入要下载的网页地址http://www.baidu.com
请输入要下载的网页地址
当关掉网络再次运行时:
请求失败的原因是:HTTPConnectionPool(host='www.baidu.com', port=80): Max retries exceeded with url: / (Caused by NameResolutionError("<urllib3.connection.HTTPConnection object at 0x00000282B35E4520>: Failed to resolve 'www.baidu.com' ([Errno 11001] getaddrinfo failed)"))
请输入要下载的网页地址