zoukankan      html  css  js  c++  java
  • 关于__setitem__,__getitem__,delitem__以及__slots__,迭代器原理,上下文管理协议还有元类

    关于__setitem__,__getitem__,delitem__

    类似于以前的学过的__setattr__,__getattr__...

    不同之处在于item结尾的是用于对象以字典添加的形式添加,查看或者删除属性的时候才会触发,如下例子:

    class Foo(object):
        # __slots__=['x','y']
        def __setitem__(self, key, value):
            print('我在写入')
            self.__dict__[key]=value
        def __getitem__(self, item):
            print('我在返回值')
            return self.__dict__[item]
        def __delitem__(self, key):
            print('我在删除值')
            del self.__dict__[key]
    
    a=Foo()
    a['x']=1
    print(a['x'])
    del a['x']

    接下来我们来看看__slots__:

    __slots__有两个作用
    作用一:
    __slots__=['x','y']
    如果在类中定义了以上的属性那么就限制了实例化对象的添加成员

    如下例子:

    class Foo(object):
        __slots__=['x','y','z']
        def run(self):
            print('from run')
    
    a=Foo()
    a.x=10
    a.y=20
    a.z=12
    a.w=13

    通过运行我们发现当我们尝试设置w属性的时候就报错了

    作用二:
    我们在类中添加__slots__后执行 对象.__dict__发现对象不在产生dict了,也就是说对象不再独立开辟对象自己的命名空间,由此可以看出在类中限制好对象的成员后,不仅可以限制对象添加成员还可以以此节约内存空间的目的

    class Foo(object):
        __slots__=['x','y','z']
        def run(self):
            print('from run')
    
    a=Foo()
    print(a.__dict__)
    b=Foo()
    print(b.__dict__)

    可能你现在还无法想象,加入我们每实例化一个对象就会产生一个dict,如果有成百上前的对象就会产生成百上千的独立命名空间,这样就会浪费很多的内存空间

    迭代器的原理:

    你有想过迭代器是如何实现的吗,假设我们要自定义一个range函数,这个时候我们就需要用到__next__和__iter__了

    我们都是知道只要是包含__iter__方法的就是一个可迭代对象,执行__next__方法就会返回一个值,那么我们模拟下range函数

    class Range(object):
        def __init__(self,start,stop,jump=0):
            self.start=start
            self.stop=stop
            self.jump=jump
            if self.jump>0:
                self.jump=self.jump-1
        def __iter__(self):
            return self
        def __next__(self):
            n=self.start
            if self.start>self.stop-1:
                raise StopIteration
            self.start+=(1+self.jump)
            return n
    for i in Range(0,9,2):
        print(i)

    我们自定义了一个Range类用来模拟range迭代器,运行后发现可以正常运行,当然如果想要百分百模拟我们还有一些地方需要完善

    关于__del__:

    这个函数有点特殊,我们还是直接说说它的原理吧。在类中定义好__del__后,它会在被python解释器的垃圾回收机制,在类没有被任何调用或者被对象指向的时候,就会被python垃圾回收机制清理来节约内存,这个时候__del__内部的代码就会执行我们来试试

    import time
    class Foo(object):
        def __del__(self):
            print('我要被销毁了')
    a=Foo()

    我们发现在程序运行结束后就会执行__del__代码,可能这样看的还不是很清楚,我们再来看看

    import time
    class Foo(object):
        def __del__(self):
            print('我要被销毁了')
    a=Foo()
    del a
    time.sleep(5)

    我们导入了一个time模块在程序运行结束之前先睡5秒,睡5秒之前先把对象a给删除,我们发现不用等程序结束运行就会执行__del__代码,如果你不信还可以先把del a给注销试试

    上下文管理协议__enter__和__exit__:

    我们打开文件读取和写入的时候会用上with这个语句,它会在文件读取完毕的时候自动关闭文件,但你有想过这是如何实现的吗?

    我们来看看他们的定义和执行顺序

    class Foo(object):
        def __enter__(self):
            print('from enter')
        def __exit__(self, exc_type, exc_val, exc_tb):
            print('from exit')
            print('exc_type',exc_type)
            print('exc_val',exc_val)
            print('exc_tb',exc_tb)
    with Foo():
        print('Foo')

    发现会优先执行enter方法,最后执行exit方法,他们到底是什么呢

    class Foo(object):
        def __enter__(self):
            print('from enter')
            return 23233
        def __exit__(self, exc_type, exc_val, exc_tb):
            print('from exit')
            print('exc_type',exc_type)
            print('exc_val',exc_val)
            print('exc_tb',exc_tb)
    with Foo()as a:
        print(a)
        print('Foo')
        raise TypeError('类型错误')

    发现enter的作用可以用来返回值后被as后面的变量名给接受值,而exit的那几个参数可以用于接受错误信息

    ,当在exit中加入return Ture后发现会忽略这些错误。

    知道他们的用处后我们来模拟一个用类自定义的日志文件写入的open函数

    import time
    class Open:
        def __init__(self,filepath,m='r',encoding='utf8'):
            self.io=open(filepath,mode=m,encoding=encoding)
            self.filepath=filepath
            self.mode=m
            self.encoding=encoding
        def write(self,line):
            t=time.strftime('%y-%m-%d %x')
            self.io.write('%s %s'%(t,line))
        def __getattr__(self,item):
            return getattr(self.io,item)
        def __enter__(self):
            return self
        def __exit__(self, exc_type, exc_val, exc_tb):
            self.io.close()
    
    with Open('001.txt','w')as f:
        f.write('xxxxxx')
        f.seek(0)
    with Open('001.txt','r')as r:
        print(r.read())

    完美,还有比这更完美的了吗

    元类

    什么是元类,通过__dict__发现其实类也是由一个字典组成的,既然类是由字典组成的我们能不能自定义一个类呢?

    name='cris'
    def run():
        print('runing')
    def add():
        print('add')
    cls=type('func',(object),{'run':run,'add':add})

    我们可以通过这种定义元类的方式来定义一个cls类,来试试能否正常调用

    name='cris'
    def run():
        print('runing')
    def add():
        print('add')
    cls=type('func',(object,),{'run':run,'add':add})
    cls.add()
    cls.run()
    print(cls.__name__)

    type有三个参数,第一个是类名,第二个是基础关系,第三个是函数字典

    通过type我们还可以定制自己的元类:

    元类起始就是类的类,可以用来控制类的行为,如果一个父类继承元类,二子类以metaclass方式继承父类,那么就可以在父类中控制类的行为,比如我们限制子类必须写doc文档

    class Foo(type):
        def __init__(self,cls_name,base,dict):
            for key in dict:
                if not callable(dict[key]):continue
                if not dict[key].__doc__:
                    raise TypeError('没有写函数文档这是不允许的')
    
    class Foo1(metaclass=Foo):
        def __init__(self,name):
            self.name=name
        def run(self):
            print('thin is run func')
    
    a=Foo1('cris')

    这个时候我们在子类中没有写函数文档就会抛出异

    实际上在我们实例化一个类的对象的时候就是在调用元类的call方法,我只是知道有这么个操作具体原理我也不明

    class Foo(type):
        def __init__(self,cls_name,base,dict):
            pass
        def __call__(self, *args, **kwargs):
            obj=self.__new__(self)
            self.__init__(obj, *args, **kwargs)
            return obj
    
    class Foo1(metaclass=Foo):
        def __init__(self,name):
            self.name=name
        def run(self):
            print('thin is run func')
    
    a=Foo1('cris')
    a.name
  • 相关阅读:
    AX 2012 Security Framework
    The new concept 'Model' in AX 2012
    How to debug the SSRS report in AX 2012
    Using The 'Report Data Provider' As The Data Source For AX 2012 SSRS Report
    Deploy SSRS Report In AX 2012
    AX 2012 SSRS Report Data Source Type
    《Taurus Database: How to be Fast, Available, and Frugal in the Cloud》阅读笔记
    图分析理论 大纲小结
    一文快速了解Posix IO 缓冲
    #转载备忘# Linux程序调试工具
  • 原文地址:https://www.cnblogs.com/crischou/p/6763799.html
Copyright © 2011-2022 走看看