zoukankan      html  css  js  c++  java
  • 面向对象最后进阶

    1.__slots__

    1.__slots__是什么:是一个类变量,变量值可以是列表,元祖,或者可迭代对象,也可以是一个字符串(意味着所有实例只有一个数据属性)
    2.定义__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#报错
    

    2.__next__和__iter__实现迭代器协议

    迭代器协议模拟range(start,end)

    # 迭代器协议模拟range(start,end)
    class Foo:
        def __init__(self,start,end):
            self.start = start
            self.end = end
    
        def __iter__(self):
            return self
    
    
        def __next__(self):
            if self.start >= self.end:
                raise StopIteration
            n = self.start
            self.start += 1
            return n
    
    f = Foo(0,10)
    print(list(f))  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    

    迭代器协议实现斐波那契数列

    # 斐波那契数列类
    class Fib:
        def __init__(self):
            self.__a = 0
            self.__b = 1
    
        def __iter__(self):
            return self
    
    
        def __next__(self):
            if self.__a > 100:
                raise StopIteration
            self.__a,self.__b = self.__b,self.__a+self.__b
            return self.__a
    
    f = Fib()
    l = [i for i in f]
    print(l)      # [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144]
    

    3.__module__和__class__

    __module__ 表示当前操作的对象在那个模块
    __class__ 表示当前操作的对象的类是什么

    4.__del__析构方法

    析构方法,当对象在内存中被释放时,自动触发执行。
    此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

    # __del__析构函数
    import time
    class Foo:
        def __init__(self, path, mode="r", encode="utf8"):
            self.f = open(path, mode=mode, encoding=encode)
    
        def __getattr__(self, item):
            return getattr(self.f, item)
    
    
        def __del__(self):
            print("------del------")
            self.f.close()
    
    f = Foo("a.txt", "w")
    f.write("qqqqqqqqqqqqqqqqqqqqqqq
    ")
    
    del f          # 清除对象时会触发执行,------del------
    # f.close()
    print("********************")
    time.sleep(5)
    

    5.__enter__和__exit__

    1.上下文管理协议,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法.

    2.__exit__()中的三个参数分别代表异常类型,异常值和追溯信息,with语句中代码块出现异常,则with后的代码都无法执行

    3.如果__exit()返回值为True,那么异常会被清空,就好像啥都没发生一样,with后的语句正常执行

    # 上下文管理协议实现打开文件
    class Foo:
        def __init__(self,path, m="r", e = "utf-8"):
            self.f = open(path, mode=m, encoding=e)
    
    
        def __getattr__(self, item):
            return getattr(self.f, item)
    
    
        def __enter__(self):
            return self
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            print(exc_type, exc_val, exc_tb)
            return 1
    
    
    with Foo("a.txt", "w") as f:  # 相当于拿到Foo.__enter__()的返回值赋值给f
        print("-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-")
        raise NameError("name cuowu")
        print("-"*50)
    
    print("主代码还在继续执行")
    
    # 执行结果
    # -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    # <class 'NameError'> name cuowu <traceback object >
    # 主代码还在继续执行
    

    1.使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预
    2.在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制,你无须再去关系这个问题,这将大有用处

    6.__call__

    对象后面加括号,触发执行。

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

    #\_\_call__
    class Foo:
        def __call__(self, *args, **kwargs):
            print("__call__ is running")
        pass
    
    f = Foo() 
    print(callable(Foo)) # True. 执行 __init__,类()是执行类下的__init__方法
    print(callable(f))   # True
    

    7.元类

    元类就是深度的魔法,99%的用户应该根本不必为此操心。如果你想搞清楚究竟是否需要用到元类,那么你就不需要它。那些实际用到元类的人都非常清楚地知道他们需要做什么,而且根本不需要解释为什么要用元类。—— Tim Peters
    创建类的另一种方式

    # 利用type产生元类
    SB = type("SB", (object,), {})
    s = SB()
    s.name = "zou"
    print(type(s))     # <class '__main_ _.SB'>
    print(s.__dict__)  # {'name': 'zou'}
    

    元类总结

    #元类总结
    class Mymeta(type):
        def __init__(self,name,bases,dic):
            print('===>Mymeta.__init__')
    
    
        def __new__(cls, *args, **kwargs):
            print('===>Mymeta.__new__')
            return type.__new__(cls,*args,**kwargs)
    
        def __call__(self, *args, **kwargs):
            print('aaa')
            obj=self.__new__(self)
            self.__init__(self,*args,**kwargs)
            return obj
    
    class Foo(object,metaclass=Mymeta):
        def __init__(self,name):
            self.name=name
        def __new__(cls, *args, **kwargs):
            return object.__new__(cls)
    
    '''
    需要记住一点:名字加括号的本质(即,任何name()的形式),都是先找到name的爹,然后执行:爹.__call__
    
    而爹.__call__一般做两件事:
    1.调用name.__new__方法并返回一个对象
    2.进而调用name.__init__方法对儿子name进行初始化
    '''
    
    '''
    class 定义Foo,并指定元类为Mymeta,这就相当于要用Mymeta创建一个新的对象Foo,于是相当于执行
    Foo=Mymeta('foo',(...),{...})
    因此我们可以看到,只定义class就会有如下执行效果
    ===>Mymeta.__new__
    ===>Mymeta.__init__
    实际上class Foo(metaclass=Mymeta)是触发了Foo=Mymeta('Foo',(...),{...})操作,
    遇到了名字加括号的形式,即Mymeta(...),于是就去找Mymeta的爹type,然后执行type.__call__(...)方法
    于是触发Mymeta.__new__方法得到一个具体的对象,然后触发Mymeta.__init__方法对对象进行初始化
    '''
    
    '''
    obj=Foo('egon')
    的原理同上
    '''
    
    '''
    总结:元类的难点在于执行顺序很绕,其实我们只需要记住两点就可以了
    1.谁后面跟括号,就从谁的爹中找__call__方法执行
    type->Mymeta->Foo->obj
    Mymeta()触发type.__call__
    Foo()触发Mymeta.__call__
    obj()触发Foo.__call__
    2.__call__内按先后顺序依次调用儿子的__new__和__init__方法
    '''
    

    限制注释信息

    # 3 自定义元类限制注释信息
    from collections import Iterable,Iterator
    class Mymeta(type):
        def __init__(self, class_name, base=None, dict=None ):
            # print(self)
            # print(class_name)
            # print(base)
            # print(dict)
            for key in dict:
                if not callable(dict[key]):continue
                if not dict[key].__doc__:
                    raise Exception("你还没写注释信息")
    
        def __call__(self, *args, **kwargs):
            print("from mytype",self,args,kwargs) # from mytype <class '__main__.Foo'> ('zou',) {}
            obj = self.__new__(self)
            self.__init__(obj, *args, **kwargs)
            return obj
    
    
    class Foo(metaclass=Mymeta):
        x = 1
        def __init__(self,name):
            "初始化信息"
            self.name = name
        def run(self):
            "run function"
            print("running")
    
    
    f = Foo("zou")      # from mytype <class '__main__.Foo'> ('zou',) {}
    # print(Foo.__dict__)
    
  • 相关阅读:
    Create方法失效而没有提示错误信息
    JS弹出窗口控制
    本周活动
    JavaScript的初步了解
    关于PHP接收文件的资料
    mvc模式改进网站结构
    一周动态
    排序
    Java的内存泄漏
    Android笔记
  • 原文地址:https://www.cnblogs.com/zouruncheng/p/6763986.html
Copyright © 2011-2022 走看看