假期(面向对象相关)

"""
一、isinstance(obj,cls) 和 issubclass(sub,super)
    isinstance(obj,cls) 检查obj是否是类cls的对象
        class Bar(object):
            pass
        class Foo(object):
            pass
        obj = Foo()
        print(isinstance(obj,Foo))     #True
        print(isinstance(obj,Bar))     #False
    issubclass(sub,super) 检查sub类是否是super类的子类(派生类)
        class Bar(object):
            pass
        class Foo(Bar):
            pass
        class Te(object):
            pass
        print(issubclass(Foo,Bar))    #True
        print(issubclass(Te,Bar))     #False
"""
"""
二、反射:通过字符串的方式操作对象相关的属性,python中的一切事物都是对象,都可以使用反射
    hasattr(object,name) 判断object中有没有一个name字符串对应的方法或者是属性
    getattr(object,name,default=None)  从object中获取name属性,如果没有返回默认值None
    setattr(obj,x,y) 给obj对象设置属性x=y
    delattr(obj,x) 删除对象obj里的x属性
    类也是对象,也可以有这四个方法
    使用方法测试:
        class Foo(object):
            name = "我是你的什么啊?"
            def __init__(self,addr):
                self.addr = addr
        obj = Foo("去你大爷的")
        print(hasattr(obj,"name"))    #True
        print(getattr(obj,"name"))    #我是你的什么啊?
        setattr(obj,"sb",True)
        print(obj.__dict__)           #{'addr': '去你大爷的', 'sb': True}
        delattr(obj,"sb")
        print(obj.__dict__)           #{'addr': '去你大爷的'}
        反射当前模块成员:
            import sys
            def s1():
                print("s1")
            def s2():
                print("s2")
            this_module = sys.modules[__name__]
            print(hasattr(this_module,"s1"))
    使用反射的好处:
        实现代码的可插拔机制;在导入模块方面经常使用反射;动态的导入模块
        
三、__setattr__,__delattr__,__getattr__;
    #__setattr__添加/修改属性会触发它的执行
    #__delattr__删除属性的时候会触发
    #__getattr__只有在使用点调用属性且属性不存在的时候才会触发

四、二次加工标准类型(包装)
    class List(list): #继承list所有的属性,也可以派生出自己新的,比如append和mid
    def append(self, p_object):
        ' 派生自己的append:加上类型检查'
        if not isinstance(p_object,int):
            raise TypeError('must be int')
        super().append(p_object)        #调用父类的append方法
    @property
    def mid(self):
        '新增自己的属性'
        index=len(self)//2
        return self[index]
    实现授权的关键点就是覆盖__getattr__方法
    import time
    class FileHandle:
        def __init__(self,filename,mode='r',encoding='utf-8'):
            self.file=open(filename,mode,encoding=encoding)
        def write(self,line):
            t=time.strftime('%Y-%m-%d %T')
            self.file.write('%s %s' %(t,line))
    
        def __getattr__(self, item):
            return getattr(self.file,item)
    
    f1=FileHandle('b.txt','w+')
    f1.write('你好啊')
    f1.seek(0)
    print(f1.read())
    f1.close()
        
五、__getattribute__:        
    和__getattr__类似,不过不管是否存在都会执行
    class Foo:
        def __init__(self,x):
            self.x = x
        def __getattribute__(self, item):
            print("我总会执行")
    obj = Foo(10)
    print(obj.x)
    print(obj.xxx)
    !当getattr和getattribute同事存在的时候只执行getattribute,除非抛出异常,两者一起执行
    
六、描述符(__get__,__set__,__delete__):
    什么是描述符:描述符的本质就是一个新式类,在这个新式类中至少实现了__get__(),__set__(),__delete__()中的一个
                这也被称为描述符协议
    __get__():调用一个属性的时候触发
    __set__():为一个属性赋值的时候触发
    __delete__():删除属性的时候触发
        class Foo:   #这个类称为描述符
            def __get__(self, instance, owner):
                pass
            def __set__(self, instance, value):
                pass
            def __delete__(self, instance):
                pass
    描述符的作用:用来代理另外一个类的属性(必须把描述符定义为这个类的类属性,不能定义到构造方法中)
    分类:
        数据描述符:至少实现了__get__() 和__set__()方法
        非数据描述符:没有实现__set__()方法
    注意事项:
        1、描述符本身应该定义为新式类,被代理的类也应该是新式类
        2、必须定义为类属性,不能定义到构造函数中
        3、要严格遵循优先级,优先级由高到低分别是(类属性,数据描述符,实例属性,非数据描述符,找不到的时候触发__getattr__())
    描述符的使用:
    描述符的总结:
    
六、property:
    一个静态属性property本质就实现了get,set,delete三种方法
    用法一:
        class Foo:
            @property
            def AAA(self):
                print("get的时候运行")
            @AAA.setter
            def AAA(self,value):
                print("set的时候运行",value)
            @AAA.deleter
            def AAA(self):
                print("delete 的时候运行")
        obj = Foo()
        obj.AAA  #get
        obj.AAA = "aaa"   #set
        del obj.AAA    #delete
    用法二:
        class Foo:
            def get_AAA(self):
                print("get的时候yunx")
            def set_AAA(self,value):
                print("set 的时候运行")
            def delete_AAA(self):
                print("delete的时候运行")
            AAA=property(get_AAA,set_AAA,delete_AAA)    #内置的property三个参数必须与get,set,delete一一对应

七、__setitem__,__getitem__,__delitem__:
    示例代码;
        class Foo:
            def __init__(self,name):
                self.name = name
            def __getitem__(self, item):
                print(self.__dict__[item])
            def __setitem__(self, key, value):
                self.__dict__[key] = value
            def __delitem__(self, key):
                print("del obj 时执行")
            def __delattr__(self, item):
                print("del obj 执行,")
                self.__dict__.pop(item)
        obj = Foo("sb")
        obj["age"] = 18
        obj["age1"] = 19
        del obj.age1
        del obj["age"]
        obj["name"] = "alex"
        print(obj.__dict__)
        
八、__str__,__repr__,__format__:
    改变对象的字符串显示__str__,__repr__,当你打印对象的时候假如里面没有这两个方法,那么打印出来的你是看不懂的
    自定义格式化字符串:__format__    
        str函数或者print函数--->obj.__str__()
        repr或者交互式解释器--->obj.__repr__()
        如果__str__没有被定义,那么就会使用__repr__来代替输出
        注意:这俩方法的返回值必须是字符串,否则抛出异常    
            - 示例:
            format_dict={
                'nat':'{obj.name}-{obj.addr}-{obj.type}',#学校名-学校地址-学校类型
                'tna':'{obj.type}:{obj.name}:{obj.addr}',#学校类型:学校名:学校地址
                'tan':'{obj.type}/{obj.addr}/{obj.name}',#学校类型/学校地址/学校名
            }
            class School:
                def __init__(self,name,addr,type):
                    self.name=name
                    self.addr=addr
                    self.type=type
            
                def __repr__(self):
                    return 'School(%s,%s)' %(self.name,self.addr)
                def __str__(self):
                    return '(%s,%s)' %(self.name,self.addr)
            
                def __format__(self, format_spec):
                    if not format_spec or format_spec not in format_dict:
                        format_spec='nat'
                    fmt=format_dict[format_spec]
                    return fmt.format(obj=self)
            s1=School('oldboy1','北京','私立')
            print('from repr: ',repr(s1))
            print('from str: ',str(s1))
            print(s1)
            
            print(format(s1,'nat'))
            print(format(s1,'tna'))
            print(format(s1,'tan'))
            print(format(s1,'asfdasdffd'))    
        
九、__slots__:
    在类中写一个slots,在吧类中的某些字段写在里面,外部才可以访问,不写访问不到
    
十、__next__和__iter__实现迭代器协议    
    模拟实现range方法:
        class Range:
            def __init__(self,n,stop,step):
                self.n=n
                self.stop=stop
                self.step=step
        
            def __next__(self):
                if self.n >= self.stop:
                    raise StopIteration
                x=self.n
                self.n+=self.step
                return x
        
            def __iter__(self):
                return self
        
        for i in Range(1,7,3): #
            print(i)
        
十一、__doc__
    - 显示描述信息,即注释信息
    - 无法被继承

十二、__module__和__class__
    - __module__  表示当前操作的对象在哪个摸快
    - __class__表示当前操作的对象的类是什么
    
十三、__del__:
    - 析构方法:当对象在内存中被释放时执行这段代码
    - 比如在数据库链接中关闭数据库,文件操作中的close操作
    
十四、__enter__和__exit__:
    __enter__在进来的时候执行
    __exit__在出去的时候执行
        - 对象调用前后执行这两个方法
        
十五、__call__方法:
    - 对象后边+括号自动触发执行
    - 构造方法的执行是由创建对象触发的,即对象=类名();而对于__call__方法是对象()或者类()()
    
十六、metaclass
    exec:三个参数       字符串形式的命令  全局作用域  局部作用域
    exec会在指定的局部作用域内执行字符串内的代码,除非明确地使用global关键字
    - 类也是对象
    - 什么是元类
        - 元类是类的类,类的模板
        - 元类是用来控制如何创建类的,正如类是创建对象的模板一样,而元类的主要目的是为了控制类的创建行为元类的实例化的结
          果为我们用class定义的类,正如类的实例为对象(f1对象是Foo类的一个实例,Foo类是 type 类的一个实例)type是python的一
          个内建元类,用来直接控制生成类,python中任何class定义的类其实都是type类实例化的对象
    - 创建类的两张方式:
        - 方式一:使用class关键字
        - 方式二:手动模拟class创建类的过程
            - 类名
            - 类的父类
            - 类体
                #类名
                class_name='Chinese'
                #类的父类
                class_bases=(object,)
                #类体
                class_body=
                country='China'
                "
                def __init__(self,name,age):
                    self.name=name
                    self.age=age
                def talk(self):
                    print('%s is talking' %self.name)
                "
    - 一个类没有声明自己的元类,默认它的元类就是type,除了使用元类type,用户也可以通过继承type俩自定义元类
    - #元类控制类的实例化过程:
            1 类(),调用元类.__call__()
            2 在1的方法中调用:
                类.__new__() #返回类的对象obj
                类.__init__(obj,...) #为对象进行初始化
            
    - 元类控制类本身的产生过程
    
        
    
    
    
"""
原文地址:https://www.cnblogs.com/52-qq/p/8448140.html