面向对象进阶
isinstance和issubclass
isinstance(obj,cls)检查是否obj是否是类 cls 的对象
class Foo(object): pass obj = Foo() isinstance(obj, Foo)
issubclass(sub, super)检查sub类是否是 super 类的派生类
class Foo(object): pass class Bar(Foo): pass issubclass(Bar, Foo)
反射
python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
hasattr
class Foo: f = '类的静态变量' def __init__(self,name,age): self.name=name self.age=age def say_hi(self): print('hi,%s'%self.name) obj=Foo('egon',73)
#检测是否含有某属性 print(hasattr(obj,'name')) print(hasattr(obj,'say_hi'))
getattr
#获取属性 n=getattr(obj,'name') print(n) func=getattr(obj,'say_hi') func()
setattr
#设置属性 setattr(obj,'sb',True) setattr(obj,'show_name',lambda self:self.name+'sb') print(obj.__dict__) print(obj.show_name(obj))
delattr
#删除属性 delattr(obj,'age') delattr(obj,'show_name') delattr(obj,'show_name111')#不存在,则报错
类对象
class Foo(object): staticField = "old boy" def __init__(self): self.name = 'wupeiqi' def func(self): return 'func' @staticmethod def bar(): return 'bar' print getattr(Foo, 'staticField') print getattr(Foo, 'func') print getattr(Foo, 'bar')
模块也可以用反射,获取相应的类或者函数等.
双下划线的特殊方法
__doc__
表示类的描述信息
class Foo: """ 描述类信息,这是用于看片的神奇 """ def func(self): pass print Foo.__doc__ #输出:类的描述信息
__module__ 和 __class__
__module__ 表示当前操作的对象在那个模块
__class__ 表示当前操作的对象的类是什么
#!/usr/bin/env python # -*- coding:utf-8 -*- class C: def __init__(self): self.name = 'wupeiqi' from lib.aa import C obj = C() print obj.__module__ # 输出 lib.aa,即:输出模块 print obj.__class__ # 输出 lib.aa.C,即:输出类
__new__方法
- 在实例化对象的时候会先执行__new__方法
- __new__方法返回一个类代表需要实例化的对象
class Bar(object): pass class Foo(object): def __new__(cls, *args, **kwargs): # 执行父类的__new__ 返回该的对象 return super(Foo,cls).__new__(cls,*args, **kwargs) # 直接返回Bar类的对象,那么obj实例化后是Bar类的一个对象 return Bar() def __int__(self): pass obj = Foo() print(obj)
可对该类进行封装到另外一个类中
比如将Foo类封装到Bar类
class Bar(object): def __init__(self,cls): self.cls = cls class Foo(object): def __new__(cls, *args, **kwargs): #cls 是Foo类 return Bar(cls) obj = Foo() print(obj)
- 在restframework里边的序列化,通过参数many=True 或者False 返回不同的类对象去序列化
- 在Wtform中,字段的类都被封装到了同一个类中(UnboundField)
- 可以做单例模式 (在restfromwork有写过)
__init__
构造方法,通过类创建对象时,自动触发执行。
class Foo: def __init__(self, name): self.name = name self.age = 18 obj = Foo('wupeiqi') # 自动执行类中的 __init__ 方法
__del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
class Foo: def __del__(self): pass
__call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class Foo: def __init__(self): pass def __call__(self, *args, **kwargs): print '__call__' obj = Foo() # 执行 __init__ obj() # 执行 __call__
- flask源码请求入口,django请求入口(WSGIHandler.__call__)
__dict__
类或对象中的所有成员
上文中我们知道:类的普通字段属于对象;类中的静态字段和方法等属于类,即
class Province: country = 'China' def __init__(self, name, count): self.name = name self.count = count def func(self, *args, **kwargs): print 'func' # 获取类的成员,即:静态字段、方法、 print Province.__dict__ # 输出:{'country': 'China', '__module__': '__main__', 'func': <function func at 0x10be30f50>, '__init__': <function __init__ at 0x10be30ed8>, '__doc__': None} obj1 = Province('HeBei',10000) print obj1.__dict__ # 获取 对象obj1 的成员 # 输出:{'count': 10000, 'name': 'HeBei'} obj2 = Province('HeNan', 3888) print obj2.__dict__ # 获取 对象obj1 的成员 # 输出:{'count': 3888, 'name': 'HeNan'}
api封装返回数据的时候,BaseResponse
__str__
如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。
class Foo: def __str__(self): return 'wupeiqi' obj = Foo() print obj # 输出:wupeiqi
__getitem__、__setitem__、__delitem__
用于索引操作,如字典。以上分别表示获取、设置、删除数据
#!/usr/bin/env python # -*- coding:utf-8 -*- class Foo(object): def __getitem__(self, key): print '__getitem__',key def __setitem__(self, key, value): print '__setitem__',key,value def __delitem__(self, key): print '__delitem__',key obj = Foo() result = obj['k1'] # 自动触发执行 __getitem__ obj['k2'] = 'wupeiqi' # 自动触发执行 __setitem__ del obj['k1'] # 自动触发执行 __delitem__
__getattr__ __setattr____delattr__
- __getattr__
- 在obj对象取值的时候会触发getattr方法 obj.xxx
- __setattr__
- 在给对象设置值的时候会触发该方法
- 注意: 在__init__初始会的时候会触发setattr,如果需要重新定制setattr,需要保持__init__能够正常执行
class Foo(object): def __init__(self,name): self.name=name def __getattr__(self, item): return self[item] def __setattr__(self, key, value): self.__dict__[key] = value obj=Foo('ming') obj.xx=123 print(obj.xx) #123 print(obj.name) #ming
当在__setattr__方法内对属性进行赋值是,不可使用self.attr = value,因为他会再次调用self,__setattr__("attr", value),则会形成无穷递归循环,最后导致堆栈溢出异常。应该通过对属性字典做索引运算来赋值任何实例属性,也就是使用self.__dict__['name'] = value.
用途:
- 在restframework的APIview类中,用__getattr__来获取配置文件的信息
- 在Flask上下文管理中,Local对象通过__getattr__对存储数据的字典进行赋值
__mro__
查看类的继承顺序
class Foo(object): def __init__(self): self.name='ming' class Foo1(object): def __init__(self): self.name='ming1' class Mycls(Foo,Foo1): name='haha' print(Mycls.__mro__)#(<class '__main__.Mycls'>, <class '__main__.Foo'>, <class '__main__.Foo1'>, <class 'object'>)
__iter__
- 构造对象可以被for循环
- 用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 __iter__
条件:
- 类里面有__iter__方法
- __iter__里面返回一个迭代对象
class Foo(object): # def __iter__(self): # return iter([11,22,33]) def __iter__(self): yield 1 yield 2 yield 3 obj = Foo() for item in obj: print(item)
class Foo(object): def __init__(self, sq): self.sq = sq def __iter__(self): return iter(self.sq) obj = Foo([11,22,33,44]) for i in obj: print i
metaclass
类创建的两种方式
#常用方式 class Foo(object): a1 = 123 def func(self): return 666 #type方式 Foo = type("Foo",(object,),{'a1':123,'func':lambda self:666}
自定义type
class MyType(type): pass class Foo(object,metaclass=MyType): a1 = 123 def func(self): return 666 Foo = MyType("Foo",(object,),{'a1':123,'func':lambda self:666}) # 注意:metaclass作用是指定当前类由谁来创建。
metaclass执行流程
- 类在创建的时候执行type的__init__方法
- 类在实例化的时候会执行type的__call__方法....__call__方法的返回值就是实例化的对象
class MyType(type): def __init__(self,*args,**kwargs): super(MyType,self).__init__(*args,**kwargs) def __call__(cls, *args, **kwargs): obj = cls.__new__(cls) cls.__init__(obj,*args, **kwargs) return obj class Foo(object,metaclass=MyType): a1 = 123 def __init__(self): pass def __new__(cls, *args, **kwargs): return object.__new__(cls) def func(self): return 666 # Foo是类 # Foo是MyType的一个对象 obj = Foo()
构造方法,通过类创建对象时,自动触发执行。