面对对象二,super......反射
一.super()
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 包含了两个非常重要的信息: 一个 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多继承图解:
二,特殊成员
相应语法对应
# __doc__ 输出类的描述(注释)信息 # __module__ 表示当前操作的对象在那个模块 # __class__ 表示当前操作的对象的类是什么 class C: def __init__(self): self.name = 'zwq' from lib.aa import C obj = C() print obj.__module__ # 输出 lib.aa,即:输出模块 print obj.__class__ # 输出 lib.aa.C,即:输出类 # __init__ 构造方法,通过类创建对象时,自动触发执行。 # __del__ 析构方法,当对象在内存中被释放时,自动触发执行。一般无须定义,由解释器在进行垃圾回收时自动触发执行的 # __call__ 将对象变为可调用对象; 对象后面加括号,触发执行。 # __dict__ 类或对象中的所有成员 # __str__ 如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。 # __getitem__、__setitem__、__delitem__ # 用于索引操作,如字典。以上分别表示获取、设置、删除# 数据 # __getslice__、__setslice__、__delslice__ 该三个方法用于分片操作 # __iter__ 用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 __iter__ # __new__ 和 __metaclass__ # __enter__ ,__exit__ with 对象 自动执行__enter__ / __exit__
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(obj,"func") # 根据字符串的形式,去判断对象中是否有该成员。 setattr(obj,"name","ZWQ") # 根据字符串的形式,动态的设置一个成员(内存) delattr(类,"func") # 根据字符串的形式,动态的删除一个成员(内存)
from types import FunctionType import handler while True: print(""" 系统支持的函数有: 1. f1 2. f2 3. f3 4. f4 5. f5 """) val = input("请输入要执行的函数:") # val = "f1" # 错误 # handler.val() if hasattr(handler,val): func_or_val = getattr(handler,val) # 根据字符串为参数,去模块中寻找与之同名的成员。 if isinstance(func_or_val,FunctionType): func_or_val() else: print(func_or_val) else: print('handler中不存在输入的属性名')
class Foo(object): country = "中国" def func(self): pass v = getattr(Foo,'func') # Foo.func # 根据字符串为参数,去类中寻找与之同名的成员。 print(v) obj = Foo() v = getattr(obj,"func") # obj.func # 根据字符串为参数,去对象中寻找与之同名的成员。 print(v)
class Account(object): func_list = ['login', 'logout', 'register'] def login(self): """ 登录 :return: """ print('登录111') def logout(self): """ 注销 :return: """ print('注销111') def register(self): """ 注册 :return: """ print('注册111') def run(self): """ 主代码 :return: """ print(""" 请输入要执行的功能: 1. 登录 2. 注销 3. 注册 """) choice = int(input('请输入要执行的序号:')) func_name = Account.func_list[choice-1] # func = getattr(Account,func_name) # Account.login # func(self) # 执行这个函数要传参数,传self func = getattr(self, func_name) # self相当于对象可以直接传self相当于self.login func() obj1 = Account() obj1.run() obj2 = Account() obj2.run()
六,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