day7-python类反射

一、概述

一般的高阶语言都有反射的功能特性,python也不例外,网上资料显示,python支持类反射和模块反射,今天就先学习一下类反射的相关知识,模块反射后续再展开把。Python的类反射用于把字符串(对应于属性或方法)反射成内存中的地址对象,以便按需调用,实现某些特性的动态装配,它主要通过hasattr()、getattr()、setattr()、和delattr()来实现,类似于数据库的增删改查操作把。

二、反射函数

以下内容主要思想转自师兄张其高的博客https://www.cnblogs.com/zhangqigao/articles/6947023.html

2.1 hasattr(obj, name_str)

作用:判断一个对象obj中是否有对应的name_str字符串所代表的属性或者方法,返回布尔值。注意这里的对象可以是类,也可以是实例化的对象。

  1 class Dog(object):
  2 
  3     def __init__(self, name):
  4         self.name = name
  5 
  6     def eat(self, food):
  7         print('%s is eating %s' % (self.name, food))
  8 
  9 obj1 = Dog('XiaoHuang')
 10 
 11 print('obj1:\t %s '  % hasattr(obj1, 'name'))  #判断属性
 12 print('class Dog:\t %s' % hasattr(Dog, 'eat')) #判断方法
 13 
 14 input = input(">>>:").strip()   #动态输入字符串,动态判断
 15 print(hasattr(obj1, input))
 16 
 17 输出:
 18 obj1:	 True
 19 class Dog:	 True
 20 >>>:food
 21 False
View Code

2.2 getattr(obj, name_str)

作用:根据字符串name_str获取obj对象中的对应方法的内存地址或者对应属性的值

  1 class Dog(object):
  2 
  3     def __init__(self, name):
  4         self.name = name
  5 
  6     def eat(self, food):
  7         print('%s is eating %s' % (self.name, food))
  8 
  9 obj1 = Dog('XiaoHuang')
 10 obj2 = Dog('Bark')
 11 
 12 print('obj1:\t %s '  % getattr(obj1, 'name'))  #返回属性地址
 13 print('class Dog:\t %s' % getattr(Dog, 'eat')) #返回方法地址
 14 print('obj1:\t %s' % getattr(obj1, 'eat'))     #返回方法地址
 15 print('obj2:\t %s' % getattr(obj2, 'eat'))
 16 
 17 结果输出:
 18 obj1:	 XiaoHuang
 19 class Dog:	 <function Dog.eat at 0x00000000021CEEA0>
 20 obj1:	 <bound method Dog.eat of <__main__.Dog object at 0x00000000021CCCC0>>
 21 obj2:	 <bound method Dog.eat of <__main__.Dog object at 0x00000000021CCCF8>>
View Code

这里有一个小疑问,既然类中的方法都保存在类中,并且只保存一份,这里通过obj1和obj2去获取的类方法的地址显示是不同的,这是为什么呢?原因待脑补后补充。

2.3 setattr(obj, name_str, value)

作用:给obj对象添加一个新属性或者新方法,setattr(x, 'y', v) is equivalent to ``x.y = v''

  1. 给对象新增一个方法
      1 class Dog(object):
      2 
      3     def __init__(self, name):
      4         self.name = name
      5 
      6     def eat(self, food):
      7         print('%s is eating %s' % (self.name, food))
      8 
      9 def bulk(self):						#预期新增的方法
     10     print('%s is yelling...' % self.name)
     11 
     12 obj1 = Dog('XiaoHuang')
     13 
     14 str_input = input(">>>:").strip()
     15 setattr(obj1, str_input, bulk)
     16 func = getattr(obj1, str_input)
     17 func(obj1)
     18 
     19 print('obj1:\t %s '  % getattr(obj1, str_input))
     20 print('class Dog:\t %s' % getattr(Dog, str_input))
     21 
     22 结果输出:
     23 >>>:hehe
     24 XiaoHuang is yelling...
     25 obj1:	 <function bulk at 0x0000000001CF3E18>
     26 Traceback (most recent call last):
     27   File "D:/python/S13/Day6/testclass.py", line 28, in <module>
     28     print('class Dog:\t %s' % getattr(Dog, str_input))
     29 AttributeError: type object 'Dog' has no attribute 'hehe'
     30 
     31 Process finished with exit code 1
    View Code
    注意:
    (1) 这里新增的方法只是对实例化的对象有效,对类无效
    (2) 最后在获取func的内存地址后,也就是bulk的内存地址后,调用时需要传入实例化对象方法,因为定义的新增bulk方法有参数self,而这种动态新增的方法,参数无论是否为self,都需要手动传入

  2. 给对象新增一个属性
      1 # !/usr/bin/env python
      2 # -*- coding:utf-8 -*-
      3 
      4 class Dog(object):
      5 
      6     def __init__(self, name):
      7         self.name = name
      8 
      9     def eat(self, food):
     10         print('%s is eating %s' % (self.name, food))
     11 
     12 
     13 obj1 = Dog('XiaoHuang')
     14 
     15 str_input = input(">>>:").strip()
     16 setattr(obj1, str_input, 3)
     17 print(getattr(obj1, str_input))
     18 print('obj1:\t %s '  % getattr(obj1, str_input))
     19 print('----')
     20 print(obj1.__dict__)
     21 
     22 输出:
     23 >>>:age
     24 3
     25 obj1:	 3
     26 ----
     27 {'name': 'XiaoHuang', 'age': 3}
    View Code

        上述示例程序显示,对象新增的属性可以通过__dict__来查看到,新增成功。

2.4 delattr(obj, name_str)

作用:删除obj对象中的属性或者方法,delattr(x, 'y') is equivalent to ``del x.y''

  1 class Dog(object):
  2 
  3     def __init__(self, name):
  4         self.name = name
  5 
  6     def eat(self, food):
  7         print('%s is eating %s' % (self.name, food))
  8 
  9 
 10 obj1 = Dog('XiaoHuang')
 11 
 12 str_input = input(">>>:").strip()
 13 delattr(obj1, str_input)
 14 print(Dog.__dict__)
 15 print('----')
 16 print(obj1.__dict__)
 17 print(getattr(obj1, str_input))
 18 
 19 输出:
 20 #删除属性
 21 >>>:name
 22 Traceback (most recent call last):
 23   File "D:/python/S13/Day6/testclass.py", line 24, in <module>
 24     print(getattr(obj1, str_input))
 25 AttributeError: 'Dog' object has no attribute 'name'  #访问被删除的name属性报错
 26 {'__module__': '__main__', '__init__': <function Dog.__init__ at 0x000000000219EEA0>, 'eat': <function Dog.eat at 0x000000000219EF28>, '__dict__': <attribute '__dict__' of 'Dog' objects>, '__weakref__': <attribute '__weakref__' of 'Dog' objects>, '__doc__': None}
 27 ----
 28 {} #实例的唯一属性name不见了
 29 
 30 #删除方法
 31 >>>:eat
 32 Traceback (most recent call last):
 33   File "D:/python/S13/Day6/testclass.py", line 20, in <module>
 34     delattr(obj1, str_input)
 35 AttributeError: eat   #方法删除后立马报错了
 36 
View Code

三、综合运用

上面主要讲述的属性或方法的动态增、删、改、查的基本用法,实际上删除和增加用的很少,这里结合查、删、改来简述一下综合运用。

  1 # !/usr/bin/env python
  2 # -*- coding:utf-8 -*-
  3 
  4 class Dog(object):
  5 
  6     def __init__(self, name):
  7         self.name = name
  8 
  9     def eat(self, food):
 10         print('%s is eating %s' % (self.name, food))
 11 
 12 
 13 obj1 = Dog('XiaoHuang')
 14 
 15 str_input = input(">>>:").strip()
 16 if hasattr(obj1, str_input):
 17     print('Before change')
 18     print('obj1\t%s:%s' % (str_input, getattr(obj1, str_input)))
 19     print('--------')
 20     setattr(obj1, str_input, 'Jinba')
 21     print('After change')
 22     print('obj1\t%s:%s' %(str_input, getattr(obj1, str_input)))
 23 else:
 24     setattr(obj1, str_input, None)  #对于不存在的属性设置为None,感觉意义不大?
 25     print(getattr(obj1, str_input))
 26 
 27 输出:
 28 >>>:name
 29 Before change
 30 obj1	name:XiaoHuang
 31 --------
 32 After change
 33 obj1	name:Jinba
 34 
 35 
View Code

posted @ 2018-08-17 06:22  里纳斯-派森  阅读(874)  评论(0编辑  收藏  举报