一.super()
# 单继承 # 在单继承中 super 就像大家所想的那样,主要是用来调用父类的方法的。 class A: def __init__(self): self.n = 2 def add(self, m): print('self is {0} @A.add'.format(self)) self.n += m class B(A): def __init__(self): self.n = 3 def add(self, m): print('self is {0} @B.add'.format(self)) super().add(m) self.n += 3 # 执行下面代码后, b.n 的值是多少呢? b = B() b.add(2) print(b.n) # 执行结果如下: # self is <__main__.B object at 0x106c49b38> @B.add # self is <__main__.B object at 0x106c49b38> @A.add # 8 """这个结果说明了两个问题: super().add(m) 确实调用了父类 A 的 add 方法。 super().add(m) 调用父类方法 def add(self, m) 时, 此时父类中 self 并不是父类的实例而是子类的实例, 所以b.add(2) 之后的结果是 5 而不是 4 。 不知道这个结果是否和你想到一样呢?下面我们来看一个多继承的例子。""" # 多继承 # 这次我们再定义一个 class C,一个 class D: class C(A): def __init__(self): self.n = 4 def add(self, m): print('self is {0} @C.add'.format(self)) super().add(m) self.n += 4 class D(B, C): def __init__(self): self.n = 5 def add(self, m): print('self is {0} @D.add'.format(self)) super().add(m) self.n += 5 # 下面的代码又输出啥呢? d = D() d.add(2) print(d.n) # 这次的输出如下: # self is <__main__.D object at 0x10ce10e48> @D.add # self is <__main__.D object at 0x10ce10e48> @B.add # self is <__main__.D object at 0x10ce10e48> @C.add # self is <__main__.D object at 0x10ce10e48> @A.add # 19
super 是个类
当我们调用 super() 的时候,实际上是实例化了一个 super 类。你没看错, super 是个类,既不是关键字也不是函数等其他数据结构:
>>> class A: pass
...
>>> s = super(A)
>>> type(s)
<class 'super'>
>>>
在大多数情况下, super 包含了两个非常重要的信息: 一个 MRO 以及 MRO 中的一个类。当以如下方式调用 super 时:
super(a_type, obj)
MRO 指的是 type(obj) 的 MRO, MRO 中的那个类就是 a_type , 同时 isinstance(obj, a_type) == True 。
当这样调用时:
super(type1, type2)
MRO 指的是 type2 的 MRO, MRO 中的那个类就是 type1 ,同时 issubclass(type2, type1) == True 。
那么, super() 实际上做了啥呢?简单来说就是:提供一个 MRO 以及一个 MRO 中的类 C , super() 将返回一个从 MRO 中 C 之后的类中查找方法的对象。
也就是说,查找方式时不是像常规方法一样从所有的 MRO 类中查找,而是从 MRO 的 tail 中查找。
举个栗子, 有个 MRO:
[A, B, C, D, E, object]
下面的调用:
super(C, A).foo()
super 只会从 C 之后查找,即: 只会在 D 或 E 或 object 中查找 foo 方法。
supper多继承图解:
二,特殊成员
class Foo(object): def __init__(self,a1,a2): self.a1 = a1 self.a2 = a2 def __call__(self, *args, **kwargs): print(11111,args,kwargs) return 123 def __getitem__(self, item): print(item) return 8 def __setitem__(self, key, value): print(key,value,111111111) def __delitem__(self, key): print(key) def __add__(self, other): return self.a1 + other.a2 def __enter__(self): print('1111') return 999 def __exit__(self, exc_type, exc_val, exc_tb): print('22222') # 1. 类名() 自动执行 __init__ # obj = Foo(1,2) # 2. 对象() 自动执行 __call__ # ret = obj(6,4,2,k1=456) # 3. 对象['xx'] 自动执行 __getitem__ # ret = obj['yu'] # print(ret) # 4. 对象['xx'] = 11 自动执行 __setitem__ # obj['k1'] = 123 # 5. del 对象[xx] 自动执行 __delitem__ # del obj['uuu'] # 6. 对象+对象 自动执行 __add__ # obj1 = Foo(1,2) # obj2 = Foo(88,99) # ret = obj2 + obj1 # print(ret) # 7. with 对象 自动执行 __enter__ / __exit__ # obj = Foo(1,2) # with obj as f: # print(f) # print('内部代码')
三,构造方法
class Foo(object): def __init__(self, a1, a2): # 初始化方法 """ 为空对象进行数据初始化 :param a1: :param a2: """ self.a1 = a1 self.a2 = a2 def __new__(cls, *args, **kwargs): # 构造方法 """ 创建一个空对象 :param args: :param kwargs: :return: """ return object.__new__(cls) # Python内部创建一个当前类的对象(初创时内部是空的.). obj1 = Foo(1,2) print(obj1) obj2 = Foo(11,12) print(obj2)
四,isinstance(obj,cls), issubclass(sub,super)和type;
isinstance(obj,cls)
检查第一个参数(对象)是否是第二个参数(类及父类)的实例。
class Base(object): pass class Foo(Base): pass obj1 = Foo() print(isinstance(obj1,Foo)) # 检查第一个参数(对象)是否是第二个参数(类及父类)的实例。 print(isinstance(obj1,Base)) # 检查第一个参数(对象)是否是第二个参数(类及父类)的实例。
issubclass(sub,super)
检查sub类是否是 super 类的派生类
issubclass class Base(object): pass class Foo(Base): pass class Bar(Foo): pass print(issubclass(Bar,Base)) # 检查第一个参数是否是第二个参数的 子子孙孙类
type:
type:获取当前对象是由那个类创建。 """ class Foo(object): pass obj = Foo() print(obj,type(obj)) # 获取当前对象是由那个类创建。 if type(obj) == Foo: print('obj是Foo类型') """
五,反射
1 什么是反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念
的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。
2 python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
四个可以实现自省的函数
下列方法适用于类和对象(一切皆对象,类本身也是一个对象)
#记忆: getattr # 根据字符串的形式,去对象中找成员。 ###
v = getattr(obj,"func") # 根据字符串为参数(第二个参数),去对象(第一个参数)中寻找与之同名的成员。
hasattr # 根据字符串的形式,去判断对象中是否有成员。
setattr # 根据字符串的形式,动态的设置一个成员(内存)
delattr # 根据字符串的形式,动态的删除一个成员(内存)
六,callable(x) 检查x是否是可调用的
def func(): pass class Foo(object): def __call__(self, *args, **kwargs): pass def func(self): pass obj = Foo() print(callable(func)) #True print(callable(Foo)) #True print(callable(obj)) #True print(callable(obj.func)) #True