zoukankan      html  css  js  c++  java
  • python之面向对象高级

    一.__slots__

    1.__slots__的概念:是一个变量,变量值可以是列表,元组,或者可迭代对象,也可以是一个字符串。

    2.使用点来访问属性本质就是在访问类或者对象的__dict__属性字典(类的字典是共享的,而每个实例是独立的)

    3.为什么要用:节省内存,不会产生新的名称空间。

    定义__slots__后,__slots__就会为实例使用一种更加紧凑的内部表示。实例通过一个很小的固定大小的数组来构建,而不是每个实例定义一个字典;在__slots__中列出的属性名在内部被映射到这个数组的指定小标上。使用__slots__一个不好的地方就是我们不能再给实例添加新的属性了,只能用__slots__中定义的那些属性名。

    4.注意事项:__slots__的很多特性都依赖于普通的基于字典的实现。另外,定义了__slots__后的类不再支持一些普通类特性,比如多继承。

    5.应用场景:一个类产生N多个对象,产生对象的属性都是相同的,用__slots__来统一管理属性

    class People:
        __slots__=["x","y","z"]
    p=People()
    print(People.__dict__)
    >>
    {'__module__': '__main__', '__slots__': ['x', 'y', 'z'], 'x': <member 'x' of 'People' objects>, 'y': <member 'y' of 'People' objects>, 'z': <member 'z' of 'People' objects>, '__doc__': None}
    
    p.x=1
    p.y=5
    p.z=4
    print(p.x,p.y,p.z)
    >>
    1 5 4
    
    p.d=9  #报错
      File "C:/python_fullstack_s4/day32/__slots__方法.py", line 14, in <module>
        p.d=9
    AttributeError: 'People' object has no attribute 'd'
    
    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__)
    >>
    ['name', 'age']
    ['name', 'age']
    #f1与f2都没有属性字典了,统一归__slots__管,节省内存 
    print(f1.__dict__)#报错
    >>
    Traceback (most recent call last):
      File "C:/python_fullstack_s4/day32/__slots__方法.py", line 23, in <module>
        print(f1.__dict__)
    AttributeError: 'Foo' object has no attribute '__dict__'
    

     二.__iter__   __next__

    可迭代对象是有方法__iter__()

    迭代器是有方法__next__()

    因而可以自己构建一个类, 使得它的对象, 既是一个可迭代对象, 也是一个迭代器 

    from collections import Iterable,Iterator#导入模块 检查是否hi可迭代对象或迭代器
    class Foo:
        def __init__(self,start):
            self.start=start
        def __iter__(self):
            return self
        def __next__(self):
            if self.start>10:#设置数据限制,当self.start>10时,停止运行
                raise StopIteration
            n=self.start
            self.start+=1
            return n
    f=Foo(0)
    # print(isinstance(f,Iterable))
    for i in f:
    print(i)
    
    >>
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    

    三.__doc__

    __doc__是类的描述信息

    该属性无法继承给子类

     四.

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

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

    class Bar():
        pass
    b=Bar()
    print(b.__class__)
    print(b.__module__)
    >>
    <class '__main__.Bar'>
    __main__
    

    五.__del__

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

    class Open:
        def __init__(self,filepath,mode="r",encode="utf8"):
            self.f=open(filepath,mode=mode,encoding=encode)
        def write(self):
            pass
        def __del__(self):#产生的对象被垃圾处理时
            # 会触发__del__
            print("--->del")
            self.f.close()
    
    f=Open("a.txt","w")
    del f#如果手动删除,直接触发,再执行别的程序
    

    六.__enter__  __exit__

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

    用途:                     

    1. 使用with语句的目的是把代码块放在with中执行,with结束后,自动完成清理工作,无须手动干预
    2. 在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制
      class Open:
          def __init__(self,name):
              self.name=name
      
          def __enter__(self):
              print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
              # return self
          def __exit__(self, exc_type, exc_val, exc_tb):
              print('with中代码块执行完毕时执行我啊')
      
      
      with Open('a.txt') as f:
      print('=====>执行代码块')
      
      >>
      出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量
      =====>执行代码块
      with中代码块执行完毕时执行我啊
        
    3. 抛出异常

      with语句中代码块出现异常,则with后的代码都无法执行

      class Foo:
          def __enter__(self):
              print("enter")
              return 11111
          def __exit__(self, exc_type, exc_val, exc_tb):
              print("exit")
              print("exc_type",exc_type)#异常类型
              print("exc_val",exc_val)#异常值
              print("exc_tb",exc_tb)#追溯信息
      
      with Foo():#1.with加对象()就回触发enter的运行
          print("1111")#2.打印
          raise NameError()#只要抛出异常,子代码块就运行完毕
                          #触发exit的运行
          print("******************")#不会运行
      print("999999999999999999999999")#子代码运行结束后(无异常)
                                  #正常运行
      
      >>
      Enter
      1111
      exit
      exc_type <class 'NameError'>
      exc_val 
      exc_tb <traceback object at 0x02EE1DA0>
      Traceback (most recent call last):
        File "C:/python_fullstack_s4/day32/上下文管理协议.py", line 17, in <module>
          raise NameError()#只要抛出异常,子代码块就运行完毕
      NameError
      

        

      异常解决
      如果__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('***着火啦,救火啊***')#传给exc_val
      print('0'*100) #------------------------------->会执行
      >>
      出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量
      =====>执行代码块
      with中代码块执行完毕时执行我啊
      <class 'AttributeError'>
      ***着火啦,救火啊***
      <traceback object at 0x02C51E68>
      0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000  

    七.__call__

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

    构造方法的执行是由创建对象触发的,即对象=类名();

    对于__call__方法的执行是由对象后加括号触发的,即对象()或者类()()

    class People:
        def __init__(self,name):
            self.name=name
        def __call__(self, *args, **kwargs):
            print("call")
    p=People("karina")
    p()#实例也变成一个可调用对象 
    >>
    call
    

    八.元类

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

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

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

    Type是python的一个内建元类,用来直接控制生成类,python中任何class定义的类其实都是type类实例化的对象

    产生类的方法

    1.
    class Foo:
        def func(self):
            print("from func")
    f1=Foo()
    f1.func()
    >>
    from func
    

      

    2.
    格式
    类名=type(class_name,class_bases(父类),class_dict({}))
    def func(self):
        print("from func")
    x=1
    Foo=type("Foo",(object,),dict({}))
    print(Foo)
    print(type(Foo))
    print(Foo.__dict__)
    >>
    <class '__main__.Foo'>
    <class 'type'>
    {'__module__': '__main__', '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None}
    

     

    新建对象的过程

      首先, 类要生成对象, 类本身需要可调用

      针对于基类, 类是基类的对象, 也就是说在基类中, 需要有一个__call__()函数, 而这个函数, 是在类的__init__之前执行的

      在基类的__call__()方法中, 需要使用self.__new__(self)来创建一个空对象, 这个对象就是类

      有了类之后就可以调用原有的方法__init__(), 这时在其中就是熟悉的生成对象了

      最后再返回这个类就行了

     

     

    class MyMetaclass(type):
        def __call__(self, *args, **kwargs):
            obj = self.__new__(self)
            self.__init__(obj, *args, **kwargs)  # obj.name='egon'
            return obj
     
    class People(metaclass=MyMetaclass):
        def __init__(self, name):
            self.name = name
     
    whc = People('whc')
    print(whc.name)
    

      

  • 相关阅读:
    SetThreadAffinityMask设置线程亲缘性
    Delphi 获取北京时间(通过百度和timedate网站)
    delphi 实现微信开发
    翻书的效果:FMX.TSwipeTransitionEffect Animation
    [每日一题] OCP1z0-047 :2013-07-15 drop column
    Delphi获取当前系统时间(使用API函数GetSystemTime)
    Delphi代码中嵌入ASM代码
    Delphi Jpg和Gif转Bmp
    Delphi RichEdit的内容保存为图片
    Delphi 实现任务栏多窗口图标显示
  • 原文地址:https://www.cnblogs.com/asaka/p/6763775.html
Copyright © 2011-2022 走看看