Python的反射:getattr

2023年 1月 4日 40.9k 0

1. 应用场景

  • 通过配置文件,控制程序运行时的流程。配置文件中常保存的是,字符串,而不是对象
  • 调试程序时,查看对象的全部属性值
  • 动态模块的导入
  • 对于第一种场景,广泛被采用的是反射。在Java的很多框架中都使用了反射机制,Python实现的Web框架Django中,也有应用。比如url的路由。第二种场景,手动添加输出某个对象object类的属性值,非常的麻烦,而且不全。这时,可以使用dir(object)列出全部属性,然后使用反射来访问。第三中场景,通过反射也能实现。

    2. Python的反射

    通过反射,可以将字符串和对象的属性关联起来。通过dir(object),可以查看对象obejct的属性列表。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    
    # -*- coding: utf-8 -*-
    class Person:
        '''
        Python反射的一个举例
        '''
        count = 0
    
        def __init__(self, name="none", salary="0"):
            self.name = name
            self.salary = salary
            Person.count += 1
    
        def getName(self):
            print "i am in getName() function"
            return self.name
    
    
    >>> p = Person(name="csw")
    >>> dir(p)
    ['__doc__', '__init__', '__module__', 'count', 'getName', 'name', 'salary']
    >>> hasattr(p, 'count')
    True
    >>> getattr(p, 'count')
    1
    >>> getattr(p, 'getName')()
    i am in getName() function
    csw
    >>> setattr(p, 'ModifiedName', 'name')
    None
    >>> delattr(p, 'name')
    None
    >>> dir(p)
    ['ModifiedName', '__doc__', '__init__', '__module__', 'count', 'getName', 'salary']
    >>> getattr(p, 'getName')()
    AttributeError: Person instance has no attribute 'name'
    

    2.1 getattr

    方式:getattr(object,‘name‘,‘default’)说明:如果存在name的属性方法,则返回name的属性方法,否则返回default的属性方法。

    2.2 hasattr

    方式:hasattr(object, ’name‘)说明:判断对象object是否包含名为name的属性方法,存在则返回True,否则返回False。hasattr是通过调用getattr(ojbect, ’name‘)是否抛出异常来实现)。

    2.3 setattr

    方式:setattr(object,‘name’,’default‘)说明:设置对象object的name属性值为default,如果没有name属性,那么创建一个新的属性。

    2.4 delattr

    方式:delattr(object,’name’)说明:删除对象object的name属性值。

    3. Python的反射实现

    globals( )函数返回字典{ key:value },key是对象的名称,value是对象的实例。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    
    >>> globals()
    {'__builtins__': <module '__builtin__' (built-in)>,
     '__file__': 'E:/code/lab/python-reflection/exapmle.py',
     '__package__': None, 'Person': <class __main__.Person at 0x00215FB8>, 
    '__name__': '__main__', '__doc__': None}
    
    >>> import test
    {'__builtins__': <module '__builtin__' (built-in)>,
     '__file__': 'E:/code/lab/python-reflection/exapmle.py', 
    '__package__': None, 'Person': <class __main__.Person at 0x02045FB8>,
     'test': <module 'test' from 'D:\Python2711\lib\test\__init__.pyc'>, 
    '__name__': '__main__', '__doc__': None}
    
    >>> globals()['test']
    <module 'test' from 'D:\Python2711\lib\test\__init__.pyc'>
    

    在执行 import test之后,可以看到新增了 test 的 key。可以利用这一点实现类似 Java 中,Class.forName()的功能。但是这种方法,使用之前必须先 import,否则会抛出异常。Python中提供了 __import__(“functionName”)函数,传入参数“functionName”,就可以导入functionName模块。然后结合getattr函数进行相关的调用。

    4. 为什么不直接用 exec和eval

    熟悉python的同学应该知道,exec和eval语句,也可以用来执行储存在字符串或文件中的Python语句。比如:

    1
    2
    3
    4
    
    >>> eval('2*3')
    6
    >>> eval("2+3")
    5
    

    那么为什么还要反射呢?使用exec和eval能够实现相同的功能,但是反射是一种编程方法、是设计模式的体现。反射凝聚了高内聚、低耦合的软件设计思想,不能简单的使用执行字符串的函数替代。

    相关文章

    KubeSphere 部署向量数据库 Milvus 实战指南
    探索 Kubernetes 持久化存储之 Longhorn 初窥门径
    征服 Docker 镜像访问限制!KubeSphere v3.4.1 成功部署全攻略
    那些年在 Terraform 上吃到的糖和踩过的坑
    无需 Kubernetes 测试 Kubernetes 网络实现
    Kubernetes v1.31 中的移除和主要变更

    发布评论