面向对象进阶

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()

 

构造方法,通过类创建对象时,自动触发执行。

posted @ 2018-08-07 00:03  R00M  阅读(139)  评论(0编辑  收藏  举报