面向对象高级

isinstance(obj,cls)和issubclass(sub,super)内置函数
 print(isinstance(obj,Foo)) # 推荐使用该函数来判断一个函数的类型
 print(isinstance('abc',str)) # ‘abc’是否是类str的一个对象/函数
 print(issubclass(Foo,object))   #Foo是否是object的子类
二 反射:python面向对象中的反射通过字符串来操作类与对象的属性,这种操作称为反射;python中的一切事物都是对象(都可以使用反射)反射也是内置函数
 反射当前模块成员、类也是对象.....
 1、hasattr  # True/False
 2、getattr  #obj.__dict__['name] getattr(obj,'name',None) 没指定参数3 +没有这个属性:报错
 3、setattr  #有就改,没就增
 4、delattr # 有就删,删除的属性没有报错
 总结:#用户用input输入了字符串形式的指令,可以被反射以操纵类和对象的属性
 好处:实现可插拔机制
   动态导入模块(基于反射当前模块成员)
__setattr__,__delattr__,__getattr__
 #__setattr__添加/修改属性会触发它的执行
 def __setattr__(self, key, value):
        print('----> from setattr')
        # self.key=value #这就无限递归了,你好好想想
        # self.__dict__[key]=value #应该使用它
 #__delattr__删除属性的时候会触发
 #__getattr__只有在使用点调用属性且属性不存在的时候才会触发
 
四 二次加工标准类型(包装)
 包装:python为大家提供了标准数据类型,以及丰富的内置方法,其实在很多场景下我们都需要基于标准数据类型来定制我们自己的数据类型,新增/改写方法,这就用到了我们刚学的继承/派生知识(其他的标准类型均可以通过下面的方式进行二次加工)
 授权:授权是包装的一个特性, 包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有产品的功能。其它的则保持原样。授权的过程,即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性。

五 __getattribute__
 当__getattribute__与__getattr__同时存在,只会执行__getattrbute__,除非__getattribute__在执行过程中抛出异常AttributeError
 
六 描述符(__get__,__set__,__delete__)
 描述符:(属性为 对象的时候) 查看 ,修改,删除自动触发对象的__get__,__set__,__delete__
 作用:代理另外一个类的属性,必须把描述符定义成这个类的类属性,不能定义到构造函数中
 描述符是可以实现大部分python类特性中的底层魔法,包括@classmethod,@staticmethd,@property甚至是__slots__属性
 描述父是很多高级库和框架的重要工具之一,描述符通常是使用到装饰器或者元类的大型框架中的一个组件.

7  利用描述符原理完成一个自定制@property,实现延迟计算(本质就是把一个函数属性利用装饰器原理做成一个描述符:类的属性字典中函数名为key,value为描述符类产生的对象)
 注意事项:
 
 疑问:如果我用类名去操作属性呢
 People.name #报错,错误的根源在于类去操作属性时,会把None传给instance
 一 描述符本身应该定义成新式类,被代理的类也应该是新式类
 二 必须把描述符定义成这个类的类属性,不能为定义到构造函数中
 三 要严格遵循该优先级,优先级由高到底分别是
  1.类属性
  2.数据描述符:至少实现了__get__()和__set__()
  3.实例属性
  4.非数据描述符:没有实现__set__()
  5.找不到的属性触发__getattr__()
class A:
    def __init__(self,name,type):
        self.name=name
        self.type=type
    def __get__(self, instance, owner):
        if instance==None:
            return self
        return instance.__dict__[self.name]
    def __set__(self, instance, value):
        if not isinstance(value,self.type):
            raise TypeError('%s类型错误'%(self.name))
        instance.__dict__[self.name]=value
    def __delete__(self, instance):
        instance.__dict__.pop(self.name)
# class B:
# #     name=A('name',str)
# #     age=A('age',int)
# #     sex=A('sex',str)
# #     def __init__(self,name,age,sex):
# #         self.name=name
# #         self.age=age
# #         self.sex=sex
终极大招
# def outter(**kwargs):
#     def inner(cls):
#         for name,type in kwargs:
#             setattr(cls,name,A(name,type))
#     return inner
# @outter(name=str,age=int,sex=str)
# class B:
#     name=A('name',str)
#     age=A('age',int)
#     sex=A('sex',str)
#     def __init__(self,name,age,sex):
#         self.name=name
#         self.age=age
#         self.sex=sex
# b=B('asa','asda','asas')
class A:
    def __init__(self,name):
        self.name=name
    def __get__(self, instance, owner,*args,**kwargs):
        if instance==None:
            return self
        return self.name(owner,*args,**kwargs)
    def __set__(self, instance, value):
        if not isinstance(value,self.type):
            raise TypeError('%s类型错误'%(self.name))
        instance.__dict__[self.name]=value
    def __delete__(self, instance):
        instance.__dict__.pop(self.name)
class A:
def __init__(self,name):
self.name=name
def __get__(self, instance, owner):
def inner(*args,**kwargs):
if instance==None:
return self
return self.name(owner,*args,**kwargs)
return inner
def __set__(self, instance, value):
if not isinstance(value,self.type):
raise TypeError('%s类型错误'%(self.name))
instance.__dict__[self.name]=value
def __delete__(self, instance):
instance.__dict__.pop(self.name)


class B:
def __init__(self,name):
self.name=name
@A
def c(self):
return self
b=B('asas')
print(b.c)
print(B.c())

# class B:
#     def __init__(self,name):
#         self.name=name
#     @A
#     def c(self):
#         return self
# b=B('asas')
# print(b.c)

六 再看property
 class Foo:
    @property
    def AAA(self):
        print('get的时候运行我啊')
    @AAA.setter
    def AAA(self,value):
        print('set的时候运行我啊')
    @AAA.deleter
    def AAA(self):
        print('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[key]时,我执行')
        self.__dict__.pop(key)
    def __delattr__(self, item):
        print('del obj.key时,我执行')
        self.__dict__.pop(item)
f1=Foo('sb')
f1['age']=18
f1['age1']=19
del f1.age1
del f1['age']
f1['name']='alex'
print(f1.__dict__)

八 __str__,__repr__,__format__
 
九 __slots__
 '''
1.__slots__是什么:是一个类变量,变量值可以是列表,元祖,或者可迭代对象,也可以是一个字符串(意味着所有实例只有一个数据属性)
2.引子:使用点来访问属性本质就是在访问类或者对象的__dict__属性字典(类的字典是共享的,而每个实例的是独立的)
3.为何使用__slots__:字典会占用大量内存,如果你有一个属性很少的类,但是有很多实例,为了节省内存可以使用__slots__取代实例的__dict__
当你定义__slots__后,__slots__就会为实例使用一种更加紧凑的内部表示。实例通过一个很小的固定大小的数组来构建,而不是为每个实例定义一个
字典,这跟元组或列表很类似。在__slots__中列出的属性名在内部被映射到这个数组的指定小标上。使用__slots__一个不好的地方就是我们不能再给
实例添加新的属性了,只能使用在__slots__中定义的那些属性名。
4.注意事项:__slots__的很多特性都依赖于普通的基于字典的实现。另外,定义了__slots__后的类不再 支持一些普通类特性了,比如多继承。大多数情况下,你应该
只在那些经常被使用到 的用作数据结构的类上定义__slots__比如在程序中需要创建某个类的几百万个实例对象 。
关于__slots__的一个常见误区是它可以作为一个封装工具来防止用户给实例增加新的属性。尽管使用__slots__可以达到这样的目的,但是这个并不是它的初衷。           更多的是用来作为一个内存优化工具。
'''
class Foo:
    __slots__='x'

f1=Foo()
f1.x=1
f1.y=2#报错
print(f1.__slots__) #f1不再有__dict__
class Bar:
    __slots__=['x','y']
   
n=Bar()
n.x,n.y=1,2
n.z=3#报错
 
 
class Foo:
    __slots__=['name','age']
f1=Foo()
f1.name='alex'
f1.age=18
print(f1.__slots__)
f2=Foo()
f2.name='egon'
f2.age=19
print(f2.__slots__)
print(Foo.__dict__)
#f1与f2都没有属性字典__dict__了,统一归__slots__管,节省内存

十 __next__和__iter__实现迭代器协议
 __author__ = 'Linhaifeng'
class Foo:
    def __init__(self,x):
        self.x=x
    def __iter__(self):
        return self
    def __next__(self):
        self.x+=1
        return self.x
from collections import Iterable,Iterator
f=Foo(3)
print(isinstance(f,Iterator))
# for i in f:
#     print(i)

十一 __doc__
 
十二 __module__和__class__

十三  __del__

十四 __enter__和__exit__
1 with open('a.txt') as f:
2   '代码块'
上述叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法
__exit__()中的三个参数分别代表异常类型,异常值和追溯信息,with语句中代码块出现异常,则with后的代码都无法执行
如果__exit()返回值为True,那么异常会被清空,就好像啥都没发生一样,with后的语句正常执行
用途或者说好处:
1.使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预
2.在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制,你无须再去关系这个问题,这将大有用处
十五 __call__
 
十六 metaclass
 
原文地址:https://www.cnblogs.com/3sss-ss-s/p/9525456.html