zoukankan      html  css  js  c++  java
  • 面向对象操作进阶

    __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__)
    
    >>>:
    del obj.key时,我执行
    del obj[key]时,我执行
    {'name': 'alex'}
    View Code
    
    
    __slots__:
    由类产生的对象不再产生自身名称空间,可以节省内存,也可以限定产生的属性。
    
    
    class Foo:
        __slots__=['name','age','sex']  #限定绑定的对象只有3个属性
    
    p = Foo()
    p.age = 18
    # print(p.__dict__)  #打印p对象字典会报错,提示'Foo' object has no attribute '__dict__'
    p.sex = 'male'
    p.name = 'Mitsui'
    print(p.name,p.sex,p.age)
    View Code
    
    
    __next__和__iter__:(实现迭代器协议)
    class My_range:
        def __init__(self,start,end):
            self.start = start
            self.end = end
    
        def __iter__(self):
            return self
    
        def __next__(self):
            n = self.start
            self.start += 1
            if n == self.end:
                raise StopIteration
            return n
    
    f = My_range(1,10)
    for i in f:
        print(i)
    View Code

    __doc__: 查看注释信息 无法被继承

    __module__ 表示当前操作的对象在那个模块

    __class__     表示当前操作的对象的类是什么

    __del__ 析构方法,当对象在内存中被释放时,自动触发执行。

    class Foo:
    
        def __del__(self):
            print('执行我啦')
    
    f1=Foo()
    del f1
    print('------->')
    
    >>>>:
    执行我啦     #del 对象被释放,所以运行了里面的print
    ------->        #如果没有del f1 则会先运行------>然后整个程序运行结束 也会打印__del__里面 ‘执行我啦’。
    View Code

    __enter__和__exit__:

    import time
    class Open:
    
        def __init__(self,filepath,mode='r',encode='utf8'):
            self.f = open(filepath,mode=mode,encoding=encode)
        def __enter__(self):
            return self  #('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')  #这里return self 而不是self.f 是因为self.f是原本open功能的句柄,return self.f 下面引用f.write 将是应用原本文件写功能,而不是自己定制的write,所以return self 赋给 f,f.write则会调用自己定制的write
    
        def write(self, line):  # 定制自己的文件写功能
            print('f自己的write',line)
            t=time.strftime('%Y-%m-%d %X')          #得到一个格式输出的时间 年Y月m日d 时分秒X
            self.f.write('%s %s' %(t,line))
        def __getattr__(self, item):
            return getattr(self.f,item)
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            self.f.close()  #with 代码结束时执行,仿原本的with open 起到一个关闭文件的作用
    
    with Open('b.txt','w+')as f:
        f.write('自己的日志写功能')
        f.seek(0)
        print(f.read())
    View Code

    1.使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预

    2.在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制,你无须再去关系这个问题,这将大有用处

     __call__

    构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

    class Foo:
        def __init__(self):
            pass
        def __call__(self, *args, **kwargs):
            print('__call__')
    
    obj = Foo()  
    obj() #对象加()触发__call__  打印输出“__call__”
    View Code

    metaclass:元类

    1.首先看看一个类是如何生成的:

     1 # 自定义一个类:
     2 def run(self):
     3     print('%s is running' % self.name)  #定义一个函数run
     4 class_name = 'Foo'    #定义类名
     5 class_dic={         #定义类里边的__dic__ 参数
     6     'name':'Mitsui',
     7     'run':run
     8 }
     9 bases = (object,)
    10 Foo = type(class_name,bases,class_dic)    #type手动创建一个类            

    1.什么是元类?

    元类是类的类,是类的模板

    元类是用来控制如何创建类的,正如类是创建对象的模板一样

    元类的实例为类,正如类的实例为对象(f1对象是Foo类的一个实例Foo类是 type 类的一个实例)

    2.一个类没有声明自己的元类,默认他的元类就是type,除了使用元类type,用户也可以通过继承type来自定义元类 
    我们先来定制一个自己的元类
    class MyType(type):
        def __init__(self,class_name,class_bases,class_dic):
            for key in class_dic:               #所有由元类生成的类的__dict__都会传入到这个class_dic
                if not callable(class_dic[key]):continue     #如果定义的类里__dict__里value不可被调用则不是函数跳过循环
                if not class_dic[key].__doc__:      #剩下的可被调用都为函数,如果函数里__doc__没有值则没写注释   
                    raise TypeError('滚去写注释')       #抛出异常提示写备注
    
    class Foo(metaclass=MyType): #in python3            等于是Foo = Mytype('Foo',(object,),{}) 分别传入Mytype __init__
        # __metaclass__ = MyType #in python2                          # (class_name,class_bases=,class_dict)
        def run(self):                                     #Foo作为对象实例化自定义的元类,所以会触发MyType.__init__
            pass                                           #达到定义类时限制函数需写注释的目的
    
    #运行结果:
    Traceback (most recent call last):
    raise TypeError('滚去写注释')
    TypeError: 滚去写注释
    View Code
    自定义的元类模拟type元类达到自动传参的功能:
    class Mytype(type):
        def __init__(self,what,bases=None,dict=None):  #只要由这个自定义元类产生的类,如下面的Foo+() 即Foo作为对象实例化,
            # 将参数传入元类的init里,self = Foo,其它属性对应后面的参数
            print('mytype init')    #当有类使用这个自定义的元类时打印验证
        def __call__(self, *args, **kwargs): #对象Foo()触发call的执行
            obj=self.__new__(self)      #如果要将产生的类实例化如f1 = Foo(),则产生一个空的对象Obj
            self.__init__(obj,*args,**kwargs)   #执行由Mytype产生的类的__init__方法,即Foo.__init__
            return obj      #返回这个这个对象,即f1=Foo(),返回这个f1,即达成一般类生成时自动传self的效果
    
    class Foo(object,metaclass=Mytype):
        x=1111111111
        def __init__(self,name):
            self.name=name
        def __new__(cls, *args, **kwargs):
            return super().__new__(cls)
    
    f1=Foo('egon')
    print(f1.__dict__)
    
    打印结果:
    mytype init
    {'name': 'egon'}
    View Code
    总结:元类的难点在于执行顺序很绕,其实我们只需要记住两点就可以了
    49 1.谁后面跟括号,就从谁的爹中找__call__方法执行
    50 type->Mymeta->Foo->obj
    51 Mymeta()触发type.__call__
    52 Foo()触发Mymeta.__call__
    53 obj()触发Foo.__call__
    54 2.__call__内按先后顺序依次调用儿子的__new__和__init__方法
     
     
     
    
    
    
     
  • 相关阅读:
    存储过程中Like没有数据?
    鼠标放上图片移动,字体移动
    Excel
    参数无效。区域性ID2155(0X086B)不是受支持的区域性
    JVM指令集及各指令的详细使用说明[转的]
    BTrace使用简介
    ST表
    树剖模板
    AjaxControlToolkit中的CalendarExtender被遮挡及日期格式本地化解决方法
    Using Beyond Compare with TFS
  • 原文地址:https://www.cnblogs.com/mitsui/p/6764036.html
Copyright © 2011-2022 走看看