zoukankan      html  css  js  c++  java
  • Python面向对象编程Day 27部分知识点

    内置函数补充及__getattribute__

    isinstance(obj,cls)检查obj是否是类cls的实例,反映族谱关系(不仅父类可以,父类的父类也可以) 

    issubclass(subcls,cls)检查subcls是否是cls的子类

    __getattribute__属性存不存在都会触发它 ‘大哥’ 里面抛出Attribute Error时交给小弟处理

    __getattr__属性不存在触发 ‘小弟

     item系列

    item是字典方式触发的

    __setitem__

    __getitem__

    __delitem__

     1 class Foo:
     2     def __getitem__(self, item):
     3         print('getitem',item)
     4         return self.__dict__[item]
     5 
     6     def __setitem__(self, key, value):
     7         print('setitem')
     8         self.__dict__[key]=value
     9 
    10     def __delitem__(self, key):
    11         print('delitem')
    12         self.__dict__.pop(key)
    13 
    14 f1=Foo()
    15 print(f1.__dict__)
    16 # f1.name='egon'  #---->点触发attr系列方法
    17 f1['name']='egon'  #--->中括号字典形式触发item系列方法
    18 f1['age']=18
    19 
    20 print('===>',f1.__dict__)
    21 
    22 # del f1.name
    23 # print(f1.__dict__)
    24 25 # print(f1.age)
    26 del f1['name']
    27 print(f1.__dict__)
    28 
    29 print(f1['age'])

    输出

    {}
    setitem
    setitem
    ===> {'name': 'egon', 'age': 18}
    delitem
    {'age': 18}
    getitem age
    18

    __str__和__repr__

     1 class Foo:
     2     def __init__(self,name,age):
     3         self.name=name
     4         self.age=age
     5     def __repr__(self):
     6         return 'this is repr'
     7     # def __str__(self):
     8     #     return 'this is str'
     9 f1=Foo('cy',23)
    10 print(f1)   #str(f1)-->f1.__str__()

    输出

    this is repr

    st函数或者print函数--->obj.__str__()

    repr函数或者交互式解释器--->obj.__repr__()

    如果__str__没被定义,那就使用__repr__来代替输出

    str和repr返回的必须是字符串,否则抛出异常

    自定制format

     1 format_dic={
     2     'ymd':'{0.year}{0.mon}{0.day}',
     3     'm-d-y':'{0.mon}-{0.day}-{0.year}',
     4     'y:m:d':'{0.year}:{0.mon}:{0.day}'
     5 }
     6 class Date:
     7     def __init__(self,year,mon,day):
     8         self.year=year
     9         self.mon=mon
    10         self.day=day
    11     def __format__(self, format_spec):
    12         print('执行__format__方法')
    13         print('--->',format_spec)
    14         if not format_spec or format_spec not in format_dic:
    15             format_spec='ymd'
    16         fm=format_dic[format_spec]
    17         return fm.format(self)
    18 d1=Date(2016,12,26)
    19 # format(d1) #d1.__format__()
    20 print('没设置格式,采用默认格式==>',format(d1))
    21 print(format(d1,'ymd'))
    22 print(format(d1,'y:m:d'))
    23 print(format(d1,'m-d-y'))
    24 print('已设定格式但格式不存在,采用默认格式==>',format(d1,'m-d:y'))

    输出

    执行__format__方法
    --->
    没设置格式,采用默认格式==> 20161226
    执行__format__方法
    ---> ymd
    20161226
    执行__format__方法
    ---> y:m:d
    2016:12:26
    执行__format__方法
    ---> m-d-y
    12-26-2016
    执行__format__方法
    ---> m-d:y
    已设定格式但格式不存在,采用默认格式==> 20161226

    __slots__

    (慎用)是一个类变量,变量值可以是字符串、列表、元组或者可迭代对象(意味着所有实例只有一个数据属性)

      为何使用__slots__?优势在于省内存(字典会占用大量内存,如果有一个属性很少的类,但是有很多实例,为了节省内存可以使用__slots__取代实例的__dict__,设置了__slots__之后,__dict__就没了)

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

      特点:不允许设置其他数据属性。  

      

     1 class Foo:
     2     __slots__=['name','age']  #{'name':None,'age':None}
     3     # __slots__='name' #{'name':None,'age':None}
     4 
     5 f1=Foo()
     6 # f1.name='egon'
     7 # print(f1.name)
     8 
     9 # f1.age=18  #--->setattr----->f1.__dict__['age']=18
    10 
    11 # print(f1.__dict__)
    12 print(Foo.__slots__)
    13 print(f1.__slots__)
    14 f1.name='egon'
    15 f1.age=17
    16 print(f1.name)
    17 print(f1.age)
    18 # f1.gender='male'
    19 
    20 
    21 f2=Foo()
    22 print(f2.__slots__)
    23 f2.name='alex'
    24 f2.age=18
    25 print(f2.name)
    26 print(f2.age)

    输出

    ['name', 'age']
    ['name', 'age']
    egon
    17
    ['name', 'age']
    alex
    18

    __doc__

    定义于开头用来说明文档信息的一个字符串,且无法被继承。

    写不写都有,不写默认是None。

    __module__和__class__

    查看实例来自哪个模块  对象.__module__

    查看实例是什么类  对象.__class__

    __del__ 析构方法

    此方法一般无需定义,因为python是门高级语言,使用时无需关心内存的分配和释放,此工作交由python解释器执行,所以析构函数的调用是由解释器在进行垃圾回收时自动触发执行的,文件执行完毕之后触发该函数执行。

     1 class Foo:
     2     def __init__(self,name):
     3         self.name=name
     4     def __del__(self):
     5         print('我执行啦')
     6 
     7 f1=Foo('alex')
     8 
     9 # del f1    #删除实例会触发__del__
    10 del f1.name #删除实例的属性不会触发__del__
    11 print('--------------------->')
    12 
    13 #程序运行完毕会自动回收内存,触发__del__

    输出

    --------------------->
    我执行啦

    __call__

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

    __next__和__iter__实现迭代器协议

     1 class Foo:
     2     def __init__(self,n):
     3         self.n=n
     4     def __iter__(self):
     5         return self
     6 
     7     def __next__(self):
     8         if self.n == 13:
     9             raise StopIteration('终止了')
    10         self.n+=1
    11         return self.n
    12 
    13 f1=Foo(10)
    14 
    15 for i in f1:  # obj=iter(f1)------------>f1.__iter__()
    16      print(i)  #obj.__next__()

    输出

    11
    12
    13

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

     1 class Fib:
     2     def __init__(self):
     3         self._a=1
     4         self._b=1
     5 
     6     def __iter__(self):
     7         return self
     8     def __next__(self):
     9         if self._a > 100:
    10             raise StopIteration('终止了')
    11         self._a,self._b=self._b,self._a + self._b
    12         return self._a
    13 
    14 f1=Fib()
    15 print(next(f1))
    16 print(next(f1))
    17 print(next(f1))
    18 print(next(f1))
    19 print(next(f1))
    20 print('==================================')
    21 for i in f1:
    22     print(i)

    输出

    1
    2
    3
    5
    8
    ==================================
    13
    21
    34
    55
    89
    144

    描述符理论

    (开发大型框架时用到)

    本质是一个新式类,至少实现了__get__()/__set__()/__delete__()中的一个,这也被成为描述符协议。

      __get__():调用一个属性时触发

      __set__():为一个属性赋值时触发

      __delete__():采用del删除属性时触发

    描述符有什么用?描述符的作用是用来代理另外一个类的属性的

    描述符分为两种:

      数据描述符:至少实现了__get__()和__set__()

      非数据描述符:没实现__set__()

    注意事项:

      1.描述符本身应该定义成新式类,被代理的类也应该是新式类;

      2.必须把描述符定义成类属性,而不能定义到构造函数中;

      3.要严格遵循该优先级,从高到低:

        类属性---数据描述符---实例属性---非数据描述符---找不到的属性触发__getattr__()

    例:

     1 class Foo:
     2     def __get__(self, instance, owner):
     3         print('===>get方法')
     4     def __set__(self, instance, value):
     5         print('===>set方法',instance,value)
     6         instance.__dict__['x']=value #对b1.__dict__进行修改
     7     def __delete__(self, instance):
     8         print('===>delete方法')
     9 
    10 class Bar:
    11     x=Foo() #描述符定义位置 在何地?   x用描述符来描述
    12     def __init__(self,n):
    13         self.x=n #b1.x=10 触发Foo的set方法
    14 #触发在何时?
    15 b1=Bar(10)  #在执行赋值操作
    16 print(b1.__dict__)
    17 b1.x=1  #在执行赋值操作
    18 print(b1.__dict__)
    19 
    20 b1.y=2  #没有触发set,因为变量y并没用描述符描述
    21 print(b1.__dict__)

    输出

    ===>set方法 <__main__.Bar object at 0x000001CDBB0197B8> 10
    {'x': 10}
    ===>set方法 <__main__.Bar object at 0x000001CDBB0197B8> 1
    {'x': 1}
    {'x': 1, 'y': 2}

    优先级的体现

     1 class Foo:
     2     def __get__(self, instance, owner):
     3         print('===>get方法')
     4     def __set__(self, instance, value):
     5         print('===>set方法',instance,value)
     6         instance.__dict__['x']=value #b1.__dict__
     7     def __delete__(self, instance):
     8         print('===>delete方法')
     9 
    10 class Bar:
    11     x=Foo()
    12 Bar.x=1    #覆盖类属性,改变了Bar的__dict__
    13 print(Bar.__dict__)
    14 print(Bar.x)

    输出

    {'__module__': '__main__', 'x': 1, '__dict__': <attribute '__dict__' of 'Bar' objects>, '__weakref__': <attribute '__weakref__' of 'Bar' objects>, '__doc__': None}
    1

    反序列化的时候要保证类还在内存中。

  • 相关阅读:
    Redis
    Redis
    运维
    Redis
    Redis
    Redis
    Redis
    Redis
    Redis
    Spring
  • 原文地址:https://www.cnblogs.com/chenyuan-1995/p/9705718.html
Copyright © 2011-2022 走看看