zoukankan      html  css  js  c++  java
  • 面向对象2

    面向对象之反射

    参考 :https://www.cnblogs.com/yuliangkaiyue/p/9516427.html

    面向对象之内置方法

    __setattr__ ,__getattr__,__delattr__

    1. class Foo:
    2. x = 1
    3. def __init__(self, y):
    4. self.y = y
    5. def __setattr__(self, key, value):
    6. print('----->setattr')
    7. # self.key =value #等同于赋值,不断触发setattr,造成递归循环
    8. self.__dict__[key] = value
    9. def __getattr__(self, item):
    10. print('------->getattr')
    11. print('%s不存在' % item)
    12. def __delattr__(self, item):
    13. print('-------delete')
    14. # del self.item # 同上理
    15. self.__dict__.pop(item)
    16. f = Foo(6)
    17. print(f.__dict__)
    18. f.z
    19. f.z =2
    20. print(f.__dict__)
    21. f.__dict__['a'] = 10 # 直接调用字典赋值并不会触发setattr方法
    22. del f.a
    23. print(f.__dict__)
    24. 执行结果:
    25. ----->setattr 因为初始化触发了__setattr__方法执行
    26. {'y': 6}
    27. ------->getattr 属性Z不存在,触发了getattr方法,所以找不到属性才触发
    28. z不存在
    29. ----->setattr
    30. {'y': 6, 'z': 2}
    31. -------delete
    32. {'y': 6, 'z': 2}

    item系列

      __setitem__,__getitem__,__delitem__ 在功能上和上边的有些类似,但是又稍有不同。item系列的特点是把类操作弄得像字典一样。


    1. class Foo:
    2. def __init__(self, name):
    3. self.name = name
    4. def __setitem__(self, key, value):
    5. print('from setitem')
    6. self.__dict__[key]=value
    7. def __getitem__(self, item):
    8. print('from getitem')
    9. print(self.__dict__.get(item))
    10. def __delitem__(self, key):
    11. print('from delitem del [key]')
    12. self.__dict__.pop(key)
    13. def __delattr__(self, item):
    14. print('from delattr del .属性')
    15. self.__dict__.pop(item)
    16. f1=Foo('李四')
    17. print(f1.__dict__)
    18. f1['age']=18
    19. f1['sex']=''
    20. print(f1.__dict__)
    21. del f1.age
    22. del f1['sex']
    23. f1['home']='滨州'
    24. print(f1.__dict__)
    25. # {'name': '李四'}
    26. # from setitem
    27. # from setitem
    28. # {'name': '李四', 'age': 18, 'sex': ''}
    29. # from delattr
    30. # from delitem
    31. # from setitem
    32. # {'name': '李四', 'home': '滨州'}

    为类设置输出 __str__,__repr__,__format__

      改变对象的字符串显示__str__,__repr__

      自定制格式化字符串__format__

    1. format_dict={
    2. 'nat':'{obj.name}-{obj.addr}-{obj.type}',#学校名-学校地址-学校类型
    3. 'tna':'{obj.type}:{obj.name}:{obj.addr}',#学校类型:学校名:学校地址
    4. 'tan':'{obj.type}/{obj.addr}/{obj.name}',#学校类型/学校地址/学校名
    5. }
    6. class School:
    7. def __init__(self,name,addr,type):
    8. self.name=name
    9. self.addr=addr
    10. self.type=type
    11. def __repr__(self):
    12. return 'School(%s,%s)' %(self.name,self.addr)
    13. def __str__(self):
    14. return '(%s,%s)' %(self.name,self.addr)
    15. def __format__(self, format_spec):
    16. # if format_spec
    17. if not format_spec or format_spec not in format_dict:
    18. format_spec='nat'
    19. fmt=format_dict[format_spec]
    20. return fmt.format(obj=self)
    21. s1=School('oldboy1','北京','私立')
    22. print('from repr: ',repr(s1))
    23. print('from str: ',str(s1))
    24. print(s1)
    25. # from repr: School(oldboy1,北京)
    26. # from str: (oldboy1,北京)
    27. # (oldboy1,北京)
    28. '''
    29. str函数或者print函数--->obj.__str__()
    30. repr或者交互式解释器--->obj.__repr__()
    31. 如果__str__没有被定义,那么就会使用__repr__来代替输出
    32. 注意:这俩方法的返回值必须是字符串,否则抛出异常
    33. '''
    34. print(format(s1,'nat'))
    35. print(format(s1,'tna'))
    36. print(format(s1,'tan'))
    37. print(format(s1,'a'))
    38. # oldboy1-北京-私立
    39. # 私立:oldboy1:北京
    40. # 私立/北京/oldboy1
    41. # oldboy1-北京-私立

     

      当然也可以在__str__()中调用format方法,以显示想要的效果 

     析构方法  __del__

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

      注:如果产生的对象仅仅只是python程序级别的(用户级),那么无需定义__del__,如果产生的对象的同时还会向操作系统发起系统调用,即一个对象有用户级与内核级两种资源,比如(打开一个文件,创建一个数据库链接),则必须在清除对象的同时回收系统资源,这就用到了__del__。简而言之,操作系统资源要通过代码手动调用管理的,用完就关闭它,用del方式可以防止忘记关闭操作系统资源而出错,也使代码简洁。

    1. class Foo:
    2. def __del__(self):
    3. print('回收')
    4. f1=Foo()
    5. del f1
    6. print('------->')
    7. #输出结果
    8. # 回收
    9. # ------->

     

    描述符(__get__, __set__, __delete__)

    描述符

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

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

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

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

    作用

    描述符的作用是用来代理另外一个类的属性的(必须把描述符定义成这个类的类属性,不能定义到构造函数中)

    1. class Foo:
    2. def __get__(self, instance, owner):
    3. print('触发get')
    4. def __set__(self, instance, value):
    5. print('触发set')
    6. def __delete__(self, instance):
    7. print('触发delete')
    8. f1=Foo()
    9. f1.name='egon'
    10. f1.name
    11. del f1.name

     

      但是,这样子并没有触发三个方法的执行

      那如何才会触发执行呢?

    1. #描述符Str
    2. class Str:
    3. def __get__(self, instance, owner):
    4. print('Str调用')
    5. def __set__(self, instance, value):
    6. print('Str设置...')
    7. def __delete__(self, instance):
    8. print('Str删除...')
    9. #描述符Int
    10. class Int:
    11. def __get__(self, instance, owner):
    12. print('Int调用')
    13. def __set__(self, instance, value):
    14. print('Int设置...')
    15. def __delete__(self, instance):
    16. print('Int删除...')
    17. class People:
    18. name=Str()
    19. age=Int()
    20. def __init__(self,name,age): #nameStr类代理,ageInt类代理,
    21. self.name=name
    22. self.age=age
    23. #何地?:定义成另外一个类的类属性
    24. #何时?:且看下列演示
    25. p1=People('alex',18)
    26. #描述符Str的使用
    27. p1.name
    28. p1.name='egon'
    29. del p1.name
    30. #描述符Int的使用
    31. p1.age
    32. p1.age=18
    33. del p1.age
    34. #我们来瞅瞅到底发生了什么
    35. print(p1.__dict__)
    36. print(People.__dict__)
    37. #补充
    38. print(type(p1) == People) #type(obj)其实是查看obj是由哪个类实例化来的
    39. print(type(p1).__dict__ == People.__dict__)
    40. 执行结果:
    41. Str设置...
    42. Int设置...
    43. Str调用
    44. Str设置...
    45. Str删除...
    46. Int调用
    47. Int设置...
    48. Int删除...
    49. {}
    50. {'__module__': '__main__', 'name': <__main__.Str object at 0x0000000A51974438>, 'age': <__main__.Int object at 0x0000000A51ACFC18>, '__init__': <function People.__init__ at 0x0000000A51AD3BF8>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None}
    51. True
    52. True

     

    注意事项

      一 描述符本身应该定义成新式类,被代理的类也应该是新式类
      二 必须把描述符定义成这个类的类属性,不能为定义到构造函数中
      三 要严格遵循该优先级,优先级由高到底分别是
               1.类属性
               2.数据描述符
               3.实例属性
               4.非数据描述符
               5.找不到的属性触发__getattr__()

      

  • 相关阅读:
    右值和move 与 forward
    C++11的chrono库,实现毫秒微秒级定时
    HDOJ 1176 免费馅饼(完全背包)
    HDU 1069 Monkey and Banana
    杭电 1003 Max Sum (动态规划)
    UVA ~ 514 ~ Rails (栈)
    UVA 679
    UVA11988 Broken Keyboard (a.k.a. Beiju Text)【数组模拟链表】
    Codeforces 845 C Two TVs
    codeforces 845A Chess Tourney
  • 原文地址:https://www.cnblogs.com/yuliangkaiyue/p/9570033.html
Copyright © 2011-2022 走看看