zoukankan      html  css  js  c++  java
  • python-聊聊反射

    反射

    对于初学python可能较难理解,但反射是非常有用。

    试想一下,当别的程序传入给你写的这段代码一个变量(var=“math”),这个变量是一个字符串,这个字符串是一个模块或者一个模块下的某个方法,你需要通过变量来导入此模块或者方法,如何导入此模块或方法呢,如果直接执行 import var是会出错的,因为var在你的这段代码中是一个变量, 这时就需要反射, 如何使用反射呢。

    1.聊聊自省

     在计算机编程中,自省是指这种能力:检查某些事物以确定它是什么、它知道什么以及他能做什么。自省向程序员提供了极大的灵活性和控制力。

    几个重要的函数:

    dir函数,传入的参数是对象,返回该对象的所有属性和函数列表:

    >>> dir(str)
    ['__add__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__getslice__', '__gt__', '__hash__', '__init__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_formatter_field_name_split', '_formatter_parser', 'capitalize', 'center', 'count', 'decode', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'index', 'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']

    可以看出,string对象的所有函数,属性都列举出来了。

    getatter方法,传入参数是对象和该对象的函数或者属性的名字,返回对象的函数或者属性实例,如下:

    >>> getattr('str','rfind')
    <built-in method rfind of str object at 0x7fc2e04c5b10>

    callable方法,如果传入的参数是可以调用的函数,则返回true,否则返回false。

    >>> callable(getattr('str','rfind'))
    True
    >>> callable(getattr('str','__doc__'))
    False
    >>> 

    列出对象的所有可以执行的函数:这个地方用到了列表推导式:

    >>> methodLIst = [method for method in dir(str) if callable(getattr(str,method))]
    >>> print methodLIst
    ['__add__', '__class__', '__contains__', '__delattr__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__getslice__', '__gt__', '__hash__', '__init__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_formatter_field_name_split', '_formatter_parser', 'capitalize', 'center', 'count', 'decode', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'index', 'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']

    2.python是如何体现反射的

    globals()

    这个函数返回一个map,这个map的key是全局范围内对象的名字,value是该对象的实例,在不导入任何module下,执行globals()的结果如下:

    >>> globals()
    {'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__doc__': None, '__package__': None}
    >>> 

    在导入sys后,可以发现,globals()返回的map中,多了sys module:

    >>> globals()
    {'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', 'sys': <module 'sys' (built-in)>, '__doc__': None, '__package__': None}

    在导入sgmlib如下:

    >>> import sgmllib
    >>> globals()
    {'sgmllib': <module 'sgmllib' from '/usr/lib64/python2.6/sgmllib.pyc'>, '__builtins__': <module '__builtin__' (built-in)>, '__package__': None, 'sys': <module 'sys' (built-in)>, '__name__': '__main__', '__doc__': None}

    如果导入类后,在map中,可以找到类SGMLParser

    >>> from sgmllib import SGMLParser
    >>> globals()
    {'sgmllib': <module 'sgmllib' from '/usr/lib64/python2.6/sgmllib.pyc'>, 'SGMLParser': <class sgmllib.SGMLParser at 0x7fbd2754c530>, '__builtins__': <module '__builtin__' (built-in)>, '__package__': None, 'sys': <module 'sys' (built-in)>, '__name__': '__main__', '__doc__': None}

    所以,只要将class的名字作为key,即可得到class。如下:

    >>> globals()['SGMLParser']
    <class sgmllib.SGMLParser at 0x7fbd2754c530>
    >>> parser = globals()['SGMLParser']()
    >>> parser
    <sgmllib.SGMLParser instance at 0x7fbd2d64f1b8>

    将模块引入,之后确定模块的相应类的名字,就可以得到了一个类对象,之后就可以实例化了。

    3.反射详解

    python中的反射功能是由以下四个内置函数提供:hasattr、getattr、setattr、delattr,改四个函数分别用于对对象内部执行:检查是否含有某成员、获取成员、设置成员、删除成员。

    #!/usr/bin/env python
    #-*- coding:utf-8 -*-
    __author__ = 'wyf'
    
    class Foo(object):
        def __init__(self):
            self.name = 'chushiyaoyue'
    
        def func(self):
            return 'func'
    
    obj = Foo()#实例化一个对象
    
    # #### 检查是否含有成员 ####
    hasattr(obj, 'name') #True
    hasattr(obj, 'func') #True
    
    # #### 获取成员 ####
    getattr(obj, 'name')
    getattr(obj, 'func')
    #chushiyaoyue
    #<bound method Foo.func of <__main__.Foo object at 0x0000000002C5F4A8>>
    # #### 设置成员 ####
    setattr(obj, 'age', 18)#添加属性
    setattr(obj, 'show', lambda num: num + 1)#添加方法
    # print vars(obj)
    #{'age': 18, 'name': 'chushiyaoyue', 'show': <function <lambda> at 0x0000000002A46128>}#已经添加了一个属性和一个方法
    # # #### 删除成员 ####
    delattr(obj, 'name')
    delattr(obj, 'func')

    __import__('模块名字')

    from 包 import 模块名 as 别名 ====等于=== 别名 = __import__("模块名的字符串")

    针对该模块同一级下另外一个目录,也就是包,而这个包下有另一个包,而我们需要导入的模块还在其下面,这时候,不能应用包.包.模块作为字符串传入__import__来导入了,因为其只会导入第一层包,需要加入一个参数fromlist = True

    a = __import__''#基础的导入
    __import__("a.b.c.file.login",fromlist=True)#多层级的导入
    __import__("a.b.c.file.login")  #是不对的 只导入了a目录 包

    python中一切实物都是对象,类,模块也是对象!反射是通过字符串的形式操作对象相关的成员!

    类是对象:

     1 #!/usr/bin/env python
     2 #-*- coding:utf-8 -*-
     3 __author__ = 'wyf'
     4 
     5 class Foo(object):
     6 
     7     staticField = "test123"
     8 
     9     def __init__(self):
    10         self.name = 'chushiyaoyue'
    11 
    12     def func(self):
    13         return 'func'
    14 
    15     @staticmethod
    16     def bar():
    17         return 'bar'
    18 
    19 print getattr(Foo, 'staticField')
    20 print getattr(Foo, 'func')
    21 print getattr(Foo, 'bar')

    模块是对象:

    1 #!/usr/bin/env python
    2 # -*- coding:utf-8 -*-
    3  
    4 def dev():
    5     return 'dev'
    home.py
     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3   
     4 """
     5 程序目录:
     6     home.py
     7     index.py
     8   
     9 当前文件:
    10     index.py
    11 """
    12   
    13   
    14 import home as obj
    15   
    16 #obj.dev()
    17   
    18 func = getattr(obj, 'dev')
    19 func() 

    实例小练习:根据用户输入的url执行相关的功能

     1 #!/usr/bin/env python
     2 #-*- coding:utf-8 -*-
     3 __author__ = 'wyf'
     4 
     5 def login():
     6     return 'login'
     7 
     8 def logout():
     9     return 'logout'
    10 
    11 def nb():
    12     return '特别牛逼的页面'
    account.py

    最简单粗暴的方法,简单很容易想到,但是如果方法一多,你要写很多代码

     1 #!/usr/bin/env python
     2 #-*- coding:utf-8 -*-
     3 __author__ = 'wyf'
     4 
     5 from lib import account
     6 
     7 url = raw_input('请输入url:')
     8 
     9 if url.endswith('login'):
    10     r = account.login()
    11     print r
    12 
    13 elif url.endswith('logout'):
    14     r = account.logout()
    15     print r
    16 
    17 elif url.endswith('nb'):
    18     r = account.nb()
    19     print r
    20 
    21 else:
    22     print '404'
    简单的方式

    使用反射的方式,一步到位不管你有多少个方法调用,我都支持

     1 #!/usr/bin/env python
     2 #-*- coding:utf-8 -*-
     3 __author__ = 'wyf'
     4 
     5 from lib import account
     6 url = raw_input('请输入url:')
     7 target_module,target_func = url.split('/')
     8 
     9 m = __import__('lib.',target_module,fromlist=True)
    10 if hasattr(m,target_func):#判断这个函数里面是否存在这个方法
    11     target_func = getattr(account,inp)#获取这个方法
    12     r = target_func()#执行这个方法
    13     print r
    14 else:
    15     print '404'
  • 相关阅读:
    SQL总结----存储过程
    SQL SERVER中的二种获得自增长ID的方法
    C#调用存储过程的ADO.Net
    扩展jQuery---选中指定索引的文本
    使用带参数的SQL语句向数据库中插入空值
    js中对小数取整
    Lr原理初识-慧测课堂笔记
    Https 安全传输的原理
    静态性能测试-慧测课堂笔记
    Docker常用命令
  • 原文地址:https://www.cnblogs.com/chushiyaoyue/p/5599297.html
Copyright © 2011-2022 走看看