zoukankan      html  css  js  c++  java
  • 面向对象_类的特殊成员

      成员名前如果有两个下划线,则表示该成员是私有成员,只能由类内部调用。

    __doc__

      表示类的描述信息

    class Animal():
        '''
        类的描述信息:动物类
        '''
    
        def eat(self):
            pass
    
    print(Animal.__doc__)

    __module__和__class__

      __module__表示当前操作对象所属的模块

      __class__表示当前操作对象所属的类

    class c():
        def __init__(self):
            self.name = 'lary'
    from module_test import c
    
    obj = c()
    
    print(obj.__module__)       #module_test
    print(obj.__class__)        #<class 'module_test.c'>

    __init__

      构造方法,通过类创建对象时,自动触发执行

    class Animal():
        def __init__(self,name):
            self.name = name
            self.feature = 'eat'
    
    animal = Animal('cat') #自动执行类中的__init__方法 

    __del__

      析构方法,当对象在内存中被释放时,自动触发执行。此方法一般无需定义,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

    __call__

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

    class Animal():
    
        def __init__(self):
            pass
    
        def __call__(self, *args, **kwargs):
            print('调用__call__')
    
    animal = Animal() #调用__init__
    animal()          #调用__call__

    __dict__

      类或对象中的所有成员

    class Animal():
        '''
        动物类
        '''
    
        feature = 'live'
    
        def __init__(self,name):
            self.name = name
    
        def __call__(self, *args, **kwargs):
            print('调用__call__')
    
    print(Animal.__dict__)
    animal = Animal('cat')
    print(animal.__dict__)

     

    __getitem__,__setitem__,__delitem__

      用于索引操作,如字典

    class Foo(object):
    
        def __getitem__(self, key):
            print('__getitem__', key)
    
        def __setitem__(self, key, value):
            print('__setitem__', key, value)
    
        def __delitem__(self, key):
            print('__delitem__', key)
    
    
    obj = Foo()
    
    result = obj['k1']  # 自动触发执行 __getitem__
    obj['k2'] = 'lary'  # 自动触发执行 __setitem__
    del obj['k1']  # 自动触发执行 __delitem__

    __iter__和__next__

      用于迭代器

    class Foo():
    
        def __init__(self,sq):
            self.sq = sq
    
        def __iter__(self):
            return iter(self.sq)
    
    obj = Foo([1,2,3,4,5])
    for i in obj:
        print(i)
    class Foo:
        def __init__(self,start,stop):
            self.num=start
            self.stop=stop
        def __iter__(self):
            return self
        def __next__(self):
            if self.num >= self.stop:
                raise StopIteration
            n=self.num
            self.num+=1
            return n
    
    f=Foo(1,5)
    from collections import Iterable,Iterator
    print(isinstance(f,Iterator))
    
    for i in Foo(1,5):
        print(i)

    __slots__

    1.__slots__是一个类变量,变量值可以是列表,元祖,或者可迭代对象,也可以是一个字符串(意味着所有实例只有一个数据属性)
    2.使用点来访问属性本质就是在访问类或者对象的__dict__属性字典(类的字典是共享的,而每个实例的是独立的)
    3.字典会占用大量内存,如果你有一个属性很少的类,但是有很多实例,为了节省内存可以使用__slots__取代实例的__dict__
    4.当你定义__slots__后,__slots__就会为实例使用一种更加紧凑的内部表示。实例通过一个很小的固定大小的数组来构建,而不是为每个实例定义一个字典,这跟元组或列表很类似。在__slots__中列出的属性名在内部被映射到这个数组的指定小标上。使用__slots__的缺点就是我们不能再给实例添加新的属性了,只能使用在__slots__中定义的那些属性名。
    5.注意事项:__slots__的很多特性都依赖于普通的基于字典的实现。另外,定义了__slots__后的类不再支持一些普通类特性了,比如多继承。大多数情况下,你应该只在那些经常被使用到的用作数据结构的类上定义__slots__,比如在程序中需要创建某个类的几百万个实例对象 。
    6.关于__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  # 报错
    print(n.__slots__)
    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__管,节省内存

    __enter__和__exit__

       我们在操作文件对象的时候可以这么写

    with open('a.txt') as f:
        f.read()

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

    class Open:
        def __init__(self,name):
            self.name=name
    
        def __enter__(self):
            print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
    
        def __exit__(self, exc_type, exc_val, exc_tb): #异常类型,异常值和追溯信息
            print('with中代码块执行完毕时执行我啊')
            print(exc_type)
            print(exc_val)
            print(exc_tb)
    
    
    with Open('a.txt') as f:
        print('=====>执行代码块')
        raise AttributeError('***异常啦***')
    print('0'*100) #------------------------------->不会执行

      with语句中代码块出现异常,则with后的代码都无法执行,r如果__exit__返回值为True,那么异常值就会被清空,with后的语句正常执行

    class Open:
        def __init__(self,name):
            self.name=name
    
        def __enter__(self):
            print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
    
        def __exit__(self, exc_type, exc_val, exc_tb): #异常类型,异常值和追溯信息
            print('with中代码块执行完毕时执行我啊')
            print(exc_type)
            print(exc_val)
            print(exc_tb)
            return True
    
    
    with Open('a.txt') as f:
        print('=====>执行代码块')
        raise AttributeError('***异常啦***')
    print('0'*100) #------------------------------->会执行
    View Code
    class Open:
        def __init__(self,filepath,mode='r',encoding='utf-8'):
            self.filepath=filepath
            self.mode=mode
            self.encoding=encoding
    
        def __enter__(self):
            self.f=open(self.filepath,mode=self.mode,encoding=self.encoding)
            return self.f
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            self.f.close()
            return True 
        def __getattr__(self, item):
            return getattr(self.f,item)
    
    with Open('a.txt','w') as f:
        print(f)
        f.write('aaaaaa')
        f.wasdf #抛出异常,交给__exit__处理
    模拟open

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

      在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制。

    __getattribute__

      访问属性时触发,不论该属性是否存在

    class Foo:
        def __init__(self,x):
            self.x=x
    
        def __getattr__(self, item):
            print('执行的是我')
            # return self.__dict__[item]
        def __getattribute__(self, item):
            print('不管是否存在,我都会执行')
            raise AttributeError('哈哈')
    
    f1=Foo(10)
    f1.x
    f1.xxxxxx
    #当__getattribute__与__getattr__同时存在,只会执行__getattrbute__,除非__getattribute__在执行过程中抛出异常AttributeError
    class animal(object):
    
        def __getattribute__(self, item):
           return object.__getattribute__(self,item)()
    
        def eat(self):
            print('eating...')
    
    #print(animal.__dict__)
    cat = animal()
    #print(cat.__dict__)
    cat.eat
    #当获取属性时,直接return object.__getattribute__(self,*args,**kwargs)
    #如果需要获取某个方法的返回值时,则需要在函数后面加上一个()即可,如果不加的话,返回的是函数引用地址
    #在__getattribute__方法里面,不能用self.xxx这种方式调用。因为调用类的属性每次都会强制调用__getattribute__,所以会导致递归调用
  • 相关阅读:
    NLog 在NetCore中实现多实例注入DI, 实现多租户模式
    Linux命令入门篇(二)
    Linux命令入门篇(一)
    uni-app初探之幸运轮盘
    uni-app初探之天气预报小例子
    iOS 底层原理之—dyld 与 objc 的关联
    QT OpenGLWidget高分屏适配时出现的问题
    基于React.js网页版弹窗|react pc端自定义对话框组件RLayer
    面向对象的六大原则
    android混淆日记
  • 原文地址:https://www.cnblogs.com/iamluoli/p/9922762.html
Copyright © 2011-2022 走看看